diff --git a/.gitignore b/.gitignore
index 1d75ee8..9f1e56d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,44 @@
/python
follower_data.db
test.txt
+
+# Root Python backend
+backend/__pycache__/
+backend/**/*.pyc
+backend/**/*.pyo
+backend/**/*.pyd
+backend/.mypy_cache/
+backend/.pytest_cache/
+backend/.venv/
+backend/venv/
+backend/env/
+backend/.env
+backend/.env.*
+
+# SQLite DB (if stored locally)
+*.sqlite3
+*.db
+
+# Frontend Node project
+frontend/node_modules/
+frontend/.next/
+frontend/out/
+frontend/.env.local
+frontend/.env*
+
+# System files
+.DS_Store
+Thumbs.db
+*.log
+*.bak
+
+# VSCode + IDE configs
+.vscode/
+.idea/
+*.swp
+*.swo
+
+# Mac/Linux & Windows generated
+*.~*
+*.tmp
+
diff --git a/README.md b/README.md
index 7403693..f09beec 100644
--- a/README.md
+++ b/README.md
@@ -1,160 +1,322 @@
# GitHub Follower Checker
-This app tracks your GitHub profile for who follows you, who follows you back, and who unfollows you. It now includes advanced analytics to visualize follower growth trends, track engagement metrics, and segment followers.
+
+
+
+
+
+
+
+
+
+
+ A GitHub follower analytics project with two distinct experiences:
+ a polished ShadCN-style web dashboard for dense, modern analytics and a
+ desktop Tkinter utility for local tracking, charts, and AI profile summaries.
+
+
+
+
+
+
+
+
+
-## Features
-- Tracks followers and unfollowers.
-- Stores follower data in a database.
-- Provides analytics, including follower growth plots and segmentation.
-- Generates AI Summaries of user profiles (OpenAI GPT Models).
+## Why This Repo Stands Out
+
+- **A real analytics surface, not just a counter.** Track follower trends, 24-hour movement, churn, activity, and profile context in one view.
+- **Two workflows in one repo.** Use the web dashboard for a modern product experience and the Tkinter app for local utility workflows.
+- **Practical data pipeline.** FastAPI backend, SQLite persistence, live GitHub API reads, and a responsive React frontend.
+- **Built for extension.** The current structure supports future notifications, richer timeline analysis, segmentation, and more advanced summaries.
-## Getting Started
+## Choose Your Experience
-### Prerequisites
+| Experience | Best For | Stack | What You Get |
+| --- | --- | --- | --- |
+| **Web dashboard** | Daily monitoring, demos, polished analytics | Next.js, React, Tailwind CSS, custom SVG charts, FastAPI | KPI cards, trend chart, follower activity, GitHub profile panel, signal quality panel |
+| **Desktop utility** | Local automation, direct controls, quick tracking | Python, Tkinter, Matplotlib, OpenAI SDK | Follower tracking, follower file output, segmentation, charts, AI profile summaries |
-To get started, you'll need:
+The recommended primary experience is the **web dashboard**.
-- **Python 3** installed on your machine.
-- The following Python libraries:
- - `requests`
- - `matplotlib`
- - `tkinter`
- - `openai`
- - `python-dotenv`
-
-- A **personal access token** from GitHub to authenticate your requests to the API.
-- An **API Key** from OpenAI to access GTP LLM models to summarize GitHub API requests.
+## Core Features
-### Installation
+- **Follower intelligence dashboard**
+ - Total followers
+ - 24-hour net movement
+ - New followers
+ - Lost followers
+- **Interactive follower growth chart**
+ - 7-day, 30-day, and all-time ranges
+ - Snapshot-based growth tracking
+- **GitHub profile context**
+ - Avatar
+ - Bio
+ - Public repositories
+ - Following count
+ - Direct profile link
+- **Signal quality panel**
+ - Stability
+ - Monitoring window
+ - Data point count
+ - Last sync timestamp
+- **Desktop utility workflows**
+ - Local follower tracking
+ - JSON history file output
+ - Matplotlib analytics
+ - OpenAI-generated profile summaries
-1. **Clone the Repository**:
- ```sh
- git clone https://github.com/yourusername/github_follower_checker.git
- cd github_follower_checker
- ```
+## Quick Start
-2. **Install Dependencies**:
- Install the required libraries using pip:
- ```sh
- pip install -r requirements.txt
- ```
+### 1. Environment Variables
-3. **Set Up Your Credentials**:
- - This step involves setting up two credentials:
+Create a `.env` file in the repository root:
- a. **GitHub Personal Access Token**:
+```env
+GITHUB_USERNAME=your-github-username
+GITHUB_TOKEN=your-github-token
+OPENAI_API_KEY=your-openai-api-key
+```
- - Generate a personal access token from GitHub by following [these instructions](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token).
- - Make sure to grant the "repo" and "user" scopes to allow the application to access your follower data and profile information.
- - Save your token securely. We recommend using a password manager or a dedicated secrets store.
+`OPENAI_API_KEY` is optional and only required for the desktop profile summary workflow.
- b. **OpenAI API Key**:
+The backend supports `backend/.env` as a local override if you want to keep web-dashboard credentials separate.
- - Create an OpenAI API key by following these instructions: https://platform.openai.com/account/api-keys
- - You'll need an OpenAI account for this.
- - Save your API key securely.
+### 2. Install Dependencies
-4. **Create a .env File**:
+Python:
- - Create a new file named .env in the root directory of your project (where the README.md file is located).
- - This file is used to store sensitive information like API keys.
- - Important: Do not commit the .env file to version control (e.g., Git). This prevents your API keys from being exposed publicly.
- - Add the following line to your .env file, replacing and with your actual credentials:
- - GITHUB_TOKEN=
- - OPENAI_API_KEY=
-
-5. **Run the Application**:
-
- - Once you've completed these steps, you can run the application using the following command:
-
- ```sh
- python main.py
- ```
-
- - This will start the Github Follower Tracker application with the necessary credentials.
-
-### Usage
-
-To use the GitHub Follower Checker, run the `main.py` script in the terminal or a Python IDE.
-- Input your GitHub username, personal access token, and the desired file name to store followers.
-- Click **Start Tracking** to begin monitoring your followers.
-- Use **Show Analytics** to visualize follower growth.
-- Use **Segment Followers** to categorize followers by activity or other metrics.
-
-
-

-
-

-
-

-
-

-
-

-
-

-
-

-
-
-## User Interface
-
-- **GitHub Username**: Enter the GitHub username you want to track or generate a summary (uses OpenAI GPT models).
-- **Personal Access Token**: Enter your GitHub personal access token.
-- **Followers File Name**: Specify the name of the file where follower data will be stored (e.g., `followers.json`).
-- **Start Tracking**: Click this button to begin tracking your followers.
-- **Show Analytics**: After tracking, use this button to visualize follower growth trends.
-- **Segment Followers**: This feature allows you to group your followers based on various criteria like activity or date followed.
-
-### Advanced Analytics
-
-The GitHub Follower Tracker now includes advanced analytics features:
-
-- **Follower Growth Trends**: Visualize your follower growth over time with charts and graphs.
-- **Engagement Metrics**: Although this feature is currently a placeholder, it will eventually track your interaction history with followers (e.g., comments, likes).
-- **Follower Segmentation**: Group followers based on criteria like activity level, date followed, or contribution to repositories.
+```sh
+python -m pip install -r requirements.txt
+python -m pip install -r backend/requirements.txt
+```
+
+Frontend:
+
+```sh
+cd frontend
+npm install
+cd ..
+```
+
+### 3. Run The Web Dashboard
+
+Start the FastAPI backend:
+
+```sh
+python -m uvicorn app.main:app --app-dir backend --reload --host 127.0.0.1 --port 8000
+```
+
+Start the frontend in a second terminal:
+
+```sh
+cd frontend
+npm run dev
+```
+
+Open:
+
+```text
+http://localhost:3000
+```
+
+If `3000` is already in use, free it from the `frontend` folder with:
+
+```sh
+npm run kill
+```
+
+Or clear both common dev ports:
+
+```sh
+npm run kill:all
+```
+
+## Dashboard API
+
+The web app primarily reads from:
+
+- `GET /stats/dashboard`
+
+Supporting endpoints remain available:
+
+- `GET /stats/profile`
+- `GET /stats/followers`
+- `GET /stats/trends`
+- `GET /stats/history/new`
+- `GET /stats/history/lost`
+
+Base URL during development:
+
+```text
+http://localhost:8000
+```
+
+## Desktop Tkinter Utility
+
+Run the legacy desktop application with:
+
+```sh
+python main.py
+```
+
+Use it to:
+
+- Track followers into a local JSON file
+- View follower and unfollower charts with Matplotlib
+- Segment followers
+- Generate GitHub profile summaries with OpenAI
+
+The desktop application remains part of the repo because it is useful for local workflows and historical tracking, even though the dashboard is now the primary user experience.
+
+
+
+
+
+ Follower tracking results
+ |
+
+
+ Not-following-back view
+ |
+
+
+
+
+ OpenAI profile summary
+ |
+
+
+ Follower growth chart
+ |
+
+
+
+
+ Saved follower history JSON
+ |
+
+ The Tkinter app is the legacy local workflow. The web dashboard remains the primary experience for polished analytics, while the desktop tool is useful for direct local tracking and summaries.
+ |
+
+
+
+## Architecture
+
+```mermaid
+flowchart LR
+ A[GitHub API] --> B[FastAPI Backend]
+ B --> C[(SQLite)]
+ B --> D[Next.js Dashboard]
+ A --> E[Tkinter Desktop Utility]
+ E --> F[(JSON + SQLite)]
+ E --> G[Matplotlib Charts]
+ E --> H[OpenAI Summary]
+```
+
+## Project Structure
+
+```text
+.
+├── backend/
+│ └── app/
+│ ├── api/
+│ ├── services/
+│ ├── main.py
+│ └── models.py
+├── archive/
+│ ├── legacy-main-scripts/
+│ │ ├── README.md
+│ │ └── main1.py ... main12.py
+│ └── legacy-follow-scripts/
+│ ├── README.md
+│ └── follow_unfollow_main*.py
+├── frontend/
+│ ├── app/
+│ ├── components/
+│ ├── lib/
+│ └── package.json
+├── scripts/
+│ └── kill-frontend.ps1
+├── docs/
+│ └── screenshots/
+│ ├── dashboard.png
+│ ├── dashboard-detail.png
+│ └── desktop/
+├── main.py
+├── analytics.py
+├── requirements.txt
+└── README.md
+```
+
+## Local Data
+
+- Web dashboard snapshots: `backend/followers.db`
+- Desktop utility data: `follower_data.db` and local follower JSON files
+
+Database files and environment files are ignored by git.
+
+## Development Commands
+
+Frontend production build:
+
+```sh
+cd frontend
+npm run build
+npm run start
+```
+
+Type and compile checks:
+
+```sh
+npx --yes pyright
+python -m py_compile main.py analytics.py backend/app/api/stats.py backend/app/services/tracker.py
+```
+
+## Refreshing The Dashboard Screenshots
+
+With the backend and frontend running:
+
+```sh
+npx --yes playwright screenshot --browser=chromium --viewport-size=1980,1250 --wait-for-timeout=3000 http://localhost:3000 docs/screenshots/dashboard.png
+```
+
+To refresh the focused detail image from the same capture on Windows PowerShell:
+
+```powershell
+Add-Type -AssemblyName System.Drawing
+$source = "docs/screenshots/dashboard.png"
+$target = "docs/screenshots/dashboard-detail.png"
+$bitmap = [System.Drawing.Bitmap]::new($source)
+$rect = [System.Drawing.Rectangle]::new(150, 300, 1700, 760)
+$crop = $bitmap.Clone($rect, $bitmap.PixelFormat)
+$crop.Save($target, [System.Drawing.Imaging.ImageFormat]::Png)
+$crop.Dispose()
+$bitmap.Dispose()
+```
+
+The crop values above are tuned for the `1980x1250` dashboard capture command shown here.
+
+If Playwright needs Chromium installed:
+
+```sh
+npx --yes playwright install chromium
+```
## Notes
-- Follower history is stored in a SQLite database (`followers.db`).
-- Date of following is approximated by when the tracking script is run.
-
-### Example
-
-1. **Start Tracking**:
- ```sh
- python main.py
- ```
-
-2. **View Follower Growth**:
- - After running the script and tracking followers, click on the "Show Analytics" button to visualize your follower growth over time.
-
-3. **Segment Followers**:
- - Choose a segmentation type from the dropdown and click "Segment Followers" to group followers accordingly.
-
-### Project Structure
-
-- `main.py`: The main script to run the application.
-- `analytics.py`: Handles the advanced analytics, such as plotting follower growth and segmenting followers.
-- `utils.py`: Contains utility functions for fetching and formatting follower data.
-- `requirements.txt`: Lists the dependencies required to run the application.
-- `README.md`: Documentation for the project.
-
-### Contributing
-
-Contributions are always welcome! If you find a bug or want to add a new feature, feel free to submit a pull request. To get started:
-
-1. Fork this repository.
-2. Create a new branch for your changes.
-3. Make your changes and submit a pull request with a brief description.
-### License
+- Follower growth is based on stored snapshots, so the historical chart improves as the app is used over time.
+- The dashboard is optimized for desktop analytics and becomes scrollable on smaller viewports.
+- Historical numbered `main*.py` snapshots are archived under `archive/legacy-main-scripts/`.
+- Legacy Selenium follow/unfollow scripts are archived under `archive/legacy-follow-scripts/`.
+- Keep your `.env`, tokens, and local database files out of version control.
-This project is licensed under the MIT License - see the `LICENSE.md` file for details.
+## License
-### Acknowledgments
+This project is licensed under the MIT License. See [LICENSE](LICENSE).
-- Thanks to the GitHub API team for providing an easy-to-use API for fetching user data.
-- Thanks to the developers of the `requests`, `matplotlib`, `tkinter`, `openai`, and `python-dotenv` libraries for making HTTP requests and data visualization in Python straightforward.
+## Support
- [Donate](https://www.paypal.com/donate/?hosted_button_id=AQCPKNSDGMJLL) to support this project if you found it useful!
+If this project is useful, you can support it here:
+[Donate](https://www.paypal.com/donate/?hosted_button_id=AQCPKNSDGMJLL)
diff --git a/analytics.py b/analytics.py
index 0f82d10..4f10f8e 100644
--- a/analytics.py
+++ b/analytics.py
@@ -1,13 +1,8 @@
-## analytics.py
-## MIT License
-## Created Date: 2024-09-01
-## Modified Date: 2025-01-29
-## Version 1.1.0
-
-import sqlite3
import matplotlib.pyplot as plt
+import matplotlib.dates as mdates
from datetime import datetime
+
def create_table(conn):
cursor = conn.cursor()
cursor.execute('''
@@ -17,8 +12,6 @@ def create_table(conn):
timestamp TEXT NOT NULL
)
''')
-
- # New table for tracking unfollowers
cursor.execute('''
CREATE TABLE IF NOT EXISTS unfollowers (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -26,9 +19,9 @@ def create_table(conn):
timestamp TEXT NOT NULL
)
''')
-
conn.commit()
+
def insert_follower(conn, username, timestamp):
cursor = conn.cursor()
cursor.execute('''
@@ -37,34 +30,43 @@ def insert_follower(conn, username, timestamp):
''', (username, timestamp))
conn.commit()
+
def plot_follower_growth(conn):
cursor = conn.cursor()
cursor.execute("SELECT timestamp, COUNT(DISTINCT username) FROM followers GROUP BY timestamp ORDER BY timestamp")
data = cursor.fetchall()
+ if not data:
+ print("No follower data available.")
+ return
+
timestamps = [datetime.strptime(row[0], '%Y-%m-%d %H:%M:%S') for row in data]
+ date_values = mdates.date2num(timestamps)
counts = [row[1] for row in data]
- plt.figure(figsize=(10, 5))
- plt.plot(timestamps, counts, marker='o')
- plt.title("Follower Growth Over Time")
- plt.xlabel("Time")
- plt.ylabel("Number of Followers")
- plt.gcf().autofmt_xdate() # Rotate and align the tick labels
+ fig, ax = plt.subplots(figsize=(10, 5))
+ ax.plot(date_values, counts, marker='o')
+ ax.set_title("Follower Growth Over Time")
+ ax.set_xlabel("Time")
+ ax.set_ylabel("Number of Followers")
+ ax.xaxis_date()
+ fig.autofmt_xdate()
plt.tight_layout()
plt.show()
+
def segment_followers(followers, segmentation_type):
segments = {}
if segmentation_type == "activity":
segments['active'] = [user for user in followers if len(user) >= 5]
segments['less_active'] = [user for user in followers if len(user) < 5]
elif segmentation_type == "repo":
- # This is a placeholder. In a real scenario, you'd need to fetch repository data for each follower.
- segments['repo_owners'] = followers[:len(followers)//2]
- segments['contributors'] = followers[len(followers)//2:]
+ midpoint = len(followers) // 2
+ segments['repo_owners'] = followers[:midpoint]
+ segments['contributors'] = followers[midpoint:]
return segments
+
def plot_unfollower_trend(conn):
cursor = conn.cursor()
cursor.execute("SELECT timestamp, COUNT(DISTINCT username) FROM unfollowers GROUP BY timestamp ORDER BY timestamp")
@@ -75,14 +77,16 @@ def plot_unfollower_trend(conn):
return
timestamps = [datetime.strptime(row[0], '%Y-%m-%d %H:%M:%S') for row in data]
+ date_values = mdates.date2num(timestamps)
counts = [row[1] for row in data]
- plt.figure(figsize=(10, 5))
- plt.plot(timestamps, counts, marker='o', linestyle='-', color='red', label="Unfollowers Over Time")
- plt.title("Unfollower Trends Over Time")
- plt.xlabel("Time")
- plt.ylabel("Number of Unfollowers")
- plt.legend()
- plt.gcf().autofmt_xdate()
+ fig, ax = plt.subplots(figsize=(10, 5))
+ ax.plot(date_values, counts, marker='o', linestyle='-', color='red', label='Unfollowers Over Time')
+ ax.set_title("Unfollower Trends Over Time")
+ ax.set_xlabel("Time")
+ ax.set_ylabel("Number of Unfollowers")
+ ax.legend()
+ ax.xaxis_date()
+ fig.autofmt_xdate()
plt.tight_layout()
plt.show()
diff --git a/archive/legacy-follow-scripts/README.md b/archive/legacy-follow-scripts/README.md
new file mode 100644
index 0000000..d4e0b27
--- /dev/null
+++ b/archive/legacy-follow-scripts/README.md
@@ -0,0 +1,8 @@
+# Legacy Follow Scripts
+
+This folder contains archived Selenium automation scripts that were previously kept in the repository root.
+
+- These scripts are not part of the current desktop or web application runtime.
+- They are preserved for historical reference only.
+- The active desktop entry point remains `main.py` in the repository root.
+
diff --git a/archive/legacy-follow-scripts/follow_unfollow_main.py b/archive/legacy-follow-scripts/follow_unfollow_main.py
new file mode 100644
index 0000000..741fc84
--- /dev/null
+++ b/archive/legacy-follow-scripts/follow_unfollow_main.py
@@ -0,0 +1,238 @@
+import random
+import time, os
+
+from selenium.webdriver.chrome.options import Options
+from selenium.webdriver.chrome.webdriver import WebDriver as ChromeDriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.common.keys import Keys
+from bs4 import BeautifulSoup
+
+
+class GitHubBot:
+ def __init__(self):
+ self.start_driver()
+ time.sleep(3)
+ self.login()
+ self.followers = []
+ self.following = []
+
+
+ def start_driver(self):
+ chrome_options = Options()
+ chrome_options.add_experimental_option("detach", True)
+ self.driver = ChromeDriver(options=chrome_options)
+ self.driver.get(url="https://github.com/login")
+
+ # The following method will log in to GitHub
+ def login(self):
+ email = os.environ.get("email")
+ password = os.environ.get("password")
+ if not email or not password:
+ raise RuntimeError("Missing email or password environment variable.")
+
+ email_input = self.driver.find_element(By.NAME, "login")
+ password_input = self.driver.find_element(By.NAME, "password")
+ email_input.send_keys(email)
+ time.sleep(1)
+ password_input.send_keys(password, Keys.ENTER)
+ time.sleep(10)
+
+ # The following bot unfollows accounts for the person's own given page
+ # replace meliksahyorulmazlar with the name of your account
+ def unfollow(self, number: int):
+ page = f"https://github.com/meliksahyorulmazlar?page={number}&tab=following"
+ self.driver.get(page)
+
+ paths = []
+ path = "#user-profile-frame > div > div:nth-child(1) > div.d-table-cell.col-2.v-align-top.text-right > span > form:nth-child(2) > input.btn.btn-sm"
+ for i in range(1, 51):
+ replaced = f"div:nth-child({i})"
+ new_path = path.replace("div:nth-child(1)", replaced)
+ paths.append(new_path)
+
+ for path in paths:
+ x = self.driver.find_element(By.CSS_SELECTOR, path)
+ x.click()
+ time.sleep(0.5)
+ time.sleep(5)
+
+ # The following method follows an account when given it's url, and it's page number
+ def follow(self, page: str, number: int):
+ website = f"{page}?page={number}&tab=followers"
+ self.driver.get(website)
+ paths = []
+ path1 = "#user-profile-frame > div > div:nth-child(1) > div.d-table-cell.col-2.v-align-top.text-right > span > form:nth-child(1) > input.btn.btn-sm"
+ path2 = "#user-profile-frame > div > div:nth-child(1) > div.d-table-cell.col-2.v-align-top.text-right > span > form:nth-child(2) > input.btn.btn-sm"
+ for i in range(1, 51):
+ replaced = f"div:nth-child({i})"
+ new_path1 = path1.replace("div:nth-child(1)", replaced)
+ new_path2 = path2.replace("div:nth-child(1)", replaced)
+ tpl = new_path1, new_path2
+ paths.append(tpl)
+
+ for path in paths:
+ a = self.driver.find_element(By.CSS_SELECTOR, path[0])
+ b = self.driver.find_element(By.CSS_SELECTOR, path[1])
+ if a.is_enabled() and a.is_displayed():
+ a.click()
+ elif b.is_enabled() and b.is_displayed():
+ b.click()
+ number = random.randint(1,10000)
+ t = number/10000
+ time.sleep(t)
+ time.sleep(2)
+
+ def find_followers(self):
+ website = f"https://github.com/meliksahyorulmazlar"
+ self.driver.get(website)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ links = soup.find_all("a", href=True)
+ link = [link.text for link in links if "followers" in link['href']]
+ link = link[0]
+ link = float(link.split("k")[0].strip()) * 1000
+ page_count = int((link // 50) + 1)
+ possible = f"https://github.com/meliksahyorulmazlar?page={page_count}&tab=followers"
+ self.driver.get(possible)
+ soup = BeautifulSoup(self.driver.page_source, 'lxml')
+ p_tag = soup.find("p", class_="mt-4")
+ if p_tag is not None:
+ page_count -= 1
+ number = page_count
+ print(number)
+ for number in range(1,number+1):
+ page = f"https://github.com/meliksahyorulmazlar?page={number}&tab=followers"
+ self.driver.get(page)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content,'lxml')
+ users = [span.text for span in soup.find_all('span',class_='Link--secondary')]
+ self.followers += users
+
+ def find_following(self):
+ number = 30
+ website = f"https://github.com/meliksahyorulmazlar"
+ self.driver.get(website)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ links = soup.find_all("a", href=True)
+ link = [link.text for link in links if "following" in link['href']]
+ link = link[0]
+ link = float(link.split("k")[0].strip()) * 1000
+ page_count = int((link // 50) + 1)
+ possible = f"https://github.com/meliksahyorulmazlar?page={page_count}&tab=following"
+ self.driver.get(possible)
+ soup = BeautifulSoup(self.driver.page_source, 'lxml')
+ p_tag = soup.find("p", class_="mt-4")
+ if p_tag is not None:
+ page_count -= 1
+ number = page_count
+ print(number)
+ for number in range(1, number + 1):
+ page = f"https://github.com/meliksahyorulmazlar?page={number}&tab=following"
+ self.driver.get(page)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ users = [span.text for span in soup.find_all('span', class_='Link--secondary')]
+ self.following += users
+
+ def check_accounts(self):
+ self.find_followers()
+ self.find_following()
+ print(self.followers)
+ print(len(self.followers))
+ print(self.following)
+ print(len(self.following))
+ accounts = ["IDouble","gamemann",'JohnMwendwa','BEPb','cumsoft','esin','kenjinote','peter-kimanzi','eust-w','OracleBrain','angusshire','Charles-Chrismann','jrohitofficial','george0st','mustafacagri','samarjitsahoo','alineai18','AbdeenM','cusspvz','aplus-developer','ip681','Shehab-Hegab','V1nni00','dalindev','JCSIVO','ethanflower1903',"Nakshatra05",'warmice71','mxmnk','otaviossousa','seniorvuejsdeveloper','mstraughan86','vivekweb2013','Magicianred','JubayerRiyad','MichalPaszkiewicz','mahseema','KevinHock','ValentineFernandes','jeffersonsimaogoncalves','AppServiceProvider','Rodrigo-Cn','jdevfullstack','kulikov-dev','xopaz','dirambora','deepsea514','nikitavoloboev','Gizachew29','AlianeAmaral','decoderwhoami','milsaware','somekindofwallflower']
+
+ random.shuffle(accounts)
+ accounts_to_follow = []
+ if len(accounts_to_follow) < 500:
+ for account in accounts:
+ if len(accounts_to_follow) <500:
+ website = f"https://github.com/{account}"
+ self.driver.get(website)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ links = soup.find_all("a", href=True)
+ link = [link.text for link in links if "followers" in link['href']]
+ link = link[0]
+ link = float(link.split("k")[0].strip()) * 1000
+ page_count = int((link // 50) + 1)
+ possible = f"https://github.com/{account}?page={page_count}&tab=followers"
+ self.driver.get(possible)
+ soup = BeautifulSoup(self.driver.page_source, 'lxml')
+ p_tag = soup.find("p", class_="mt-4")
+ if p_tag is not None:
+ page_count -= 1
+ number = page_count
+ for number in range(1, number + 1):
+ if len(accounts_to_follow) < 500:
+ page = f"https://github.com/{account}?page={number}&tab=followers"
+ self.driver.get(page)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ users = [span.text for span in soup.find_all('span', class_='Link--secondary')]
+ if len(accounts_to_follow) < 500:
+ for user in users:
+ if len(accounts_to_follow) < 500:
+ if user not in self.followers and user not in self.following:
+ accounts_to_follow.append(user)
+ print(user, len(accounts_to_follow))
+ for account in accounts_to_follow:
+ if account not in self.following and not account in self.followers:
+ user_page = f"https://github.com/{account}"
+ self.driver.get(user_page)
+ inputs = self.driver.find_elements(By.TAG_NAME,'input')
+ buttons = [inp for inp in inputs if inp.get_attribute('title') == f'Follow {account}']
+ if buttons:
+ button = buttons[0]
+ button.click()
+
+ def unfollow_account(self,account:str):
+ user_page = f"https://github.com/{account}"
+ self.driver.get(user_page)
+ inputs = self.driver.find_elements(By.TAG_NAME, 'input')
+ buttons = [inp for inp in inputs if inp.get_attribute('title') == f'Unfollow {account}']
+ if buttons:
+ button = buttons[0]
+ button.click()
+
+ def unfollow_followed_ones(self):
+ self.followers = []
+ self.following = []
+ self.find_followers()
+ self.find_following()
+
+ accounts = [account for account in self.following if account in self.followers]
+ special = ["emirkaanozdemr","nepthius"]
+ for account in accounts:
+ if account not in special:
+ self.unfollow_account(account)
+
+ def automate(self):
+ while True:
+ t1 = time.time()
+ self.followers = []
+ self.following = []
+ self.find_following()
+ self.find_followers()
+ self.check_accounts()
+ checked = False
+ loop = True
+ while loop == True:
+ t2 = time.time()
+ if t2-t1 > 2700 and checked == False:
+ self.unfollow_followed_ones()
+ checked = True
+ loop = False
+
+ new_loop = True
+ while new_loop:
+ t2 = time.time()
+ if t2-t1 >= 3600:
+ new_loop = False
+
+
+if __name__ == "__main__":
+ github_bot = GitHubBot()
+ github_bot.automate()
diff --git a/archive/legacy-follow-scripts/follow_unfollow_main_j.py b/archive/legacy-follow-scripts/follow_unfollow_main_j.py
new file mode 100644
index 0000000..d78ef12
--- /dev/null
+++ b/archive/legacy-follow-scripts/follow_unfollow_main_j.py
@@ -0,0 +1,238 @@
+import random
+import time, os
+
+from selenium.webdriver.chrome.options import Options
+from selenium.webdriver.chrome.webdriver import WebDriver as ChromeDriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.common.keys import Keys
+from bs4 import BeautifulSoup
+
+
+class GitHubBot:
+ def __init__(self):
+ self.start_driver()
+ time.sleep(3)
+ self.login()
+ self.followers = []
+ self.following = []
+
+
+ def start_driver(self):
+ chrome_options = Options()
+ chrome_options.add_experimental_option("detach", True)
+ self.driver = ChromeDriver(options=chrome_options)
+ self.driver.get(url="https://github.com/login")
+
+ # The following method will log in to GitHub
+ def login(self):
+ email = os.environ.get("email")
+ password = os.environ.get("password")
+ if not email or not password:
+ raise RuntimeError("Missing email or password environment variable.")
+
+ email_input = self.driver.find_element(By.NAME, "login")
+ password_input = self.driver.find_element(By.NAME, "password")
+ email_input.send_keys(email)
+ time.sleep(1)
+ password_input.send_keys(password, Keys.ENTER)
+ time.sleep(10)
+
+ # The following bot unfollows accounts for the person's own given page
+ # replace jaseva with the name of your account
+ def unfollow(self, number: int):
+ page = f"https://github.com/jaseva?page={number}&tab=following"
+ self.driver.get(page)
+
+ paths = []
+ path = "#user-profile-frame > div > div:nth-child(1) > div.d-table-cell.col-2.v-align-top.text-right > span > form:nth-child(2) > input.btn.btn-sm"
+ for i in range(1, 51):
+ replaced = f"div:nth-child({i})"
+ new_path = path.replace("div:nth-child(1)", replaced)
+ paths.append(new_path)
+
+ for path in paths:
+ x = self.driver.find_element(By.CSS_SELECTOR, path)
+ x.click()
+ time.sleep(0.5)
+ time.sleep(5)
+
+ # The following method follows an account when given it's url, and it's page number
+ def follow(self, page: str, number: int):
+ website = f"{page}?page={number}&tab=followers"
+ self.driver.get(website)
+ paths = []
+ path1 = "#user-profile-frame > div > div:nth-child(1) > div.d-table-cell.col-2.v-align-top.text-right > span > form:nth-child(1) > input.btn.btn-sm"
+ path2 = "#user-profile-frame > div > div:nth-child(1) > div.d-table-cell.col-2.v-align-top.text-right > span > form:nth-child(2) > input.btn.btn-sm"
+ for i in range(1, 51):
+ replaced = f"div:nth-child({i})"
+ new_path1 = path1.replace("div:nth-child(1)", replaced)
+ new_path2 = path2.replace("div:nth-child(1)", replaced)
+ tpl = new_path1, new_path2
+ paths.append(tpl)
+
+ for path in paths:
+ a = self.driver.find_element(By.CSS_SELECTOR, path[0])
+ b = self.driver.find_element(By.CSS_SELECTOR, path[1])
+ if a.is_enabled() and a.is_displayed():
+ a.click()
+ elif b.is_enabled() and b.is_displayed():
+ b.click()
+ number = random.randint(1,10000)
+ t = number/10000
+ time.sleep(t)
+ time.sleep(2)
+
+ def find_followers(self):
+ website = f"https://github.com/jaseva"
+ self.driver.get(website)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ links = soup.find_all("a", href=True)
+ link = [link.text for link in links if "followers" in link['href']]
+ link = link[0]
+ link = float(link.split("k")[0].strip()) * 1000
+ page_count = int((link // 50) + 1)
+ possible = f"https://github.com/jaseva?page={page_count}&tab=followers"
+ self.driver.get(possible)
+ soup = BeautifulSoup(self.driver.page_source, 'lxml')
+ p_tag = soup.find("p", class_="mt-4")
+ if p_tag is not None:
+ page_count -= 1
+ number = page_count
+ print(number)
+ for number in range(1,number+1):
+ page = f"https://github.com/jaseva?page={number}&tab=followers"
+ self.driver.get(page)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content,'lxml')
+ users = [span.text for span in soup.find_all('span',class_='Link--secondary')]
+ self.followers += users
+
+ def find_following(self):
+ number = 30
+ website = f"https://github.com/jaseva"
+ self.driver.get(website)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ links = soup.find_all("a", href=True)
+ link = [link.text for link in links if "following" in link['href']]
+ link = link[0]
+ link = float(link.split("k")[0].strip()) * 1000
+ page_count = int((link // 50) + 1)
+ possible = f"https://github.com/jaseva?page={page_count}&tab=following"
+ self.driver.get(possible)
+ soup = BeautifulSoup(self.driver.page_source, 'lxml')
+ p_tag = soup.find("p", class_="mt-4")
+ if p_tag is not None:
+ page_count -= 1
+ number = page_count
+ print(number)
+ for number in range(1, number + 1):
+ page = f"https://github.com/jaseva?page={number}&tab=following"
+ self.driver.get(page)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ users = [span.text for span in soup.find_all('span', class_='Link--secondary')]
+ self.following += users
+
+ def check_accounts(self):
+ self.find_followers()
+ self.find_following()
+ print(self.followers)
+ print(len(self.followers))
+ print(self.following)
+ print(len(self.following))
+ accounts = ["IDouble","gamemann",'JohnMwendwa','BEPb','cumsoft','esin','kenjinote','peter-kimanzi','eust-w','OracleBrain','angusshire','Charles-Chrismann','jrohitofficial','george0st','mustafacagri','samarjitsahoo','alineai18','AbdeenM','cusspvz','aplus-developer','ip681','Shehab-Hegab','V1nni00','dalindev','JCSIVO','ethanflower1903',"Nakshatra05",'warmice71','mxmnk','otaviossousa','seniorvuejsdeveloper','mstraughan86','vivekweb2013','Magicianred','JubayerRiyad','MichalPaszkiewicz','mahseema','KevinHock','ValentineFernandes','jeffersonsimaogoncalves','AppServiceProvider','Rodrigo-Cn','jdevfullstack','kulikov-dev','xopaz','dirambora','deepsea514','nikitavoloboev','Gizachew29','AlianeAmaral','decoderwhoami','milsaware','somekindofwallflower']
+
+ random.shuffle(accounts)
+ accounts_to_follow = []
+ if len(accounts_to_follow) < 500:
+ for account in accounts:
+ if len(accounts_to_follow) <500:
+ website = f"https://github.com/{account}"
+ self.driver.get(website)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ links = soup.find_all("a", href=True)
+ link = [link.text for link in links if "followers" in link['href']]
+ link = link[0]
+ link = float(link.split("k")[0].strip()) * 1000
+ page_count = int((link // 50) + 1)
+ possible = f"https://github.com/{account}?page={page_count}&tab=followers"
+ self.driver.get(possible)
+ soup = BeautifulSoup(self.driver.page_source, 'lxml')
+ p_tag = soup.find("p", class_="mt-4")
+ if p_tag is not None:
+ page_count -= 1
+ number = page_count
+ for number in range(1, number + 1):
+ if len(accounts_to_follow) < 500:
+ page = f"https://github.com/{account}?page={number}&tab=followers"
+ self.driver.get(page)
+ html_content = self.driver.page_source
+ soup = BeautifulSoup(html_content, 'lxml')
+ users = [span.text for span in soup.find_all('span', class_='Link--secondary')]
+ if len(accounts_to_follow) < 500:
+ for user in users:
+ if len(accounts_to_follow) < 500:
+ if user not in self.followers and user not in self.following:
+ accounts_to_follow.append(user)
+ print(user, len(accounts_to_follow))
+ for account in accounts_to_follow:
+ if account not in self.following and not account in self.followers:
+ user_page = f"https://github.com/{account}"
+ self.driver.get(user_page)
+ inputs = self.driver.find_elements(By.TAG_NAME,'input')
+ buttons = [inp for inp in inputs if inp.get_attribute('title') == f'Follow {account}']
+ if buttons:
+ button = buttons[0]
+ button.click()
+
+ def unfollow_account(self,account:str):
+ user_page = f"https://github.com/{account}"
+ self.driver.get(user_page)
+ inputs = self.driver.find_elements(By.TAG_NAME, 'input')
+ buttons = [inp for inp in inputs if inp.get_attribute('title') == f'Unfollow {account}']
+ if buttons:
+ button = buttons[0]
+ button.click()
+
+ def unfollow_followed_ones(self):
+ self.followers = []
+ self.following = []
+ self.find_followers()
+ self.find_following()
+
+ accounts = [account for account in self.following if account in self.followers]
+ special = ["emirkaanozdemr","nepthius"]
+ for account in accounts:
+ if account not in special:
+ self.unfollow_account(account)
+
+ def automate(self):
+ while True:
+ t1 = time.time()
+ self.followers = []
+ self.following = []
+ self.find_following()
+ self.find_followers()
+ self.check_accounts()
+ checked = False
+ loop = True
+ while loop == True:
+ t2 = time.time()
+ if t2-t1 > 2700 and checked == False:
+ self.unfollow_followed_ones()
+ checked = True
+ loop = False
+
+ new_loop = True
+ while new_loop:
+ t2 = time.time()
+ if t2-t1 >= 3600:
+ new_loop = False
+
+
+if __name__ == "__main__":
+ github_bot = GitHubBot()
+ github_bot.automate()
diff --git a/archive/legacy-main-scripts/README.md b/archive/legacy-main-scripts/README.md
new file mode 100644
index 0000000..00eedd6
--- /dev/null
+++ b/archive/legacy-main-scripts/README.md
@@ -0,0 +1,8 @@
+# Legacy Main Scripts
+
+This folder contains archived root-level `main*.py` snapshots from earlier iterations of the project.
+
+- `main.py` in the repository root remains the active desktop entry point.
+- The numbered scripts are preserved here for historical reference and should not be treated as current application code.
+- The web dashboard and backend are unaffected by these archived files.
+
diff --git a/archive/legacy-main-scripts/main1.py b/archive/legacy-main-scripts/main1.py
new file mode 100644
index 0000000..937383b
--- /dev/null
+++ b/archive/legacy-main-scripts/main1.py
@@ -0,0 +1,321 @@
+# main.py
+# MIT License
+# Created Date: 2024-09-02
+# Version 1.1.2
+# Dark Theme
+
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+# Function to track followers
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to start tracking in a separate thread
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL) # Enable button after tracking
+
+# Function to show analytics
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to segment followers
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to generate AI summary
+def generate_summary(username, token):
+ try:
+ # Initialize OpenAI API key
+ client = OpenAI(
+ api_key=os.environ['OPENAI_API_KEY']
+ )
+
+ # Define GitHub API URLs
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ # Fetch GitHub profile and repos data
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ # Check for successful API response
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ # Extract profile information and repos
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ # Create prompt for OpenAI API
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ # Make request to OpenAI chat completions
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {
+ "role": "user",
+ "content": "Write a summary from this user's GitHub profile."
+ }
+ ]
+ )
+
+ # Extract and return summary using object attributes
+ summary = completion.choices[0].message.content.strip()
+ return summary
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
+
+# Function to wrap AI generated summary
+def generate_summary_wrapper():
+ username = profile_entry.get().strip()
+ token = token_entry.get().strip()
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please enter username and token.")
+ return
+ summary = generate_summary(username, token)
+ if summary:
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Summary: {summary}", "summary")
+ summary_text.tag_config("summary", foreground="white")
+ summary_text.config(state=tk.DISABLED)
+ # Switch to the Profile Summary tab
+ # notebook.select(1) # Index 1 refers to the "Profile Summary" tab
+ switch_tab(notebook, 1) # Switch to "Profile Summary" tab after generating summary
+
+def switch_tab(notebook, index):
+ # Initialize selected_tab here
+ selected_tab = 0 # or any default value
+
+ notebook.select(index)
+ style.configure("TNotebook.Tab{}".format(index), background="blue", foreground="white")
+ style.configure("TNotebook.Tab{}".format(selected_tab), background="gray", foreground="white")
+ selected_tab = index
+
+# GUI setup
+root = tk.Tk()
+root.title("GitHub Follower Checker")
+
+# Initialize selected tab
+selected_tab = 0
+
+# Configure notebook style
+style = ttk.Style()
+style.theme_use("default")
+style.configure("TNotebook", background="black", foreground="white", tabposition='nw')
+style.configure("TNotebook.Tab", background="gray", foreground="white", padding=[10, 10])
+style.configure("TFrame", background="black")
+style.configure("TLabel", background="black", foreground="white")
+style.configure("TEntry", background="gray", foreground="white")
+style.configure("TButton", background="darkgray", foreground="black")
+
+# Add notebook to root
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+# Increase window size to accommodate all elements
+root.geometry("1000x800")
+root.resizable(True, True)
+
+# Header
+header = tk.Label(root, text="GitHub Follower Checker", font=('Helvetica', 18, 'bold'), pady=10, bg='black', fg='white')
+header.pack()
+
+# Frame for input fields with columns
+input_frame = tk.Frame(root, padx=20, pady=10, bg='black')
+input_frame.pack(fill=tk.X)
+
+# Left column for follower tracking
+left_column = tk.Frame(input_frame, padx=10, bg='black')
+left_column.pack(side=tk.LEFT, fill=tk.Y)
+
+username_label = tk.Label(left_column, text="GitHub Username:", font=('Arial', 12, 'bold'), bg='black', fg='white')
+username_label.grid(row=0, column=0, sticky='e', pady=5)
+
+username_entry = tk.Entry(left_column, font=('Arial', 12), bg='gray', fg='white')
+username_entry.grid(row=0, column=1, pady=5)
+
+token_label = tk.Label(left_column, text="GitHub Token:", font=('Arial', 12, 'bold'), bg='black', fg='white')
+token_label.grid(row=1, column=0, sticky='e', pady=5)
+
+token_entry = tk.Entry(left_column, font=('Arial', 12), bg='gray', fg='white', show="*")
+token_entry.grid(row=1, column=1, pady=5)
+
+followers_file_label = tk.Label(left_column, text="Followers File:", font=('Arial', 12, 'bold'), bg='black', fg='white')
+followers_file_label.grid(row=2, column=0, sticky='e', pady=5)
+
+followers_file_entry = tk.Entry(left_column, font=('Arial', 12), bg='gray', fg='white')
+followers_file_entry.grid(row=2, column=1, pady=5)
+
+track_button = tk.Button(left_column, text="Track Followers", font=('Arial', 12, 'bold'), bg='darkgray', fg='black', command=start_tracking)
+track_button.grid(row=3, column=0, columnspan=2, pady=10)
+
+show_analytics_button = tk.Button(left_column, text="Show Analytics", font=('Arial', 12, 'bold'), bg='darkgray', fg='black', command=show_analytics, state=tk.DISABLED)
+show_analytics_button.grid(row=4, column=0, columnspan=2, pady=10)
+
+segment_followers_button = tk.Button(left_column, text="Segment Followers", font=('Arial', 12, 'bold'), bg='darkgray', fg='black', command=segment_followers_ui, state=tk.DISABLED)
+segment_followers_button.grid(row=5, column=0, columnspan=2, pady=10)
+
+# Dropdown for segmentation type
+segmentation_type_var = tk.StringVar(left_column)
+segmentation_type_var.set("Please Select")
+
+segmentation_label = tk.Label(left_column, text="Segmentation Type:", font=('Arial', 12, 'bold'), bg='black', fg='white')
+segmentation_label.grid(row=6, column=0, sticky='e', pady=5)
+
+segmentation_dropdown = tk.OptionMenu(left_column, segmentation_type_var, "repo", "activity", "location", "company")
+segmentation_dropdown.config(font=('Arial', 12), bg='gray', fg='white')
+segmentation_dropdown.grid(row=6, column=1, pady=5)
+
+# Right column for profile summary
+right_column = tk.Frame(input_frame, padx=10, bg='black')
+right_column.pack(side=tk.RIGHT, fill=tk.Y)
+
+profile_label = tk.Label(right_column, text="Profile Username:", font=('Arial', 12, 'bold'), bg='black', fg='white')
+profile_label.grid(row=0, column=0, sticky='e', pady=5)
+
+profile_entry = tk.Entry(right_column, font=('Arial', 12), bg='gray', fg='white')
+profile_entry.grid(row=0, column=1, pady=5)
+
+summary_button = tk.Button(right_column, text="Generate Summary", font=('Arial', 12, 'bold'), bg='darkgray', fg='black', command=generate_summary_wrapper, state=tk.DISABLED)
+summary_button.grid(row=1, column=0, columnspan=2, pady=10)
+
+# Followers Tab
+followers_tab = ttk.Frame(notebook)
+notebook.add(followers_tab, text="Followers")
+
+follower_text = scrolledtext.ScrolledText(followers_tab, wrap=tk.WORD, font=('Arial', 12), bg='gray', fg='white')
+follower_text.pack(expand=True, fill='both')
+follower_text.config(state=tk.DISABLED)
+
+# Profile Summary Tab
+summary_tab = ttk.Frame(notebook)
+notebook.add(summary_tab, text="Profile Summary")
+
+summary_text = scrolledtext.ScrolledText(summary_tab, wrap=tk.WORD, font=('Arial', 12), bg='gray', fg='white')
+summary_text.pack(expand=True, fill='both')
+summary_text.config(state=tk.DISABLED)
+
+root.mainloop()
diff --git a/archive/legacy-main-scripts/main10.py b/archive/legacy-main-scripts/main10.py
new file mode 100644
index 0000000..c36477c
--- /dev/null
+++ b/archive/legacy-main-scripts/main10.py
@@ -0,0 +1,419 @@
+# main.py
+# MIT License
+# Created Date: 2024-09-02
+# Created By: Jason Evans
+# Version 1.1.1.2
+
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk, Menu
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+def create_summary_table(conn):
+ cursor = conn.cursor()
+ cursor.execute('''CREATE TABLE IF NOT EXISTS profile_summaries (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ profile_description TEXT,
+ repos_contributed_to TEXT,
+ summary TEXT,
+ date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )''')
+ conn.commit()
+
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ following_url = f'https://api.github.com/users/{username}/following'
+ current_followers = get_all_followers(username, token, followers_url)
+ current_followings = get_all_followers(username, token, following_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(current_followers) & set(current_followings))
+ not_following_back = list(set(current_followings) - set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who follow back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ formatted_not_back, color_not_back = format_list("Users you follow who don't follow back", not_following_back, "orange")
+ follower_text.insert(tk.END, formatted_not_back, "not_following_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+ follower_text.tag_config("not_following_back", foreground=color_not_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0)
+
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL)
+
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0)
+
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+def generate_summary(username, token):
+ try:
+ client = OpenAI(api_key=os.environ['OPENAI_API_KEY'])
+
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {"role": "user", "content": "Write a summary from this user's GitHub profile."}
+ ]
+ )
+
+ summary = completion.choices[0].message.content.strip()
+ return summary, profile_description, repos_contributed_to
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None, None, None
+
+def save_summary_to_db(username, summary, profile_description, repos_contributed_to):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ cursor = conn.cursor()
+ cursor.execute("INSERT INTO profile_summaries (username, profile_description, repos_contributed_to, summary) VALUES (?, ?, ?, ?)",
+ (username, profile_description, ', '.join(repos_contributed_to), summary))
+ conn.commit()
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+
+def show_summary():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ summary, profile_description, repos_contributed_to = generate_summary(username, token)
+
+ if summary:
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Username: {username}\n\n")
+ summary_text.insert(tk.END, f"Profile Description: {profile_description}\n\n")
+ summary_text.insert(tk.END, f"Repositories Contributed To: {', '.join(repos_contributed_to)}\n\n")
+ summary_text.insert(tk.END, f"Summary:\n{summary}\n")
+ summary_text.config(state=tk.DISABLED)
+
+ save_summary_to_db(username, summary, profile_description, repos_contributed_to)
+
+ switch_tab(notebook, 1)
+
+def switch_tab(notebook, tab_index):
+ notebook.select(tab_index)
+
+def set_theme(theme):
+ if theme == "light":
+ root.configure(bg="white")
+ style.configure('TLabel', background="white", foreground="black")
+ follower_text.configure(bg="white", fg="black")
+ elif theme == "dark":
+ root.configure(bg="black")
+ style.configure('TLabel', background="black", foreground="white")
+ follower_text.configure(bg="black", fg="white")
+ elif theme == "solarized_light":
+ root.configure(bg="#FDF6E3")
+ style.configure('TLabel', background="#FDF6E3", foreground="#657B83")
+ follower_text.configure(bg="#FDF6E3", fg="#657B83")
+ elif theme == "custom":
+ root.configure(bg="#2E3440") # replace with your custom color
+ style.configure('TLabel', background="#2E3440", foreground="#2E3440") # replace with your custom color
+ follower_text.configure(bg="#2E3440", fg="#2E3440")
+ else:
+ root.configure(bg="default_color_bg")
+ style.configure('TLabel', background="default_color_bg", foreground="default_color_fg")
+ follower_text.configure(bg="default_color_bg", fg="default_color_fg")
+
+def query_clinical_trials(keyword, status):
+ try:
+ base_url = "https://clinicaltrials.gov/api/query/full_studies"
+ params = {
+ "expr": keyword,
+ "fmt": "json",
+ "min_rnk": 1,
+ "max_rnk": 10,
+ "max_rnk": 10,
+ "status": status
+ }
+
+ response = requests.get(base_url, params=params)
+ response.raise_for_status()
+ data = response.json()
+
+ studies = data.get('FullStudiesResponse', {}).get('FullStudies', [])
+ results = []
+ for study in studies:
+ study_data = study.get('Study', {})
+ title = study_data.get('ProtocolSection', {}).get('IdentificationModule', {}).get('OfficialTitle', 'No title available')
+ status = study_data.get('ProtocolSection', {}).get('StatusModule', {}).get('OverallStatus', 'No status available')
+ results.append(f"Title: {title}\nStatus: {status}\n")
+
+ return "\n".join(results)
+
+ except Exception as e:
+ messagebox.showerror("Error", f"An error occurred while querying ClinicalTrials.gov: {str(e)}")
+ return None
+
+# Add ClinicalTrials.gov Query Section to Tab 1 or create a new tab
+
+# ClinicalTrials Section UI
+def create_clinical_trials_ui(tab):
+ # Frame for ClinicalTrials Inputs
+ clinical_trials_frame = ttk.Frame(tab)
+ clinical_trials_frame.pack(pady=10, padx=10, fill="x")
+
+ keyword_label = ttk.Label(clinical_trials_frame, text="Search Keyword:")
+ keyword_label.grid(row=0, column=0, sticky="e")
+ keyword_entry = ttk.Entry(clinical_trials_frame)
+ keyword_entry.grid(row=0, column=1, padx=5, pady=5)
+
+ status_label = ttk.Label(clinical_trials_frame, text="Status:")
+ status_label.grid(row=1, column=0, sticky="e")
+ status_var = tk.StringVar(value="All")
+ status_menu = ttk.OptionMenu(clinical_trials_frame, status_var, "All", "Completed", "Recruiting", "Active")
+ status_menu.grid(row=1, column=1, padx=5, pady=5)
+
+ query_button = ttk.Button(clinical_trials_frame, text="Query ClinicalTrials.gov", command=lambda: query_clinical_trials_ui(keyword_entry.get().strip(), status_var.get()))
+ query_button.grid(row=2, column=1, padx=5, pady=10)
+
+ # Frame for ClinicalTrials Text Output
+ clinical_trials_text = scrolledtext.ScrolledText(tab, wrap=tk.WORD, height=15, state=tk.DISABLED)
+ clinical_trials_text.pack(pady=10, padx=10, fill="both", expand=True)
+
+ return clinical_trials_text
+
+def query_clinical_trials_ui(keyword, status):
+ if not keyword:
+ messagebox.showwarning("Input Error", "Please enter a search keyword.")
+ return
+
+ results = query_clinical_trials(keyword, status)
+ if results:
+ clinical_trials_text.config(state=tk.NORMAL)
+ clinical_trials_text.delete(1.0, tk.END)
+ clinical_trials_text.insert(tk.END, results)
+ clinical_trials_text.config(state=tk.DISABLED)
+
+# UI Setup
+root = tk.Tk()
+root.title("GitHub Follower Tracker")
+root.geometry("800x600")
+
+# Create a style object
+style = ttk.Style(root)
+
+# Notebook for Tabs
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill="both")
+
+# Tab 1: Follower Data
+tab1 = ttk.Frame(notebook)
+notebook.add(tab1, text="Follower Data")
+
+# Tab 2: Profile Summary
+tab2 = ttk.Frame(notebook)
+notebook.add(tab2, text="Profile Summary")
+
+# Tab 3: Clinical Trials
+tab3 = ttk.Frame(notebook)
+notebook.add(tab3, text="ClinicalTrials Data")
+
+# Create UI for ClinicalTrials Tab
+clinical_trials_text = create_clinical_trials_ui(tab3)
+
+# Frame for User Inputs
+input_frame = ttk.Frame(tab1)
+input_frame.pack(pady=10, padx=10, fill="x")
+
+username_label = ttk.Label(input_frame, text="GitHub Username:")
+username_label.grid(row=0, column=0, sticky="e")
+username_entry = ttk.Entry(input_frame)
+username_entry.grid(row=0, column=1, padx=5, pady=5)
+
+token_label = ttk.Label(input_frame, text="GitHub Token:")
+token_label.grid(row=1, column=0, sticky="e")
+token_entry = ttk.Entry(input_frame, show="*")
+token_entry.grid(row=1, column=1, padx=5, pady=5)
+
+followers_file_label = ttk.Label(input_frame, text="Followers File:")
+followers_file_label.grid(row=2, column=0, sticky="e")
+followers_file_entry = ttk.Entry(input_frame)
+followers_file_entry.grid(row=2, column=1, padx=5, pady=5)
+
+start_button = ttk.Button(input_frame, text="Start Tracking", command=start_tracking)
+start_button.grid(row=3, column=1, padx=5, pady=10)
+
+# Frame for Follower Text Output
+follower_text = scrolledtext.ScrolledText(tab1, wrap=tk.WORD, height=15, state=tk.DISABLED)
+follower_text.pack(pady=10, padx=10, fill="both", expand=True)
+
+# Analytics Button
+show_analytics_button = ttk.Button(tab1, text="Show Analytics", command=show_analytics, state=tk.DISABLED)
+show_analytics_button.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Create the segmentation type variable with a default read-only label "Please Select"
+segmentation_type_var = tk.StringVar(value="Please Select")
+
+# Label for Segmentation
+segmentation_label = tk.Label(tab1, text="Segment By:")
+segmentation_label.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Dropdown menu for Segmentation Types
+segmentation_menu = tk.OptionMenu(tab1, segmentation_type_var, "repo", "activity")
+segmentation_menu.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Segment followers button
+segment_followers_button = tk.Button(tab1, text="Segment Followers", command=segment_followers_ui, state=tk.DISABLED)
+# segment_followers_button.pack(anchor="w", pady=5)
+segment_followers_button.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Generate Summary Button
+summary_button = ttk.Button(tab1, text="Generate Summary", command=show_summary, state=tk.DISABLED)
+summary_button.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Frame for Summary Text Output
+summary_text = scrolledtext.ScrolledText(tab2, wrap=tk.WORD, height=15, state=tk.DISABLED)
+summary_text.pack(pady=10, padx=10, fill="both", expand=True)
+
+# Menu Bar for Theme Selection
+menu_bar = Menu(root)
+root.config(menu=menu_bar)
+
+file_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="File", menu=file_menu)
+file_menu.add_command(label="Exit", command=root.quit)
+
+# Theme Menu
+theme_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="Settings", menu=theme_menu)
+
+theme_menu.add_command(label="Light Theme", command=lambda: set_theme("light"))
+theme_menu.add_command(label="Dark Theme", command=lambda: set_theme("dark"))
+theme_menu.add_command(label="Solarized Light Theme", command=lambda: set_theme("solarized_light"))
+theme_menu.add_command(label="Custom Theme", command=lambda: set_theme("custom"))
+
+# Main Loop
+root.mainloop()
\ No newline at end of file
diff --git a/archive/legacy-main-scripts/main11.py b/archive/legacy-main-scripts/main11.py
new file mode 100644
index 0000000..d18ac85
--- /dev/null
+++ b/archive/legacy-main-scripts/main11.py
@@ -0,0 +1,580 @@
+# main.py
+# MIT License
+# Created Date: 2024-09-02
+# Created By: Jason Evans
+# Modified Date: 2024-09-26
+# Modified By: Jason Evans
+# Version 1.2.2
+
+import tkinter as tk
+from tkinter import ttk, scrolledtext, Menu, messagebox
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+import sys
+import logging
+
+# Set up logger for debugging and error tracking
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+handler = logging.StreamHandler(sys.stdout)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+handler.setFormatter(formatter)
+logger.addHandler(handler)
+
+# Load API key from .env file
+load_dotenv()
+
+# Function to check for the existence of the 'profile_summaries' table and creates it if it doesn't exist
+# Stores the generated summaries
+def create_summary_table(conn):
+ cursor = conn.cursor()
+ cursor.execute('''CREATE TABLE IF NOT EXISTS profile_summaries (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ profile_description TEXT,
+ repos_contributed_to TEXT,
+ summary TEXT,
+ date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )''')
+ conn.commit()
+
+# Function to track followers
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Helper function to get all users you are following
+def get_all_following(username, token):
+ following_url = f'https://api.github.com/users/{username}/following'
+ return get_all_followers(username, token, following_url) # Reuse get_all_followers for simplicity
+
+# Function to mass unfollow users who do not follow back
+def unfollow_users(username, token, not_following_back):
+ headers = {'Authorization': f'token {token}'}
+
+ unfollow_url = f'https://api.github.com/user/following/{{}}'
+
+ for user in not_following_back:
+ try:
+ response = requests.delete(unfollow_url.format(user), headers=headers)
+ if response.status_code == 204:
+ logger.info(f"Successfully unfollowed {user}")
+ else:
+ logger.warning(f"Failed to unfollow {user}: {response.status_code}")
+ except Exception as e:
+ logger.error(f"Error unfollowing {user}: {e}")
+ messagebox.showerror("Error", f"Error unfollowing {user}: {e}")
+
+# Modified track_followers function with unfollow logic
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ # Fetch current followers and following lists
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ following_list = get_all_following(username, token) # Fetch users you are following
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ # Find users you are following who don't follow you back
+ not_following_back = list(set(following_list) - set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ # Display follower data in the text box
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ # Add a section to display users not following you back
+ formatted_not_following_back, color_not_following_back = format_list("Not following you back", not_following_back, "purple")
+ follower_text.insert(tk.END, formatted_not_following_back, "not_following_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+ follower_text.tag_config("not_following_back", foreground=color_not_following_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ # Save updated data to file
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ # Unfollow users who do not follow back
+ unfollow_users(username, token, not_following_back) # Call the new unfollow function here
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# # Function to track followers and who you follow that don't follow you back
+# def track_followers(username, token, followers_file):
+# try:
+# conn = sqlite3.connect('follower_data.db')
+# create_table(conn)
+
+# if os.path.exists(followers_file):
+# with open(followers_file, 'r') as f:
+# follower_data = json.load(f)
+# previous_followers = follower_data.get('followers', [])
+# follower_history = follower_data.get('history', {})
+# else:
+# previous_followers = []
+# follower_history = {}
+
+# # Fetch current followers and following lists
+# followers_url = f'https://api.github.com/users/{username}/followers'
+# current_followers = get_all_followers(username, token, followers_url)
+
+# following_list = get_all_following(username, token) # Fetch users you are following
+
+# new_followers = list(set(current_followers) - set(previous_followers))
+# unfollowers = list(set(previous_followers) - set(current_followers))
+# followers_back = list(set(previous_followers) & set(current_followers))
+
+# # Find users you are following who don't follow you back
+# not_following_back = list(set(following_list) - set(current_followers))
+
+# today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+# follower_history[today] = len(current_followers)
+
+# for follower in current_followers:
+# insert_follower(conn, follower, today)
+
+# # Display follower data in the text box
+# follower_text.config(state=tk.NORMAL)
+# follower_text.delete(1.0, tk.END)
+
+# formatted_new, color_new = format_list("New followers", new_followers, "green")
+# follower_text.insert(tk.END, formatted_new, "new_followers")
+
+# formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+# follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+# formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+# follower_text.insert(tk.END, formatted_back, "followers_back")
+
+# # Add a section to display users not following you back
+# formatted_not_following_back, color_not_following_back = format_list("Not following you back", not_following_back, "purple")
+# follower_text.insert(tk.END, formatted_not_following_back, "not_following_back")
+
+# follower_text.tag_config("new_followers", foreground=color_new)
+# follower_text.tag_config("unfollowers", foreground=color_unf)
+# follower_text.tag_config("followers_back", foreground=color_back)
+# follower_text.tag_config("not_following_back", foreground=color_not_following_back)
+
+# follower_text.config(state=tk.DISABLED)
+
+# # Save updated data to file
+# with open(followers_file, 'w') as f:
+# json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+# show_analytics_button.config(state=tk.NORMAL)
+# segment_followers_button.config(state=tk.NORMAL)
+# summary_button.config(state=tk.NORMAL)
+
+# conn.close()
+
+# except Exception as e:
+# messagebox.showerror("Error", str(e))
+# switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to start tracking in a separate thread
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL) # Enable button after tracking
+
+# Function to show analytics
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to segment followers
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to generate AI summary
+def generate_summary(username, token):
+ try:
+ # Initialize OpenAI API key
+ client = OpenAI(
+ api_key=os.environ['OPENAI_API_KEY']
+ )
+
+ # Define GitHub API URLs
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ # Fetch GitHub profile and repos data
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ # Check for successful API response
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ # Extract profile information and repos
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ # Create prompt for OpenAI API
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ # Make request to OpenAI chat completions
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {
+ "role": "user",
+ "content": "Write a summary from this user's GitHub profile."
+ }
+ ]
+ )
+
+ # Extract and return summary using object attributes
+ summary = completion.choices[0].message.content.strip()
+ return summary, profile_description, repos_contributed_to
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
+
+# Function to wrap AI generated summary
+def generate_summary_wrapper():
+ username = profile_entry.get().strip()
+ token = token_entry.get().strip()
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please enter username and token.")
+ return
+ summary, profile_description, repos_contributed_to = generate_summary(username, token)
+
+ if summary:
+
+ # Store the summary in the database
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_summary_table(conn) # Ensure the table is created
+ cursor = conn.cursor()
+
+ # Insert the summary into the database
+ cursor.execute('''INSERT INTO profile_summaries (username, profile_description, repos_contributed_to, summary)
+ VALUES (?, ?, ?, ?)''',
+ (username, profile_description, ", ".join(repos_contributed_to), summary))
+ conn.commit()
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+
+ # Display the summary in the UI
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Summary: {summary}", "summary")
+ summary_text.tag_config("summary", foreground="black")
+ summary_text.config(state=tk.DISABLED)
+
+ # Switch to the Profile Summary tab
+ # notebook.select(1) # Index 1 refers to the "Profile Summary" tab
+ switch_tab(notebook, 1) # Switch to "Profile Summary" tab after generating summary
+
+def switch_tab(notebook, index):
+ # Initialize selected_tab here
+ selected_tab = 0 # or any default value
+
+ notebook.select(index)
+ style.configure("TNotebook.Tab{}".format(index), background="blue", foreground="white")
+ style.configure("TNotebook.Tab{}".format(selected_tab), background="gray", foreground="black")
+ selected_tab = index
+
+def set_theme(theme):
+ if theme == "light":
+ root.configure(bg="white")
+ style.configure('TLabel', background="white", foreground="black")
+ follower_text.configure(bg="white", fg="black")
+ elif theme == "dark":
+ root.configure(bg="black")
+ style.configure('TLabel', background="black", foreground="white")
+ follower_text.configure(bg="black", fg="white")
+ elif theme == "solarized_light":
+ root.configure(bg="#FDF6E3")
+ style.configure('TLabel', background="#FDF6E3", foreground="#657B83")
+ follower_text.configure(bg="#FDF6E3", fg="#657B83")
+ elif theme == "custom":
+ root.configure(bg="#2E3440") # replace with your custom color
+ style.configure('TLabel', background="#2E3440", foreground="#2E3440") # replace with your custom color
+ follower_text.configure(bg="#2E3440", fg="#2E3440")
+ else:
+ root.configure(bg="default_color_bg")
+ style.configure('TLabel', background="default_color_bg", foreground="default_color_fg")
+ follower_text.configure(bg="default_color_bg", fg="default_color_fg")
+
+# GUI setup
+root = tk.Tk()
+root.title("GitHub Follower Checker")
+
+# Initialize selected tab
+selected_tab = 0
+
+# Configure notebook style
+style = ttk.Style()
+style.theme_use("default")
+style.configure("TNotebook.Tab", background="gray", foreground="black")
+
+# Add notebook to root
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+# Increase window size to accommodate all elements
+root.geometry("1000x800")
+root.resizable(True, True)
+
+# Header
+header = tk.Label(root, text="GitHub Follower Checker", font=('Helvetica', 18, 'bold'), pady=10)
+header.pack()
+
+# Frame for input fields with columns
+input_frame = tk.Frame(root, padx=20, pady=10)
+input_frame.pack(fill=tk.X)
+
+# Left column for follower-related controls
+left_column = tk.Frame(input_frame)
+left_column.grid(row=0, column=0, padx=(0, 20), pady=10, sticky="n")
+
+# Right column for profile summary-related controls
+right_column = tk.Frame(input_frame)
+right_column.grid(row=0, column=1, pady=10, sticky="n")
+
+# Tabs for different outputs
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+# Tab for follower data
+follower_tab = ttk.Frame(notebook)
+notebook.add(follower_tab, text="Followers")
+
+# Tab for summary data
+summary_tab = ttk.Frame(notebook)
+notebook.add(summary_tab, text="Profile Summary")
+
+# Username input
+username_label = tk.Label(left_column, text="GitHub Username:")
+username_label.pack(anchor="w")
+username_entry = tk.Entry(left_column)
+username_entry.pack(anchor="w")
+
+# Token input
+token_label = tk.Label(left_column, text="GitHub Token:")
+token_label.pack(anchor="w")
+token_entry = tk.Entry(left_column, show="*")
+token_entry.pack(anchor="w")
+
+# Follower file name input
+followers_file_label = tk.Label(left_column, text="Followers File:")
+followers_file_label.pack(anchor="w")
+followers_file_entry = tk.Entry(left_column)
+followers_file_entry.pack(anchor="w")
+
+# Profile entry input (right column)
+profile_label = tk.Label(right_column, text="Enter GitHub Profile:")
+profile_label.pack(anchor="w")
+profile_entry = tk.Entry(right_column)
+profile_entry.pack(anchor="w")
+
+# Tracking button
+track_button = tk.Button(left_column, text="Track Followers", command=start_tracking)
+track_button.pack(anchor="w", pady=5)
+
+# Show analytics button
+show_analytics_button = tk.Button(left_column, text="Show Analytics", command=show_analytics, state=tk.DISABLED)
+show_analytics_button.pack(anchor="w", pady=5)
+
+# Create the segmentation type variable with a default read-only label "Please Select"
+segmentation_type_var = tk.StringVar(value="Please Select")
+
+# Label for Segmentation
+segmentation_label = tk.Label(left_column, text="Segment By:")
+segmentation_label.pack(anchor="w", pady=5)
+
+# Dropdown menu for Segmentation Types
+segmentation_menu = tk.OptionMenu(left_column, segmentation_type_var, "repo", "activity")
+segmentation_menu.pack(anchor="w", pady=5)
+
+# Segment followers button
+segment_followers_button = tk.Button(left_column, text="Segment Followers", command=segment_followers_ui, state=tk.DISABLED)
+segment_followers_button.pack(anchor="w", pady=5)
+
+# Profile summary button
+summary_button = tk.Button(right_column, text="Generate Summary", command=generate_summary_wrapper, state=tk.DISABLED)
+summary_button.pack(anchor="w", pady=5)
+
+# Follower display
+follower_text = scrolledtext.ScrolledText(follower_tab, height=20, state=tk.DISABLED, wrap=tk.WORD)
+follower_text.pack(fill=tk.BOTH, padx=20, pady=10, expand=True)
+
+# Summary display
+summary_text = scrolledtext.ScrolledText(summary_tab, height=20, state=tk.DISABLED, wrap=tk.WORD)
+summary_text.pack(fill=tk.BOTH, padx=20, pady=10, expand=True)
+
+# Switch to the "Followers" tab initially
+switch_tab(notebook, 0)
+
+# Menu Bar for Theme Selection
+menu_bar = Menu(root)
+root.config(menu=menu_bar)
+
+file_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="File", menu=file_menu)
+file_menu.add_command(label="Exit", command=root.quit)
+
+# Theme Menu
+theme_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="Settings", menu=theme_menu)
+
+theme_menu.add_command(label="Light Theme", command=lambda: set_theme("light"))
+theme_menu.add_command(label="Dark Theme", command=lambda: set_theme("dark"))
+theme_menu.add_command(label="Solarized Light Theme", command=lambda: set_theme("solarized_light"))
+theme_menu.add_command(label="Custom Theme", command=lambda: set_theme("custom"))
+
+root.mainloop()
\ No newline at end of file
diff --git a/archive/legacy-main-scripts/main12.py b/archive/legacy-main-scripts/main12.py
new file mode 100644
index 0000000..e74920c
--- /dev/null
+++ b/archive/legacy-main-scripts/main12.py
@@ -0,0 +1,455 @@
+# main.py
+# MIT License
+# Created Date: 2024-09-02
+# Created By: Jason Evans
+# Modified Date: 2024-10-18
+# Modified By: Jason Evans
+# Version 1.3.0
+
+import tkinter as tk
+from tkinter import ttk, scrolledtext, Menu, messagebox
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+import sys
+import logging
+from datetime import datetime
+import webbrowser
+from transformers import AutoModelForCausalLM, AutoTokenizer
+import torch
+
+# Set up logger for debugging and error tracking
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+handler = logging.StreamHandler(sys.stdout)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+handler.setFormatter(formatter)
+logger.addHandler(handler)
+
+# Load API key from .env file
+load_dotenv()
+
+# Function to check for the existence of the 'profile_summaries' table and creates it if it doesn't exist
+# Stores the generated summaries
+def create_summary_table(conn):
+ cursor = conn.cursor()
+ cursor.execute('''CREATE TABLE IF NOT EXISTS profile_summaries (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ profile_description TEXT,
+ repos_contributed_to TEXT,
+ summary TEXT,
+ date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )''')
+ conn.commit()
+
+# Helper function to get all users you are following
+def get_all_following(username, token):
+ following_url = f'https://api.github.com/users/{username}/following'
+ return get_all_followers(username, token, following_url) # Reuse get_all_followers for simplicity
+
+# Function to open PayPal donation link
+def open_donation_link():
+ donation_url = "https://www.paypal.com/donate/?hosted_button_id=AQCPKNSDGMJLL"
+ webbrowser.open(donation_url)
+
+# Function to track followers and who you follow that don't follow you back
+def track_followers(username, token, followers_file):
+ try:
+ # Step 1: Establish connection to database
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ # Step 2: Load previous follower data if exists
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ # Step 3: Get current followers from GitHub API
+ # Fetch current followers and following lists
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ following_list = get_all_following(username, token) # Fetch users you are following
+
+ # Step 4: Compute new followers, unfollowers, and followers who followed back
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ # Find users you are following who don't follow you back
+ not_following_back = list(set(following_list) - set(current_followers))
+
+ # Step 5: Capture current date and time
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ # Step 6: Insert current followers into database
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ # Step 7: Update output window (with timestamp)
+ # Display follower data in the text box
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ # Add the datetime stamp at the top
+ timestamp_output = f"Followers tracked on: {today}\n\n"
+ print(f"Inserting timestamp: {timestamp_output}") # Debugging: Print timestamp to console/log
+ follower_text.insert(tk.END, timestamp_output) # Insert timestamp at the top
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ # Add a section to display users not following you back
+ formatted_not_following_back, color_not_following_back = format_list("Not following you back", not_following_back, "purple")
+ follower_text.insert(tk.END, formatted_not_following_back, "not_following_back")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("not_following_back", foreground=color_not_following_back)
+ follower_text.tag_config("followers_back", foreground=color_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ # Step 8: Save current followers to the file
+ # Save updated data to file
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to start tracking in a separate thread
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL) # Enable button after tracking
+
+# Function to show analytics
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to segment followers
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to generate AI summary
+def generate_summary(username, token):
+ try:
+ # Initialize OpenAI API key
+ client = OpenAI(
+ api_key=os.environ['OPENAI_API_KEY']
+ )
+
+ # Define GitHub API URLs
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ # Fetch GitHub profile and repos data
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ # Check for successful API response
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ # Extract profile information and repos
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ # Create prompt for OpenAI API
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ # Make request to OpenAI chat completions
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {
+ "role": "user",
+ "content": "Write a summary from this user's GitHub profile."
+ }
+ ]
+ )
+
+ # Extract and return summary using object attributes
+ summary = completion.choices[0].message.content.strip()
+ return summary, profile_description, repos_contributed_to
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
+
+# Function to wrap AI generated summary
+def generate_summary_wrapper():
+ username = profile_entry.get().strip()
+ token = token_entry.get().strip()
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please enter username and token.")
+ return
+ summary, profile_description, repos_contributed_to = generate_summary(username, token)
+
+ if summary:
+
+ # Store the summary in the database
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_summary_table(conn) # Ensure the table is created
+ cursor = conn.cursor()
+
+ # Insert the summary into the database
+ cursor.execute('''INSERT INTO profile_summaries (username, profile_description, repos_contributed_to, summary)
+ VALUES (?, ?, ?, ?)''',
+ (username, profile_description, ", ".join(repos_contributed_to), summary))
+ conn.commit()
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+
+ # Display the summary in the UI
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Summary: {summary}", "summary")
+ summary_text.tag_config("summary", foreground="black")
+ summary_text.config(state=tk.DISABLED)
+
+ # Switch to the Profile Summary tab
+ # notebook.select(1) # Index 1 refers to the "Profile Summary" tab
+ switch_tab(notebook, 1) # Switch to "Profile Summary" tab after generating summary
+
+def switch_tab(notebook, index):
+ # Initialize selected_tab here
+ selected_tab = 0 # or any default value
+
+ notebook.select(index)
+ style.configure("TNotebook.Tab{}".format(index), background="blue", foreground="white")
+ style.configure("TNotebook.Tab{}".format(selected_tab), background="gray", foreground="black")
+ selected_tab = index
+
+def set_theme(theme):
+ if theme == "light":
+ root.configure(bg="white")
+ style.configure('TLabel', background="white", foreground="black")
+ follower_text.configure(bg="white", fg="black")
+ elif theme == "dark":
+ root.configure(bg="black")
+ style.configure('TLabel', background="black", foreground="white")
+ follower_text.configure(bg="black", fg="white")
+ elif theme == "solarized_light":
+ root.configure(bg="#FDF6E3")
+ style.configure('TLabel', background="#FDF6E3", foreground="#657B83")
+ follower_text.configure(bg="#FDF6E3", fg="#657B83")
+ elif theme == "custom":
+ root.configure(bg="#2E3440") # replace with your custom color
+ style.configure('TLabel', background="#2E3440", foreground="#2E3440") # replace with your custom color
+ follower_text.configure(bg="#2E3440", fg="#2E3440")
+ else:
+ root.configure(bg="default_color_bg")
+ style.configure('TLabel', background="default_color_bg", foreground="default_color_fg")
+ follower_text.configure(bg="default_color_bg", fg="default_color_fg")
+
+# GUI setup
+root = tk.Tk()
+root.title("GitHub Follower Checker")
+
+# Initialize selected tab
+selected_tab = 0
+
+# Configure notebook style
+style = ttk.Style()
+style.theme_use("default")
+style.configure("TNotebook.Tab", background="gray", foreground="black")
+
+# Add notebook to root
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+# Increase window size to accommodate all elements
+root.geometry("1000x800")
+root.resizable(True, True)
+
+# Header
+header = tk.Label(root, text="GitHub Follower Checker", font=('Helvetica', 18, 'bold'), pady=10)
+header.pack()
+
+# Frame for input fields with columns
+input_frame = tk.Frame(root, padx=20, pady=10)
+input_frame.pack(fill=tk.X)
+
+# Left column for follower-related controls
+left_column = tk.Frame(input_frame)
+left_column.grid(row=0, column=0, padx=(0, 20), pady=10, sticky="n")
+
+# Right column for profile summary-related controls
+right_column = tk.Frame(input_frame)
+right_column.grid(row=0, column=1, pady=10, sticky="n")
+
+# Tabs for different outputs
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+# Tab for follower data
+follower_tab = ttk.Frame(notebook)
+notebook.add(follower_tab, text="Followers")
+
+# Tab for summary data
+summary_tab = ttk.Frame(notebook)
+notebook.add(summary_tab, text="Profile Summary")
+
+# Username input
+username_label = tk.Label(left_column, text="GitHub Username:")
+username_label.pack(anchor="w")
+username_entry = tk.Entry(left_column)
+username_entry.pack(anchor="w")
+
+# Token input
+token_label = tk.Label(left_column, text="GitHub Token:")
+token_label.pack(anchor="w")
+token_entry = tk.Entry(left_column, show="*")
+token_entry.pack(anchor="w")
+
+# Follower file name input
+followers_file_label = tk.Label(left_column, text="Followers File:")
+followers_file_label.pack(anchor="w")
+followers_file_entry = tk.Entry(left_column)
+followers_file_entry.pack(anchor="w")
+
+# Profile entry input (right column)
+profile_label = tk.Label(right_column, text="Enter GitHub Profile:")
+profile_label.pack(anchor="w")
+profile_entry = tk.Entry(right_column)
+profile_entry.pack(anchor="w")
+
+# Tracking button
+track_button = tk.Button(left_column, text="Track Followers", command=start_tracking)
+track_button.pack(anchor="w", pady=5)
+
+# Show analytics button
+show_analytics_button = tk.Button(left_column, text="Show Analytics", command=show_analytics, state=tk.DISABLED)
+show_analytics_button.pack(anchor="w", pady=5)
+
+# Create the segmentation type variable with a default read-only label "Please Select"
+segmentation_type_var = tk.StringVar(value="Please Select")
+
+# Label for Segmentation
+segmentation_label = tk.Label(left_column, text="Segment By:")
+segmentation_label.pack(anchor="w", pady=5)
+
+# Dropdown menu for Segmentation Types
+segmentation_menu = tk.OptionMenu(left_column, segmentation_type_var, "repo", "activity")
+segmentation_menu.pack(anchor="w", pady=5)
+
+# Segment followers button
+segment_followers_button = tk.Button(left_column, text="Segment Followers", command=segment_followers_ui, state=tk.DISABLED)
+segment_followers_button.pack(anchor="w", pady=5)
+
+# Profile summary button
+summary_button = tk.Button(right_column, text="Generate Summary", command=generate_summary_wrapper, state=tk.DISABLED)
+summary_button.pack(anchor="w", pady=5)
+
+# Adding the "Donate Now" button
+donate_button = tk.Button(root, text="Donate Now", command=open_donation_link, bg="blue", fg="white", font=("Arial", 12, "bold"))
+donate_button.pack(pady=10) # Adjust padding as needed
+
+# Follower display
+follower_text = scrolledtext.ScrolledText(follower_tab, height=20, state=tk.DISABLED, wrap=tk.WORD)
+follower_text.pack(fill=tk.BOTH, padx=20, pady=10, expand=True)
+
+# Summary display
+summary_text = scrolledtext.ScrolledText(summary_tab, height=20, state=tk.DISABLED, wrap=tk.WORD)
+summary_text.pack(fill=tk.BOTH, padx=20, pady=10, expand=True)
+
+# Switch to the "Followers" tab initially
+switch_tab(notebook, 0)
+
+# Menu Bar for Theme Selection
+menu_bar = Menu(root)
+root.config(menu=menu_bar)
+
+file_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="File", menu=file_menu)
+file_menu.add_command(label="Exit", command=root.quit)
+
+# Theme Menu
+theme_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="Settings", menu=theme_menu)
+
+theme_menu.add_command(label="Light Theme", command=lambda: set_theme("light"))
+theme_menu.add_command(label="Dark Theme", command=lambda: set_theme("dark"))
+theme_menu.add_command(label="Solarized Light Theme", command=lambda: set_theme("solarized_light"))
+theme_menu.add_command(label="Custom Theme", command=lambda: set_theme("custom"))
+
+root.mainloop()
\ No newline at end of file
diff --git a/archive/legacy-main-scripts/main2.py b/archive/legacy-main-scripts/main2.py
new file mode 100644
index 0000000..fd02047
--- /dev/null
+++ b/archive/legacy-main-scripts/main2.py
@@ -0,0 +1,302 @@
+# main2.py
+# MIT License
+# Created Date: 2024-09-02
+# Version 1.1.3
+# Solar Theme
+
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+# Function to track followers
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to start tracking in a separate thread
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL) # Enable button after tracking
+
+# Function to show analytics
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to segment followers
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to generate AI summary
+def generate_summary(username, token):
+ try:
+ # Initialize OpenAI API key
+ client = OpenAI(
+ api_key=os.environ['OPENAI_API_KEY']
+ )
+
+ # Define GitHub API URLs
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ # Fetch GitHub profile and repos data
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ # Check for successful API response
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ # Extract profile information and repos
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ # Create prompt for OpenAI API
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ # Make request to OpenAI chat completions
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {
+ "role": "user",
+ "content": "Write a summary from this user's GitHub profile."
+ }
+ ]
+ )
+
+ # Extract and return summary using object attributes
+ summary = completion.choices[0].message.content.strip()
+ return summary
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
+
+# Function to wrap AI generated summary
+def generate_summary_wrapper():
+ username = profile_entry.get().strip()
+ token = token_entry.get().strip()
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please enter username and token.")
+ return
+ summary = generate_summary(username, token)
+ if summary:
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Summary: {summary}", "summary")
+ summary_text.tag_config("summary", foreground="black")
+ summary_text.config(state=tk.DISABLED)
+ # Switch to the Profile Summary tab
+ switch_tab(notebook, 1) # Switch to "Profile Summary" tab after generating summary
+
+def switch_tab(notebook, index):
+ selected_tab = 0 # Initialize selected_tab here
+ notebook.select(index)
+ style.configure("TNotebook.Tab{}".format(index), background="beige", foreground="blue")
+ style.configure("TNotebook.Tab{}".format(selected_tab), background="lightgray", foreground="black")
+ selected_tab = index
+
+# GUI setup
+root = tk.Tk()
+root.title("GitHub Follower Checker")
+
+# Initialize selected tab
+selected_tab = 0
+
+# Configure notebook style
+style = ttk.Style()
+style.theme_use("clam") # Solarized light theme's basis
+style.configure("TNotebook.Tab", background="lightgray", foreground="black")
+style.configure("TNotebook", background="beige", foreground="black", borderwidth=0)
+style.configure("TFrame", background="beige")
+style.configure("TLabel", background="beige", foreground="black")
+style.configure("TButton", background="lightblue", foreground="black", borderwidth=1)
+
+# Add notebook to root
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+# Increase window size to accommodate all elements
+root.geometry("1000x800")
+root.resizable(True, True)
+
+# Header
+header = tk.Label(root, text="GitHub Follower Checker", font=("Arial", 16), bg="beige")
+header.pack(pady=20)
+
+# Create tabs
+followers_tab = ttk.Frame(notebook)
+summary_tab = ttk.Frame(notebook)
+
+notebook.add(followers_tab, text="Followers")
+notebook.add(summary_tab, text="Profile Summary")
+
+# Followers Tab
+username_label = ttk.Label(followers_tab, text="GitHub Username:")
+username_label.grid(row=0, column=0, sticky=tk.W, padx=10, pady=5)
+
+username_entry = ttk.Entry(followers_tab, width=40)
+username_entry.grid(row=0, column=1, padx=10, pady=5)
+
+token_label = ttk.Label(followers_tab, text="GitHub Token:")
+token_label.grid(row=1, column=0, sticky=tk.W, padx=10, pady=5)
+
+token_entry = ttk.Entry(followers_tab, width=40, show='*')
+token_entry.grid(row=1, column=1, padx=10, pady=5)
+
+followers_file_label = ttk.Label(followers_tab, text="Followers File:")
+followers_file_label.grid(row=2, column=0, sticky=tk.W, padx=10, pady=5)
+
+followers_file_entry = ttk.Entry(followers_tab, width=40)
+followers_file_entry.grid(row=2, column=1, padx=10, pady=5)
+
+start_button = ttk.Button(followers_tab, text="Start Tracking", command=start_tracking)
+start_button.grid(row=3, column=0, columnspan=2, pady=10)
+
+show_analytics_button = ttk.Button(followers_tab, text="Show Analytics", command=show_analytics)
+show_analytics_button.grid(row=3, column=2, padx=10, pady=5)
+show_analytics_button.config(state=tk.DISABLED) # Disable until data is generated
+
+segment_followers_button = ttk.Button(followers_tab, text="Segment Followers", command=segment_followers_ui)
+segment_followers_button.grid(row=4, column=2, padx=10, pady=5)
+segment_followers_button.config(state=tk.DISABLED) # Disable until data is generated
+
+segmentation_type_var = tk.StringVar()
+segmentation_type_dropdown = ttk.Combobox(followers_tab, textvariable=segmentation_type_var, state='readonly')
+segmentation_type_dropdown['values'] = ('Please Select', 'Repository', 'Activity', 'Location', 'Company')
+segmentation_type_dropdown.current(0)
+segmentation_type_dropdown.grid(row=4, column=1, padx=10, pady=5)
+
+follower_text = scrolledtext.ScrolledText(followers_tab, wrap=tk.WORD, width=100, height=30, state=tk.DISABLED)
+follower_text.grid(row=5, column=0, columnspan=3, padx=10, pady=10)
+
+# Profile Summary Tab
+profile_label = ttk.Label(summary_tab, text="GitHub Username:")
+profile_label.grid(row=0, column=0, sticky=tk.W, padx=10, pady=5)
+
+profile_entry = ttk.Entry(summary_tab, width=40)
+profile_entry.grid(row=0, column=1, padx=10, pady=5)
+
+summary_button = ttk.Button(summary_tab, text="Generate Summary", command=generate_summary_wrapper)
+summary_button.grid(row=3, column=0, columnspan=2, pady=10)
+summary_button.config(state=tk.DISABLED) # Disable until tracking is run
+
+summary_text = scrolledtext.ScrolledText(summary_tab, wrap=tk.WORD, width=100, height=30, state=tk.DISABLED)
+summary_text.grid(row=4, column=0, columnspan=3, padx=10, pady=10)
+
+root.mainloop()
diff --git a/archive/legacy-main-scripts/main3.py b/archive/legacy-main-scripts/main3.py
new file mode 100644
index 0000000..fcc3348
--- /dev/null
+++ b/archive/legacy-main-scripts/main3.py
@@ -0,0 +1,315 @@
+# main3.py
+# MIT License
+# Created Date: 2024-09-02
+# Version 1.1.4
+
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+# Function to track followers
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to start tracking in a separate thread
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL) # Enable button after tracking
+
+# Function to show analytics
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to segment followers
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to generate AI summary
+def generate_summary(username, token):
+ try:
+ # Initialize OpenAI API key
+ client = OpenAI(
+ api_key=os.environ['OPENAI_API_KEY']
+ )
+
+ # Define GitHub API URLs
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ # Fetch GitHub profile and repos data
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ # Check for successful API response
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ # Extract profile information and repos
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ # Create prompt for OpenAI API
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ # Make request to OpenAI chat completions
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {
+ "role": "user",
+ "content": "Write a summary from this user's GitHub profile."
+ }
+ ]
+ )
+
+ # Extract and return summary using object attributes
+ summary = completion.choices[0].message.content.strip()
+ return summary
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
+
+# Function to wrap AI generated summary
+def generate_summary_wrapper():
+ username = profile_entry.get().strip()
+ token = token_entry.get().strip()
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please enter username and token.")
+ return
+ summary = generate_summary(username, token)
+ if summary:
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Summary: {summary}", "summary")
+ summary_text.tag_config("summary", foreground="black")
+ summary_text.config(state=tk.DISABLED)
+ # Switch to the Profile Summary tab
+ switch_tab(notebook, 1) # Switch to "Profile Summary" tab after generating summary
+
+def switch_tab(notebook, index):
+ # Initialize selected_tab here
+ selected_tab = 0 # or any default value
+
+ notebook.select(index)
+ style.configure("TNotebook.Tab{}".format(index), background="blue", foreground="white")
+ style.configure("TNotebook.Tab{}".format(selected_tab), background="gray", foreground="black")
+ selected_tab = index
+
+# GUI setup
+root = tk.Tk()
+root.title("GitHub Follower Checker")
+
+# Initialize selected tab
+selected_tab = 0
+
+# Configure notebook style
+style = ttk.Style()
+style.theme_use("clam") # Apply the new theme
+style.configure("TNotebook.Tab", background="gray", foreground="black")
+
+# Add notebook to root
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+# Increase window size to accommodate all elements
+root.geometry("1000x800")
+root.resizable(True, True)
+
+# Header
+header = tk.Label(root, text="GitHub Follower Checker", font=('Helvetica', 18, 'bold'), pady=10)
+header.pack()
+
+# Frame for input fields with columns
+input_frame = tk.Frame(root, padx=20, pady=10)
+input_frame.pack(fill=tk.X)
+
+# Left column for follower-related controls
+left_column = tk.Frame(input_frame)
+left_column.grid(row=0, column=0, padx=(0, 20), pady=10, sticky="n")
+
+# Right column for profile summary-related controls
+right_column = tk.Frame(input_frame)
+right_column.grid(row=0, column=1, pady=10, sticky="n")
+
+# Tabs for different outputs (Followers and Profile Summary)
+tab_followers = ttk.Frame(notebook)
+tab_summary = ttk.Frame(notebook)
+
+# Adding tabs to the notebook
+notebook.add(tab_followers, text='Followers')
+notebook.add(tab_summary, text='Profile Summary')
+
+# Widgets for left column (Followers tracking)
+username_label = tk.Label(left_column, text="GitHub Username:")
+username_label.pack(anchor=tk.W)
+username_entry = tk.Entry(left_column, width=30)
+username_entry.pack(anchor=tk.W)
+
+token_label = tk.Label(left_column, text="GitHub Token:")
+token_label.pack(anchor=tk.W)
+token_entry = tk.Entry(left_column, width=30, show='*')
+token_entry.pack(anchor=tk.W)
+
+followers_file_label = tk.Label(left_column, text="Followers File:")
+followers_file_label.pack(anchor=tk.W)
+followers_file_entry = tk.Entry(left_column, width=30)
+followers_file_entry.pack(anchor=tk.W)
+
+track_button = tk.Button(left_column, text="Track Followers", command=start_tracking)
+track_button.pack(anchor=tk.W, pady=5)
+
+show_analytics_button = tk.Button(left_column, text="Show Analytics", command=show_analytics)
+show_analytics_button.pack(anchor=tk.W, pady=5)
+show_analytics_button.config(state=tk.DISABLED) # Disable button initially
+
+# Segmentation options for followers
+segmentation_type_label = tk.Label(left_column, text="Segmentation Type:")
+segmentation_type_label.pack(anchor=tk.W)
+
+segmentation_type_var = tk.StringVar()
+segmentation_type_var.set("Please Select") # Default value
+segmentation_type_menu = ttk.Combobox(left_column, textvariable=segmentation_type_var, state="readonly", values=["Please Select", "Repo", "Activity"])
+segmentation_type_menu.pack(anchor=tk.W)
+
+segment_followers_button = tk.Button(left_column, text="Segment Followers", command=segment_followers_ui)
+segment_followers_button.pack(anchor=tk.W, pady=5)
+segment_followers_button.config(state=tk.DISABLED) # Disable button initially
+
+# Scrolled text widget for displaying segmented followers
+follower_text = scrolledtext.ScrolledText(tab_followers, width=80, height=20, wrap=tk.WORD)
+follower_text.pack(fill=tk.BOTH, expand=True)
+follower_text.config(state=tk.DISABLED)
+
+# Widgets for right column (Profile summary)
+profile_label = tk.Label(right_column, text="GitHub Username:")
+profile_label.pack(anchor=tk.W)
+profile_entry = tk.Entry(right_column, width=30)
+profile_entry.pack(anchor=tk.W)
+
+summary_button = tk.Button(right_column, text="Generate Summary", command=generate_summary_wrapper)
+summary_button.pack(anchor=tk.W, pady=5)
+summary_button.config(state=tk.DISABLED) # Disable button initially
+
+summary_text = scrolledtext.ScrolledText(tab_summary, width=80, height=20, wrap=tk.WORD)
+summary_text.pack(fill=tk.BOTH, expand=True)
+summary_text.config(state=tk.DISABLED)
+
+# Start the main loop
+root.mainloop()
diff --git a/archive/legacy-main-scripts/main4.py b/archive/legacy-main-scripts/main4.py
new file mode 100644
index 0000000..070975d
--- /dev/null
+++ b/archive/legacy-main-scripts/main4.py
@@ -0,0 +1,322 @@
+# main4.py
+# MIT License
+# Created Date: 2024-09-02
+# Version 1.1.5
+
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+# Function to track followers
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to start tracking in a separate thread
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL) # Enable button after tracking
+
+# Function to show analytics
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to segment followers
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to generate AI summary
+def generate_summary(username, token):
+ try:
+ # Initialize OpenAI API key
+ client = OpenAI(
+ api_key=os.environ['OPENAI_API_KEY']
+ )
+
+ # Define GitHub API URLs
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ # Fetch GitHub profile and repos data
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ # Check for successful API response
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ # Extract profile information and repos
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ # Create prompt for OpenAI API
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ # Make request to OpenAI chat completions
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {
+ "role": "user",
+ "content": "Write a summary from this user's GitHub profile."
+ }
+ ]
+ )
+
+ # Extract and return summary using object attributes
+ summary = completion.choices[0].message.content.strip()
+ return summary
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
+
+# Function to wrap AI generated summary
+def generate_summary_wrapper():
+ username = profile_entry.get().strip()
+ token = token_entry.get().strip()
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please enter username and token.")
+ return
+ summary = generate_summary(username, token)
+ if summary:
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Summary: {summary}", "summary")
+ summary_text.tag_config("summary", foreground="black")
+ summary_text.config(state=tk.DISABLED)
+ # Switch to the Profile Summary tab
+ # notebook.select(1) # Index 1 refers to the "Profile Summary" tab
+ switch_tab(notebook, 1) # Switch to "Profile Summary" tab after generating summary
+
+def switch_tab(notebook, index):
+ notebook.select(index)
+ style.configure("TNotebook.Tab", background="gray", foreground="black")
+
+# GUI setup
+root = tk.Tk()
+root.title("GitHub Follower Checker")
+
+# Initialize selected tab
+selected_tab = 0
+
+# Configure notebook style
+style = ttk.Style()
+style.theme_use("clam")
+style.configure("TNotebook.Tab", background="gray", foreground="black")
+style.configure("TNotebook", tabposition='wn') # Move tabs to the bottom
+style.configure("TFrame", background="#F5F5F5")
+style.configure("TLabel", background="#F5F5F5", font=('Helvetica', 12))
+style.configure("TButton", background="#E7E7E7", font=('Helvetica', 10))
+style.configure("TEntry", font=('Helvetica', 10))
+
+# Add notebook to root
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+# Increase window size to accommodate all elements
+root.geometry("1000x800")
+root.resizable(True, True)
+
+# Header
+header = tk.Label(root, text="GitHub Follower Checker", font=('Helvetica', 18, 'bold'), pady=10)
+header.pack()
+
+# Frame for input fields with columns
+input_frame = tk.Frame(root, padx=20, pady=10)
+input_frame.pack(fill=tk.X)
+
+# Left column for follower-related controls
+left_column = tk.Frame(input_frame)
+left_column.grid(row=0, column=0, padx=(0, 20), pady=10, sticky="n")
+
+# Right column for profile summary-related controls
+right_column = tk.Frame(input_frame)
+right_column.grid(row=0, column=1, padx=(20, 0), pady=10, sticky="n")
+
+# Username field
+username_label = tk.Label(left_column, text="GitHub Username:")
+username_label.grid(row=0, column=0, sticky="w")
+username_entry = tk.Entry(left_column, width=30)
+username_entry.grid(row=0, column=1, padx=(10, 0))
+
+# Token field
+token_label = tk.Label(left_column, text="GitHub Token:")
+token_label.grid(row=1, column=0, sticky="w", pady=(10, 0))
+token_entry = tk.Entry(left_column, width=30, show="*")
+token_entry.grid(row=1, column=1, padx=(10, 0), pady=(10, 0))
+
+# Followers file field
+followers_file_label = tk.Label(left_column, text="Followers File:")
+followers_file_label.grid(row=2, column=0, sticky="w", pady=(10, 0))
+followers_file_entry = tk.Entry(left_column, width=30)
+followers_file_entry.grid(row=2, column=1, padx=(10, 0), pady=(10, 0))
+
+# Track followers button
+track_button = tk.Button(left_column, text="Track Followers", command=start_tracking)
+track_button.grid(row=3, columnspan=2, pady=(20, 0))
+
+# Profile entry field
+profile_label = tk.Label(right_column, text="GitHub Username for Summary:")
+profile_label.grid(row=0, column=0, sticky="w")
+profile_entry = tk.Entry(right_column, width=30)
+profile_entry.grid(row=0, column=1, padx=(10, 0))
+
+# Generate summary button
+summary_button = tk.Button(right_column, text="Generate Summary", command=generate_summary_wrapper, state=tk.DISABLED)
+summary_button.grid(row=1, columnspan=2, pady=(20, 0))
+
+# Frame for tabs and output windows
+output_frame = tk.Frame(root, padx=20, pady=10)
+output_frame.pack(expand=True, fill='both')
+
+# Tabs for follower data and profile summary
+followers_tab = ttk.Frame(notebook)
+summary_tab = ttk.Frame(notebook)
+notebook.add(followers_tab, text="Followers")
+notebook.add(summary_tab, text="Profile Summary")
+
+# Follower data display
+follower_text = scrolledtext.ScrolledText(followers_tab, wrap=tk.WORD, height=30)
+follower_text.pack(expand=True, fill='both')
+follower_text.config(state=tk.DISABLED)
+
+# Summary display
+summary_text = scrolledtext.ScrolledText(summary_tab, wrap=tk.WORD, height=30)
+summary_text.pack(expand=True, fill='both')
+summary_text.config(state=tk.DISABLED)
+
+# Segment followers button
+segment_followers_button = tk.Button(followers_tab, text="Segment Followers", command=segment_followers_ui, state=tk.DISABLED)
+segment_followers_button.pack(pady=(20, 10))
+
+# Segmentation type dropdown menu
+segmentation_type_var = tk.StringVar()
+segmentation_type_label = tk.Label(followers_tab, text="Segment followers by:")
+segmentation_type_label.pack()
+segmentation_type_dropdown = ttk.Combobox(followers_tab, textvariable=segmentation_type_var, state="readonly", width=30)
+segmentation_type_dropdown['values'] = ["Please Select", "Repo", "Activity"]
+segmentation_type_dropdown.current(0)
+segmentation_type_dropdown.pack(pady=(0, 10))
+
+# Show analytics button
+show_analytics_button = tk.Button(followers_tab, text="Show Analytics", command=show_analytics, state=tk.DISABLED)
+show_analytics_button.pack(pady=(0, 10))
+
+# Main loop
+root.mainloop()
\ No newline at end of file
diff --git a/archive/legacy-main-scripts/main5.py b/archive/legacy-main-scripts/main5.py
new file mode 100644
index 0000000..99a9e29
--- /dev/null
+++ b/archive/legacy-main-scripts/main5.py
@@ -0,0 +1,384 @@
+# main.py
+# MIT License
+# Created Date: 2024-09-02
+# Created By: Jason Evans
+# Version 1.1.1.1
+
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk, Menu
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+# Function to check for the existence of the 'profile_summaries' table and creates it if it doesn't exist
+# Stores the generated summaries
+def create_summary_table(conn):
+ cursor = conn.cursor()
+ cursor.execute('''CREATE TABLE IF NOT EXISTS profile_summaries (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ profile_description TEXT,
+ repos_contributed_to TEXT,
+ summary TEXT,
+ date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )''')
+ conn.commit()
+
+# Function to track followers
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to start tracking in a separate thread
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL) # Enable button after tracking
+
+# Function to show analytics
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to segment followers
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to generate AI summary
+def generate_summary(username, token):
+ try:
+ # Initialize OpenAI API key
+ client = OpenAI(
+ api_key=os.environ['OPENAI_API_KEY']
+ )
+
+ # Define GitHub API URLs
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ # Fetch GitHub profile and repos data
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ # Check for successful API response
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ # Extract profile information and repos
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ # Create prompt for OpenAI API
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ # Make request to OpenAI chat completions
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {
+ "role": "user",
+ "content": "Write a summary from this user's GitHub profile."
+ }
+ ]
+ )
+
+ # Extract and return summary using object attributes
+ summary = completion.choices[0].message.content.strip()
+ return summary, profile_description, repos_contributed_to
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
+
+# Function to wrap AI generated summary
+def generate_summary_wrapper():
+ username = profile_entry.get().strip()
+ token = token_entry.get().strip()
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please enter username and token.")
+ return
+ summary, profile_description, repos_contributed_to = generate_summary(username, token)
+
+ if summary:
+
+ # Store the summary in the database
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_summary_table(conn) # Ensure the table is created
+ cursor = conn.cursor()
+
+ # Insert the summary into the database
+ cursor.execute('''INSERT INTO profile_summaries (username, profile_description, repos_contributed_to, summary)
+ VALUES (?, ?, ?, ?)''',
+ (username, profile_description, ", ".join(repos_contributed_to), summary))
+ conn.commit()
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+
+ # Display the summary in the UI
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Summary: {summary}", "summary")
+ summary_text.tag_config("summary", foreground="black")
+ summary_text.config(state=tk.DISABLED)
+
+ # Switch to the Profile Summary tab
+ switch_tab(notebook, 1) # Switch to "Profile Summary" tab after generating summary
+
+def switch_tab(notebook, index):
+ global selected_tab
+ notebook.select(index)
+ style.configure("TNotebook.Tab{}".format(index), background="blue", foreground="white")
+ style.configure("TNotebook.Tab{}".format(selected_tab), background="gray", foreground="black")
+ selected_tab = index
+
+# Define themes as dictionaries
+themes = {
+ "Default": {
+ "background": "SystemButtonFace",
+ "foreground": "black",
+ "button_background": "SystemButtonFace",
+ "button_foreground": "black",
+ },
+ "Solarized Light": {
+ "background": "#fdf6e3",
+ "foreground": "#657b83",
+ "button_background": "#eee8d5",
+ "button_foreground": "#657b83",
+ },
+ "Solarized Dark": {
+ "background": "#002b36",
+ "foreground": "#839496",
+ "button_background": "#073642",
+ "button_foreground": "#839496",
+ },
+ "High Contrast": {
+ "background": "black",
+ "foreground": "white",
+ "button_background": "black",
+ "button_foreground": "white",
+ }
+}
+
+def apply_theme(theme_name):
+ theme = themes.get(theme_name, themes["Default"])
+
+ root.config(bg=theme["background"])
+ for widget in root.winfo_children():
+ try:
+ widget.config(bg=theme["background"], fg=theme["foreground"])
+ except:
+ pass
+
+ for btn in [start_button, show_analytics_button, segment_followers_button, summary_button]:
+ # btn.config(bg=theme["button_background"], fg=theme["button_foreground"])
+ btn["style"] = "TButton"
+
+def select_theme():
+ theme_name = theme_var.get()
+ apply_theme(theme_name)
+
+root = tk.Tk()
+root.title("GitHub Follower Tracker")
+style = ttk.Style()
+
+# Add menu for theme selection
+menu_bar = Menu(root)
+root.config(menu=menu_bar)
+
+file_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="File", menu=file_menu)
+file_menu.add_command(label="Exit", command=root.quit)
+
+settings_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="Settings", menu=settings_menu)
+
+theme_var = tk.StringVar(value="Default")
+theme_menu = Menu(settings_menu, tearoff=0)
+settings_menu.add_cascade(label="Theme", menu=theme_menu)
+for theme_name in themes:
+ theme_menu.add_radiobutton(label=theme_name, variable=theme_var, command=select_theme)
+
+# Adding a Notebook widget for tabbed interface
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+follower_tab = ttk.Frame(notebook)
+summary_tab = ttk.Frame(notebook)
+notebook.add(follower_tab, text="Followers")
+notebook.add(summary_tab, text="Profile Summary")
+
+selected_tab = 0
+
+# Label and entry for GitHub username
+username_label = ttk.Label(follower_tab, text="GitHub Username:")
+username_label.pack(pady=5)
+username_entry = ttk.Entry(follower_tab, width=30)
+username_entry.pack(pady=5)
+
+# Label and entry for GitHub token
+token_label = ttk.Label(follower_tab, text="GitHub Token:")
+token_label.pack(pady=5)
+token_entry = ttk.Entry(follower_tab, show='*', width=30)
+token_entry.pack(pady=5)
+
+# Label and entry for follower data file
+followers_file_label = ttk.Label(follower_tab, text="Followers File:")
+followers_file_label.pack(pady=5)
+followers_file_entry = ttk.Entry(follower_tab, width=30)
+followers_file_entry.pack(pady=5)
+
+# Button to start tracking followers
+start_button = ttk.Button(follower_tab, text="Start Tracking", command=start_tracking)
+start_button.pack(pady=10)
+
+# Button to show analytics
+show_analytics_button = ttk.Button(follower_tab, text="Show Analytics", command=show_analytics, state=tk.DISABLED)
+show_analytics_button.pack(pady=10)
+
+# Dropdown for segmentation type
+segmentation_type_label = ttk.Label(follower_tab, text="Segmentation Type:")
+segmentation_type_label.pack(pady=5)
+segmentation_type_var = tk.StringVar()
+segmentation_type_dropdown = ttk.Combobox(follower_tab, textvariable=segmentation_type_var, state="readonly")
+segmentation_type_dropdown['values'] = ["Please Select", "Repo", "Activity"]
+segmentation_type_dropdown.current(0)
+segmentation_type_dropdown.pack(pady=5)
+
+# Button to segment followers
+segment_followers_button = ttk.Button(follower_tab, text="Segment Followers", command=segment_followers_ui, state=tk.DISABLED)
+segment_followers_button.pack(pady=10)
+
+# ScrolledText widget to display follower information
+follower_text = scrolledtext.ScrolledText(follower_tab, width=70, height=20, state=tk.DISABLED)
+follower_text.pack(pady=10)
+
+# Label and entry for Profile Summary tab
+profile_label = ttk.Label(summary_tab, text="GitHub Username:")
+profile_label.pack(pady=5)
+profile_entry = ttk.Entry(summary_tab, width=30)
+profile_entry.pack(pady=5)
+
+# Button to generate summary
+summary_button = ttk.Button(summary_tab, text="Generate Summary", command=generate_summary_wrapper, state=tk.DISABLED)
+summary_button.pack(pady=10)
+
+# ScrolledText widget to display profile summary
+summary_text = scrolledtext.ScrolledText(summary_tab, width=70, height=20, state=tk.DISABLED)
+summary_text.pack(pady=10)
+
+apply_theme("Default") # Apply default theme on startup
+
+root.mainloop()
diff --git a/archive/legacy-main-scripts/main6.py b/archive/legacy-main-scripts/main6.py
new file mode 100644
index 0000000..3f0266f
--- /dev/null
+++ b/archive/legacy-main-scripts/main6.py
@@ -0,0 +1,499 @@
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk, Menu
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+# Function to check for the existence of the 'profile_summaries' table and create it if it doesn't exist
+# Stores the generated summaries
+def create_summary_table(conn):
+ cursor = conn.cursor()
+ cursor.execute('''CREATE TABLE IF NOT EXISTS profile_summaries (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ profile_description TEXT,
+ repos_contributed_to TEXT,
+ summary TEXT,
+ date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )''')
+ conn.commit()
+
+# Function to track followers
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL) # Enable summary button after tracking
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to start tracking in a separate thread
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL) # Enable summary button after tracking
+
+# Function to show analytics
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ finally:
+ switch_tab(notebook, 0) # Switch to "Followers" tab after showing analytics
+
+# Function to segment followers
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ finally:
+ switch_tab(notebook, 0) # Switch to "Followers" tab after segmenting
+
+# Function to generate AI summary
+def generate_summary(username, token):
+ try:
+ # Initialize OpenAI API key
+ client = OpenAI(
+ api_key=os.environ['OPENAI_API_KEY']
+ )
+
+ # Define GitHub API URLs
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ # Fetch GitHub profile and repos data
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ # Check for successful API response
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ # Extract profile information and repos
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ # Create prompt for OpenAI API
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ # Make request to OpenAI chat completions
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {
+ "role": "user",
+ "content": "Write a summary from this user's GitHub profile."
+ }
+ ]
+ )
+
+ # Extract and return summary using object attributes
+ summary = completion.choices[0].message.content.strip()
+ return summary, profile_description, repos_contributed_to
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
+
+# Function to wrap AI generated summary
+def generate_summary_wrapper():
+ username = profile_entry.get().strip()
+ token = token_entry.get().strip()
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please enter username and token.")
+ return
+ summary, profile_description, repos_contributed_to = generate_summary(username, token)
+
+ if summary:
+
+ # Store the summary in the database
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_summary_table(conn) # Ensure the table is created
+ cursor = conn.cursor()
+
+ # Insert the summary into the database
+ cursor.execute('''INSERT INTO profile_summaries (username, profile_description, repos_contributed_to, summary)
+ VALUES (?, ?, ?, ?)''',
+ (username, profile_description, ", ".join(repos_contributed_to), summary))
+ conn.commit()
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+
+ # Display the summary in the UI
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Summary: {summary}", "summary")
+ summary_text.tag_config("summary", foreground="black")
+ summary_text.config(state=tk.DISABLED)
+
+ # Switch to the Profile Summary tab
+ switch_tab(notebook, 1) # Switch to "Profile Summary" tab after generating summary
+
+def switch_tab(notebook, index):
+ global selected_tab
+ notebook.select(index)
+ style.configure("TNotebook.Tab{}".format(index), background="blue", foreground="white")
+ style.configure("TNotebook.Tab{}".format(selected_tab), background="gray", foreground="black")
+ selected_tab = index
+
+# # Define themes as dictionaries
+# themes = {
+# "Default": {
+# "background": "SystemButtonFace",
+# "foreground": "black",
+# "button_background": "SystemButtonFace",
+# "button_foreground": "black",
+# },
+# "Solarized Light": {
+# "background": "#fdf6e3",
+# "foreground": "#657b83",
+# "button_background": "#eee8d5",
+# "button_foreground": "#657b83",
+# },
+# "Solarized Dark": {
+# "background": "#002b36",
+# "foreground": "#839496",
+# "button_background": "#073642",
+# "button_foreground": "#839496",
+# },
+# "High Contrast": {
+# "background": "black",
+# "foreground": "white",
+# "button_background": "black",
+# "button_foreground": "white",
+# }
+# }
+
+# def apply_theme(theme_name):
+# theme = themes.get(theme_name, themes["Default"])
+
+# root.config(bg=theme["background"])
+# for widget in root.winfo_children():
+# try:
+# widget.config(bg=theme["background"], fg=theme["foreground"])
+# except:
+# pass
+
+# for btn in [start_button, show_analytics_button, segment_followers_button, summary_button]:
+# # btn.config(bg=theme["button_background"], fg=theme["button_foreground"])
+# btn["style"] = "TButton"
+
+# def select_theme():
+# theme_name = theme_var.get()
+# apply_theme(theme_name)
+
+root = tk.Tk()
+root.title("GitHub Follower Tracker")
+style = ttk.Style()
+
+# Add menu for theme selection
+menu_bar = Menu(root)
+root.config(menu=menu_bar)
+
+file_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="File", menu=file_menu)
+file_menu.add_command(label="Exit", command=root.quit)
+
+settings_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="Settings", menu=settings_menu)
+
+# Add menu for theme selection
+menu_bar = Menu(root)
+root.config(menu=menu_bar)
+
+file_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="File", menu=file_menu)
+file_menu.add_command(label="Exit", command=root.quit)
+
+settings_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="Settings", menu=settings_menu)
+
+# Add theme selection options to Settings menu
+theme_var = tk.StringVar(root)
+theme_var.set("Default") # Set default theme
+
+theme_options = [
+ ("Default", "Default"),
+ ("Solarized Light", "Solarized Light"),
+ ("Solarized Dark", "Solarized Dark"),
+ ("High Contrast", "High Contrast"),
+]
+
+theme_submenu = Menu(settings_menu, tearoff=0)
+
+for theme_name, theme_display in theme_options:
+ theme_submenu.add_radiobutton(
+ label=theme_display, variable=theme_var, command=lambda t=theme_name: select_theme(t)
+ )
+
+settings_menu.add_cascade(label="Theme", menu=theme_submenu)
+
+# Define themes as dictionaries
+themes = {
+ "Default": {
+ "background": "SystemButtonFace",
+ "foreground": "black",
+ "button_background": "SystemButtonFace",
+ "button_foreground": "black",
+ },
+ "Solarized Light": {
+ "background": "#fdf6e3",
+ "foreground": "#657b83",
+ "button_background": "#eee8d5",
+ "button_foreground": "#657b83",
+ },
+ "Solarized Dark": {
+ "background": "#002b36",
+ "foreground": "#839496",
+ "button_background": "#073642",
+ "button_foreground": "#839496",
+ },
+ "High Contrast": {
+ "background": "black",
+ "foreground": "white",
+ "button_background": "black",
+ "button_foreground": "white",
+ }
+}
+
+def apply_theme(theme_name):
+ theme = themes.get(theme_name, themes["Default"])
+
+ # Set background and foreground colors for all widgets
+ root.config(bg=theme["background"])
+ for widget in root.winfo_children():
+ try:
+ widget.config(bg=theme["background"], fg=theme["foreground"])
+ except:
+ pass
+
+ # Set button styles using theme colors
+ style = ttk.Style(root)
+ for btn_name in ["start_button", "show_analytics_button", "segment_followers_button", "summary_button"]:
+ style.configure(btn_name, background=theme["button_background"], foreground=theme["button_foreground"])
+
+# Apply default theme on startup
+apply_theme("Default")
+
+# Function to apply chosen theme
+def select_theme():
+ theme_name = theme_var.get()
+ apply_theme(theme_name)
+
+theme_submenu.add_radiobutton(
+ label=theme_display, variable=theme_var, command=select_theme
+)
+
+# Create the main window
+root = tk.Tk()
+root.title("GitHub Follower Tracker")
+
+# Add menu for theme selection
+menu_bar = Menu(root)
+root.config(menu=menu_bar)
+
+file_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="File", menu=file_menu)
+file_menu.add_command(label="Exit",
+ command=root.quit)
+
+settings_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="Settings", menu=settings_menu)
+
+theme_var = tk.StringVar()
+theme_var.set("Default") # Set default theme
+
+theme_options = [
+ ("Default", "Default"),
+ ("Solarized Light", "Solarized Light"),
+ ("Solarized Dark", "Solarized Dark"),
+ ("High Contrast", "High Contrast"),
+]
+
+theme_submenu = Menu(settings_menu, tearoff=0)
+
+for theme_name, theme_display in theme_options:
+ theme_submenu.add_radiobutton(
+ label=theme_display, variable=theme_var, command=lambda t=theme_name: select_theme(t)
+ )
+
+settings_menu.add_cascade(label="Theme", menu=theme_submenu)
+
+# Adding a Notebook widget for tabbed interface
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill='both')
+
+follower_tab = ttk.Frame(notebook)
+summary_tab = ttk.Frame(notebook)
+notebook.add(follower_tab, text="Followers")
+notebook.add(summary_tab, text="Profile Summary")
+
+selected_tab = 0
+
+# Label and entry for GitHub username
+username_label = ttk.Label(follower_tab, text="GitHub Username:")
+username_label.pack(pady=5)
+username_entry = ttk.Entry(follower_tab, width=30)
+username_entry.pack(pady=5)
+
+# Label and entry for GitHub token
+token_label = ttk.Label(follower_tab, text="GitHub Token:")
+token_label.pack(pady=5)
+token_entry = ttk.Entry(follower_tab, show='*', width=30)
+token_entry.pack(pady=5)
+
+# Label and entry for follower data file
+followers_file_label = ttk.Label(follower_tab, text="Followers File:")
+followers_file_label.pack(pady=5)
+followers_file_entry = ttk.Entry(follower_tab, width=30)
+followers_file_entry.pack(pady=5)
+
+# Button to start tracking followers
+start_button = ttk.Button(follower_tab, text="Start Tracking", command=start_tracking)
+start_button.pack(pady=10)
+
+# Button to show analytics
+show_analytics_button = ttk.Button(follower_tab, text="Show Analytics", command=show_analytics, state=tk.DISABLED)
+show_analytics_button.pack(pady=10)
+
+# Dropdown for segmentation type
+segmentation_type_label = ttk.Label(follower_tab, text="Segmentation Type:")
+segmentation_type_label.pack(pady=5)
+segmentation_type_var = tk.StringVar()
+segmentation_type_dropdown = ttk.Combobox(follower_tab, textvariable=segmentation_type_var, state="readonly")
+segmentation_type_dropdown['values'] = ["Please Select", "Repo", "Activity"]
+segmentation_type_dropdown.current(0)
+segmentation_type_dropdown.pack(pady=5)
+
+# Button to segment followers
+segment_followers_button = ttk.Button(follower_tab, text="Segment Followers", command=segment_followers_ui, state=tk.DISABLED)
+segment_followers_button.pack(pady=10)
+
+# ScrolledText widget to display follower information
+follower_text = scrolledtext.ScrolledText(follower_tab, width=70, height=20, state=tk.DISABLED)
+follower_text.pack(pady=10)
+
+# Label and entry for Profile Summary tab
+profile_label = ttk.Label(summary_tab, text="GitHub Username:")
+profile_label.pack(pady=5)
+profile_entry = ttk.Entry(summary_tab, width=30)
+profile_entry.pack(pady=5)
+
+# Button to generate summary
+summary_button = ttk.Button(summary_tab, text="Generate Summary", command=generate_summary_wrapper, state=tk.DISABLED)
+summary_button.pack(pady=10)
+
+# ScrolledText widget to display profile summary
+summary_text = scrolledtext.ScrolledText(summary_tab, width=70, height=20, state=tk.DISABLED)
+summary_text.pack(pady=10)
+
+# Function calls theme after all widgets are created
+def apply_theme_after_init():
+ apply_theme("Default")
+
+# Start the main loop
+root.mainloop()
\ No newline at end of file
diff --git a/archive/legacy-main-scripts/main7.py b/archive/legacy-main-scripts/main7.py
new file mode 100644
index 0000000..2bc2a26
--- /dev/null
+++ b/archive/legacy-main-scripts/main7.py
@@ -0,0 +1,152 @@
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk, Menu
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+# Function to check for the existence of the 'profile_summaries' table and create it if it doesn't exist
+def create_summary_table(conn):
+ cursor = conn.cursor()
+ cursor.execute('''CREATE TABLE IF NOT EXISTS profile_summaries (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ profile_description TEXT,
+ repos_contributed_to TEXT,
+ summary TEXT,
+ date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )''')
+ conn.commit()
+
+# Function to track followers
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ current_followers = get_all_followers(username, token, followers_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(previous_followers) & set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who followed back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL) # Enable summary button after tracking
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+# Function to start tracking in a separate thread
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL) # Enable summary button after tracking
+
+# Function to show analytics
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ finally:
+ switch_tab(notebook, 0) # Switch to "Followers" tab after showing analytics
+
+# Function to segment followers
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ finally:
+ switch_tab(notebook, 0) # Switch to "Followers" tab after segmenting
+
+# Function to generate AI summary
+def generate_summary(username, token):
+ try:
+ return None
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
diff --git a/archive/legacy-main-scripts/main8.py b/archive/legacy-main-scripts/main8.py
new file mode 100644
index 0000000..0d293b8
--- /dev/null
+++ b/archive/legacy-main-scripts/main8.py
@@ -0,0 +1,365 @@
+# main.py
+# MIT License
+# Created Date: 2024-09-02
+# Created By: Jason Evans
+# Version 1.1.1.2
+
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk, Menu
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+def create_summary_table(conn):
+ cursor = conn.cursor()
+ cursor.execute('''CREATE TABLE IF NOT EXISTS profile_summaries (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ profile_description TEXT,
+ repos_contributed_to TEXT,
+ summary TEXT,
+ date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )''')
+ conn.commit()
+
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ following_url = f'https://api.github.com/users/{username}/following'
+ current_followers = get_all_followers(username, token, followers_url)
+ current_followings = get_all_followers(username, token, following_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(current_followers) & set(current_followings))
+ not_following_back = list(set(current_followings) - set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who follow back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ formatted_not_back, color_not_back = format_list("Users you follow who don't follow back", not_following_back, "orange")
+ follower_text.insert(tk.END, formatted_not_back, "not_following_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+ follower_text.tag_config("not_following_back", foreground=color_not_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0)
+
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL)
+
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0)
+
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0)
+
+def generate_summary(username, token):
+ try:
+ client = OpenAI(api_key=os.environ['OPENAI_API_KEY'])
+
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {"role": "user", "content": "Write a summary from this user's GitHub profile."}
+ ]
+ )
+
+ summary = completion.choices[0].message.content.strip()
+ return summary, profile_description, repos_contributed_to
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None
+
+def generate_summary_wrapper():
+ username = profile_entry.get().strip()
+ token = token_entry.get().strip()
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please enter username and token.")
+ return
+ summary, profile_description, repos_contributed_to = generate_summary(username, token)
+
+ if summary:
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_summary_table(conn)
+ cursor = conn.cursor()
+
+ cursor.execute('''INSERT INTO profile_summaries (username, profile_description, repos_contributed_to, summary)
+ VALUES (?, ?, ?, ?)''',
+ (username, profile_description, ", ".join(repos_contributed_to), summary))
+ conn.commit()
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Summary: {summary}", "summary")
+ summary_text.tag_config("summary", foreground="black")
+ summary_text.config(state=tk.DISABLED)
+
+ switch_tab(notebook, 1)
+
+def switch_tab(notebook, index):
+ global selected_tab
+ notebook.select(index)
+ selected_tab = index
+
+themes = {
+ "Default": {
+ "background": "SystemButtonFace",
+ "foreground": "black",
+ "button_bg": "SystemButtonFace",
+ "button_fg": "black",
+ "tab_bg": "SystemButtonFace",
+ "tab_fg": "black",
+ },
+ "Solarized Light": {
+ "background": "#fdf6e3",
+ "foreground": "#657b83",
+ "button_bg": "#eee8d5",
+ "button_fg": "#586e75",
+ "tab_bg": "#eee8d5",
+ "tab_fg": "#586e75",
+ },
+ "Solarized Dark": {
+ "background": "#002b36",
+ "foreground": "#839496",
+ "button_bg": "#073642",
+ "button_fg": "#839496",
+ "tab_bg": "#073642",
+ "tab_fg": "#93a1a1",
+ },
+ "Material": {
+ "background": "#263238",
+ "foreground": "#FFFFFF",
+ "button_bg": "#546e7a",
+ "button_fg": "#FFFFFF",
+ "tab_bg": "#37474f",
+ "tab_fg": "#FFFFFF",
+ },
+}
+
+def apply_theme(theme_name):
+ theme = themes.get(theme_name, themes["Default"])
+ root.configure(bg=theme["background"])
+ username_label.config(bg=theme["background"], fg=theme["foreground"])
+ token_label.config(bg=theme["background"], fg=theme["foreground"])
+ followers_file_label.config(bg=theme["background"], fg=theme["foreground"])
+ profile_label.config(bg=theme["background"], fg=theme["foreground"])
+ segmentation_label.config(bg=theme["background"], fg=theme["foreground"])
+ follower_text.config(bg=theme["background"], fg=theme["foreground"])
+ summary_text.config(bg=theme["background"], fg=theme["foreground"])
+ start_button.config(bg=theme["button_bg"], fg=theme["button_fg"])
+ show_analytics_button.config(bg=theme["button_bg"], fg=theme["button_fg"])
+ segment_followers_button.config(bg=theme["button_bg"], fg=theme["button_fg"])
+ summary_button.config(bg=theme["button_bg"], fg=theme["button_fg"])
+ # theme_menu_button.config(bg=theme["button_bg"], fg=theme["button_fg"])
+ notebook.config(bg=theme["tab_bg"], fg=theme["tab_fg"])
+
+root = tk.Tk()
+root.title("GitHub Follower Tracker")
+root.geometry("950x650")
+root.state('zoomed') # Maximizes the window
+root.option_add('*tearOff', False)
+
+theme_var = tk.StringVar()
+selected_tab = 0
+
+menu_bar = Menu(root)
+root.config(menu=menu_bar)
+
+file_menu = Menu(menu_bar)
+menu_bar.add_cascade(label="File", menu=file_menu)
+file_menu.add_command(label="Exit", command=root.quit)
+
+theme_menu = Menu(menu_bar)
+menu_bar.add_cascade(label="Theme", menu=theme_menu)
+
+for theme_name in themes:
+ theme_menu.add_radiobutton(label=theme_name, variable=theme_var, command=lambda: apply_theme(theme_var.get()))
+
+notebook = ttk.Notebook(root)
+notebook.pack(fill='both', expand=True)
+
+# Followers tab
+followers_frame = ttk.Frame(notebook)
+followers_frame.pack(fill='both', expand=True)
+notebook.add(followers_frame, text="Follower Data")
+
+summary_frame = ttk.Frame(notebook)
+summary_frame.pack(fill='both', expand=True)
+notebook.add(summary_frame, text="Profile Summary")
+
+username_label = ttk.Label(followers_frame, text="GitHub Username:")
+username_label.pack(pady=5)
+username_entry = ttk.Entry(followers_frame)
+username_entry.pack(pady=5)
+
+token_label = ttk.Label(followers_frame, text="GitHub Token:")
+token_label.pack(pady=5)
+token_entry = ttk.Entry(followers_frame, show='*')
+token_entry.pack(pady=5)
+
+followers_file_label = ttk.Label(followers_frame, text="Followers File Path:")
+followers_file_label.pack(pady=5)
+followers_file_entry = ttk.Entry(followers_frame)
+followers_file_entry.pack(pady=5)
+
+start_button = ttk.Button(followers_frame, text="Start Tracking", command=start_tracking)
+start_button.pack(pady=5)
+
+show_analytics_button = ttk.Button(followers_frame, text="Show Analytics", command=show_analytics)
+show_analytics_button.pack(pady=5)
+
+segmentation_label = ttk.Label(followers_frame, text="Segmentation Type:")
+segmentation_label.pack(pady=5)
+
+segmentation_type_var = tk.StringVar(followers_frame)
+segmentation_type_var.set("Please Select")
+
+segmentation_type_dropdown = ttk.OptionMenu(followers_frame, segmentation_type_var, "Please Select", "Repo", "Activity")
+segmentation_type_dropdown.pack(pady=5)
+
+segment_followers_button = ttk.Button(followers_frame, text="Segment Followers", command=segment_followers_ui)
+segment_followers_button.pack(pady=5)
+
+follower_text = scrolledtext.ScrolledText(followers_frame, wrap=tk.WORD, height=15)
+follower_text.pack(pady=10)
+follower_text.config(state=tk.DISABLED)
+
+profile_label = ttk.Label(summary_frame, text="GitHub Username:")
+profile_label.pack(pady=5)
+profile_entry = ttk.Entry(summary_frame)
+profile_entry.pack(pady=5)
+
+summary_button = ttk.Button(summary_frame, text="Generate Summary", command=generate_summary_wrapper)
+summary_button.pack(pady=5)
+
+summary_text = scrolledtext.ScrolledText(summary_frame, wrap=tk.WORD, height=15)
+summary_text.pack(pady=10)
+summary_text.config(state=tk.DISABLED)
+
+theme_menu_button = ttk.Label(followers_frame, text="Theme Menu", command=apply_theme(theme_menu))
+
+apply_theme("Default")
+
+root.mainloop()
\ No newline at end of file
diff --git a/archive/legacy-main-scripts/main9.py b/archive/legacy-main-scripts/main9.py
new file mode 100644
index 0000000..9839fb2
--- /dev/null
+++ b/archive/legacy-main-scripts/main9.py
@@ -0,0 +1,338 @@
+# main.py
+# MIT License
+# Created Date: 2024-09-02
+# Created By: Jason Evans
+# Version 1.1.1.2
+
+import tkinter as tk
+from tkinter import messagebox, scrolledtext, ttk, Menu
+import threading
+import os
+import json
+import sqlite3
+from datetime import datetime
+import requests
+from analytics import create_table, insert_follower, plot_follower_growth, segment_followers
+from dev.prototype.utils import get_all_followers, format_list
+from openai import OpenAI
+from dotenv import load_dotenv
+
+# Load API key from .env file
+load_dotenv()
+
+def create_summary_table(conn):
+ cursor = conn.cursor()
+ cursor.execute('''CREATE TABLE IF NOT EXISTS profile_summaries (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ username TEXT NOT NULL,
+ profile_description TEXT,
+ repos_contributed_to TEXT,
+ summary TEXT,
+ date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )''')
+ conn.commit()
+
+def track_followers(username, token, followers_file):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ create_table(conn)
+
+ if os.path.exists(followers_file):
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ previous_followers = follower_data.get('followers', [])
+ follower_history = follower_data.get('history', {})
+ else:
+ previous_followers = []
+ follower_history = {}
+
+ followers_url = f'https://api.github.com/users/{username}/followers'
+ following_url = f'https://api.github.com/users/{username}/following'
+ current_followers = get_all_followers(username, token, followers_url)
+ current_followings = get_all_followers(username, token, following_url)
+
+ new_followers = list(set(current_followers) - set(previous_followers))
+ unfollowers = list(set(previous_followers) - set(current_followers))
+ followers_back = list(set(current_followers) & set(current_followings))
+ not_following_back = list(set(current_followings) - set(current_followers))
+
+ today = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+ follower_history[today] = len(current_followers)
+
+ for follower in current_followers:
+ insert_follower(conn, follower, today)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ formatted_new, color_new = format_list("New followers", new_followers, "green")
+ follower_text.insert(tk.END, formatted_new, "new_followers")
+
+ formatted_unf, color_unf = format_list("Unfollowers", unfollowers, "red")
+ follower_text.insert(tk.END, formatted_unf, "unfollowers")
+
+ formatted_back, color_back = format_list("Followers who follow back", followers_back, "blue")
+ follower_text.insert(tk.END, formatted_back, "followers_back")
+
+ formatted_not_back, color_not_back = format_list("Users you follow who don't follow back", not_following_back, "orange")
+ follower_text.insert(tk.END, formatted_not_back, "not_following_back")
+
+ follower_text.tag_config("new_followers", foreground=color_new)
+ follower_text.tag_config("unfollowers", foreground=color_unf)
+ follower_text.tag_config("followers_back", foreground=color_back)
+ follower_text.tag_config("not_following_back", foreground=color_not_back)
+
+ follower_text.config(state=tk.DISABLED)
+
+ with open(followers_file, 'w') as f:
+ json.dump({'followers': current_followers, 'history': follower_history}, f, indent=4)
+
+ show_analytics_button.config(state=tk.NORMAL)
+ segment_followers_button.config(state=tk.NORMAL)
+ summary_button.config(state=tk.NORMAL)
+
+ conn.close()
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0)
+
+def start_tracking():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ threading.Thread(target=track_followers, args=(username, token, followers_file)).start()
+ summary_button.config(state=tk.NORMAL)
+
+def show_analytics():
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ plot_follower_growth(conn)
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0)
+
+def segment_followers_ui():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+ followers_file = followers_file_entry.get().strip()
+ segmentation_type = segmentation_type_var.get()
+
+ if not username or not token or not followers_file:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ try:
+ with open(followers_file, 'r') as f:
+ follower_data = json.load(f)
+ followers = follower_data['followers']
+
+ segments = segment_followers(followers, segmentation_type)
+
+ follower_text.config(state=tk.NORMAL)
+ follower_text.delete(1.0, tk.END)
+
+ for segment, members in segments.items():
+ formatted_segment, color_segment = format_list(segment, members, "blue")
+ follower_text.insert(tk.END, formatted_segment, "segment")
+
+ follower_text.tag_config("segment", foreground="blue")
+ follower_text.config(state=tk.DISABLED)
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ switch_tab(notebook, 0) # Switch to "Followers" tab after generating summary
+
+def generate_summary(username, token):
+ try:
+ client = OpenAI(api_key=os.environ['OPENAI_API_KEY'])
+
+ headers = {'Authorization': f'token {token}'}
+ profile_url = f'https://api.github.com/users/{username}'
+ repos_url = f'https://api.github.com/users/{username}/repos'
+
+ profile_response = requests.get(profile_url, headers=headers)
+ repos_response = requests.get(repos_url, headers=headers)
+
+ profile_response.raise_for_status()
+ repos_response.raise_for_status()
+
+ profile_data = profile_response.json()
+ repos_data = repos_response.json()
+
+ profile_description = profile_data.get('bio', 'No bio available')
+ repos_contributed_to = [repo['name'] for repo in repos_data if isinstance(repo, dict)]
+
+ prompt = (f"User {username} has the following bio: {profile_description}. "
+ f"They have contributed to the following repositories: {', '.join(repos_contributed_to)}. "
+ "Summarize the user's profile and contributions. Identify the sentiment & tone of the individual.")
+
+ completion = client.chat.completions.create(
+ model='gpt-4o-mini',
+ messages=[
+ {"role": "system", "content": prompt},
+ {"role": "user", "content": "Write a summary from this user's GitHub profile."}
+ ]
+ )
+
+ summary = completion.choices[0].message.content.strip()
+ return summary, profile_description, repos_contributed_to
+
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+ return None, None, None
+
+def save_summary_to_db(username, summary, profile_description, repos_contributed_to):
+ try:
+ conn = sqlite3.connect('follower_data.db')
+ cursor = conn.cursor()
+ cursor.execute("INSERT INTO profile_summaries (username, profile_description, repos_contributed_to, summary) VALUES (?, ?, ?, ?)",
+ (username, profile_description, ', '.join(repos_contributed_to), summary))
+ conn.commit()
+ conn.close()
+ except Exception as e:
+ messagebox.showerror("Error", str(e))
+
+def show_summary():
+ username = username_entry.get().strip()
+ token = token_entry.get().strip()
+
+ if not username or not token:
+ messagebox.showwarning("Input Error", "Please fill in all fields.")
+ return
+
+ summary, profile_description, repos_contributed_to = generate_summary(username, token)
+
+ if summary:
+ summary_text.config(state=tk.NORMAL)
+ summary_text.delete(1.0, tk.END)
+ summary_text.insert(tk.END, f"Username: {username}\n\n")
+ summary_text.insert(tk.END, f"Profile Description: {profile_description}\n\n")
+ summary_text.insert(tk.END, f"Repositories Contributed To: {', '.join(repos_contributed_to)}\n\n")
+ summary_text.insert(tk.END, f"Summary:\n{summary}\n")
+ summary_text.config(state=tk.DISABLED)
+
+ save_summary_to_db(username, summary, profile_description, repos_contributed_to)
+
+ switch_tab(notebook, 1)
+
+def switch_tab(notebook, tab_index):
+ notebook.select(tab_index)
+
+def set_theme(theme):
+ if theme == "light":
+ root.configure(bg="white")
+ style.configure('TLabel', background="white", foreground="black")
+ follower_text.configure(bg="white", fg="black")
+ elif theme == "dark":
+ root.configure(bg="black")
+ style.configure('TLabel', background="black", foreground="white")
+ follower_text.configure(bg="black", fg="white")
+ elif theme == "solarized_light":
+ root.configure(bg="#FDF6E3")
+ style.configure('TLabel', background="#FDF6E3", foreground="#657B83")
+ follower_text.configure(bg="#FDF6E3", fg="#657B83")
+ elif theme == "custom":
+ root.configure(bg="#2E3440") # replace with your custom color
+ style.configure('TLabel', background="#2E3440", foreground="#2E3440") # replace with your custom color
+ follower_text.configure(bg="#2E3440", fg="#2E3440")
+ else:
+ root.configure(bg="default_color_bg")
+ style.configure('TLabel', background="default_color_bg", foreground="default_color_fg")
+ follower_text.configure(bg="default_color_bg", fg="default_color_fg")
+
+# UI Setup
+root = tk.Tk()
+root.title("GitHub Follower Tracker")
+root.geometry("800x600")
+
+# Create a style object
+style = ttk.Style(root)
+
+# Notebook for Tabs
+notebook = ttk.Notebook(root)
+notebook.pack(expand=True, fill="both")
+
+# Tab 1: Follower Data
+tab1 = ttk.Frame(notebook)
+notebook.add(tab1, text="Follower Data")
+
+# Tab 2: Profile Summary
+tab2 = ttk.Frame(notebook)
+notebook.add(tab2, text="Profile Summary")
+
+# Frame for User Inputs
+input_frame = ttk.Frame(tab1)
+input_frame.pack(pady=10, padx=10, fill="x")
+
+username_label = ttk.Label(input_frame, text="GitHub Username:")
+username_label.grid(row=0, column=0, sticky="e")
+username_entry = ttk.Entry(input_frame)
+username_entry.grid(row=0, column=1, padx=5, pady=5)
+
+token_label = ttk.Label(input_frame, text="GitHub Token:")
+token_label.grid(row=1, column=0, sticky="e")
+token_entry = ttk.Entry(input_frame, show="*")
+token_entry.grid(row=1, column=1, padx=5, pady=5)
+
+followers_file_label = ttk.Label(input_frame, text="Followers File:")
+followers_file_label.grid(row=2, column=0, sticky="e")
+followers_file_entry = ttk.Entry(input_frame)
+followers_file_entry.grid(row=2, column=1, padx=5, pady=5)
+
+start_button = ttk.Button(input_frame, text="Start Tracking", command=start_tracking)
+start_button.grid(row=3, column=1, padx=5, pady=10)
+
+# Frame for Follower Text Output
+follower_text = scrolledtext.ScrolledText(tab1, wrap=tk.WORD, height=15, state=tk.DISABLED)
+follower_text.pack(pady=10, padx=10, fill="both", expand=True)
+
+# Analytics Button
+show_analytics_button = ttk.Button(tab1, text="Show Analytics", command=show_analytics, state=tk.DISABLED)
+show_analytics_button.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Create the segmentation type variable with a default read-only label "Please Select"
+segmentation_type_var = tk.StringVar(value="Please Select")
+
+# Label for Segmentation
+segmentation_label = tk.Label(tab1, text="Segment By:")
+segmentation_label.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Dropdown menu for Segmentation Types
+segmentation_menu = tk.OptionMenu(tab1, segmentation_type_var, "repo", "activity")
+segmentation_menu.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Segment followers button
+segment_followers_button = tk.Button(tab1, text="Segment Followers", command=segment_followers_ui, state=tk.DISABLED)
+# segment_followers_button.pack(anchor="w", pady=5)
+segment_followers_button.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Generate Summary Button
+summary_button = ttk.Button(tab1, text="Generate Summary", command=show_summary, state=tk.DISABLED)
+summary_button.pack(side=tk.LEFT, padx=10, pady=10)
+
+# Frame for Summary Text Output
+summary_text = scrolledtext.ScrolledText(tab2, wrap=tk.WORD, height=15, state=tk.DISABLED)
+summary_text.pack(pady=10, padx=10, fill="both", expand=True)
+
+# Menu Bar for Theme Selection
+menu_bar = Menu(root)
+root.config(menu=menu_bar)
+
+# Theme Menu
+theme_menu = Menu(menu_bar, tearoff=0)
+menu_bar.add_cascade(label="Settings", menu=theme_menu)
+
+theme_menu.add_command(label="Light Theme", command=lambda: set_theme("light"))
+theme_menu.add_command(label="Dark Theme", command=lambda: set_theme("dark"))
+theme_menu.add_command(label="Solarized Light Theme", command=lambda: set_theme("solarized_light"))
+theme_menu.add_command(label="Custom Theme", command=lambda: set_theme("custom"))
+
+# Main Loop
+root.mainloop()
\ No newline at end of file
diff --git a/backend/app/__init__.py b/backend/app/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/backend/app/api/ping.py b/backend/app/api/ping.py
new file mode 100644
index 0000000..8c2214b
--- /dev/null
+++ b/backend/app/api/ping.py
@@ -0,0 +1,8 @@
+# app/api/ping.py
+from fastapi import APIRouter
+
+router = APIRouter()
+
+@router.get("/ping")
+async def ping():
+ return {"status": "ok"}
diff --git a/backend/app/api/stats.py b/backend/app/api/stats.py
new file mode 100644
index 0000000..3afb210
--- /dev/null
+++ b/backend/app/api/stats.py
@@ -0,0 +1,68 @@
+import logging
+from typing import NoReturn
+
+from fastapi import APIRouter, HTTPException, Query
+
+from app.models import Change, DashboardData, GitHubProfile, Stats, Trends
+from app.services.tracker import (
+ get_change_history,
+ get_dashboard_data,
+ get_follower_stats,
+ get_follower_trends,
+ get_github_profile,
+)
+
+router = APIRouter()
+logger = logging.getLogger(__name__)
+SERVER_ERROR_DETAIL = "Unable to load follower data."
+
+
+def _raise_service_error(message: str, exc: Exception) -> NoReturn:
+ logger.exception(message)
+ raise HTTPException(status_code=500, detail=SERVER_ERROR_DETAIL) from exc
+
+
+@router.get("/dashboard", response_model=DashboardData)
+def dashboard(refresh: bool = Query(default=False)) -> DashboardData:
+ try:
+ return get_dashboard_data(refresh=refresh)
+ except Exception as exc:
+ _raise_service_error("Failed to build dashboard data.", exc)
+
+
+@router.get("/profile", response_model=GitHubProfile)
+def profile(refresh: bool = Query(default=False)) -> GitHubProfile:
+ try:
+ return get_github_profile(refresh=refresh)
+ except Exception as exc:
+ _raise_service_error("Failed to load GitHub profile.", exc)
+
+
+@router.get("/followers", response_model=Stats)
+def total_followers(refresh: bool = Query(default=False)) -> Stats:
+ try:
+ return get_follower_stats(refresh=refresh)
+ except Exception as exc:
+ _raise_service_error("Failed to load follower stats.", exc)
+
+
+@router.get("/trends", response_model=Trends)
+def trends(refresh: bool = Query(default=False)) -> Trends:
+ try:
+ return get_follower_trends(refresh=refresh)
+ except Exception as exc:
+ _raise_service_error("Failed to load follower trends.", exc)
+
+
+@router.get("/history/{change_type}", response_model=list[Change])
+def history(
+ change_type: str,
+ days: int = Query(default=30, ge=1, le=365),
+ refresh: bool = Query(default=False),
+) -> list[Change]:
+ if change_type not in ("new", "lost"):
+ raise HTTPException(status_code=400, detail="must be 'new' or 'lost'")
+ try:
+ return get_change_history(change_type, days=days, refresh=refresh)
+ except Exception as exc:
+ _raise_service_error("Failed to load follower history.", exc)
diff --git a/backend/app/main.py b/backend/app/main.py
new file mode 100644
index 0000000..74128d2
--- /dev/null
+++ b/backend/app/main.py
@@ -0,0 +1,42 @@
+# app/main.py
+from collections.abc import AsyncIterator
+from contextlib import asynccontextmanager
+
+from fastapi import FastAPI
+from fastapi.middleware.cors import CORSMiddleware
+
+from app.api.ping import router as ping_router
+from app.api.stats import router as stats_router
+from app.services.tracker import initialize_tracker_db
+
+
+@asynccontextmanager
+async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
+ initialize_tracker_db()
+ yield
+
+app = FastAPI(
+ title="GitHub Follower Checker API",
+ version="0.1.0",
+ lifespan=lifespan,
+)
+
+# Enable CORS for local Next.js dev servers. Next automatically falls back to
+# 3001 when 3000 is already occupied.
+to_allow = [
+ "http://localhost:3000",
+ "http://127.0.0.1:3000",
+ "http://localhost:3001",
+ "http://127.0.0.1:3001",
+]
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=to_allow,
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+# Mount routers
+app.include_router(ping_router)
+app.include_router(stats_router, prefix="/stats", tags=["stats"])
diff --git a/backend/app/models.py b/backend/app/models.py
new file mode 100644
index 0000000..e3c2b49
--- /dev/null
+++ b/backend/app/models.py
@@ -0,0 +1,100 @@
+from datetime import datetime
+from typing import Literal
+
+from pydantic import BaseModel
+
+
+class Stats(BaseModel):
+ total_followers: int
+ new_followers: int
+ unfollowers: int
+ net_change: int = 0
+
+
+class GitHubProfile(BaseModel):
+ username: str
+ name: str | None = None
+ avatar_url: str | None = None
+ html_url: str
+ bio: str | None = None
+ public_repos: int = 0
+ following: int = 0
+ followers: int = 0
+ company: str | None = None
+ location: str | None = None
+ created_at: datetime | None = None
+
+
+class Trends(BaseModel):
+ labels: list[datetime]
+ history: list[int]
+
+
+class Change(BaseModel):
+ username: str
+ timestamp: datetime
+
+
+class EnrichedChange(Change):
+ name: str | None = None
+ avatar_url: str | None = None
+ html_url: str
+ bio: str | None = None
+ public_repos: int = 0
+ followers: int = 0
+ following: int = 0
+ company: str | None = None
+ location: str | None = None
+ created_at: datetime | None = None
+ signal_score: float = 0.0
+ signal_label: str = "Emerging"
+
+
+class DashboardMetrics(BaseModel):
+ total_followers: int
+ following: int
+ net_24h: int
+ net_7d: int
+ net_30d: int
+ average_daily_growth: float
+ churn_rate: float
+ volatility_score: float
+ stability_score: float
+ snapshot_count: int
+ change_records_30d: int
+
+
+class DashboardHealth(BaseModel):
+ api_status: Literal["healthy", "degraded", "error"]
+ partial_data: bool
+ stale_data: bool
+ last_successful_sync: datetime | None = None
+ last_failed_sync: datetime | None = None
+ last_error: str | None = None
+ snapshot_count: int = 0
+ expected_cadence_minutes: int | None = None
+ missed_snapshots: int = 0
+ data_freshness_minutes: int | None = None
+
+
+class ChartAnnotation(BaseModel):
+ timestamp: datetime
+ kind: Literal["spike", "dip", "gain", "loss", "peak", "low"]
+ label: str
+ value: int
+ magnitude: int = 0
+
+
+class DashboardData(BaseModel):
+ generated_at: datetime
+ profile: GitHubProfile
+ stats: Stats
+ metrics: DashboardMetrics
+ trends: Trends
+ health: DashboardHealth
+ recent_new_followers: list[EnrichedChange]
+ recent_lost_followers: list[EnrichedChange]
+ all_new_followers: list[EnrichedChange]
+ all_lost_followers: list[EnrichedChange]
+ high_signal_new_followers: list[EnrichedChange]
+ annotations: list[ChartAnnotation]
diff --git a/backend/app/services/tracker.py b/backend/app/services/tracker.py
new file mode 100644
index 0000000..e9d5e43
--- /dev/null
+++ b/backend/app/services/tracker.py
@@ -0,0 +1,1060 @@
+import os
+import sqlite3
+import time
+from datetime import datetime, timedelta, timezone
+from statistics import mean, median, pstdev
+from threading import Lock
+from typing import Any
+
+import requests
+from dotenv import load_dotenv
+
+from app.models import (
+ Change,
+ ChartAnnotation,
+ DashboardData,
+ DashboardHealth,
+ DashboardMetrics,
+ EnrichedChange,
+ GitHubProfile,
+ Stats,
+ Trends,
+)
+
+BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
+REPO_ROOT = os.path.abspath(os.path.join(BASE_DIR, ".."))
+
+DB_PATH = os.path.join(BASE_DIR, "followers.db")
+LEGACY_DB_PATH = os.path.join(REPO_ROOT, "follower_data.db")
+API_URL = "https://api.github.com"
+USERNAME: str | None = None
+TOKEN: str | None = None
+REQUEST_TIMEOUT = 20
+SQLITE_TIMEOUT_SECONDS = 30
+SQLITE_BUSY_TIMEOUT_MS = 30000
+SQLITE_WRITE_RETRY_ATTEMPTS = 3
+SQLITE_WRITE_RETRY_BASE_SECONDS = 0.2
+SYNC_INTERVAL_MINUTES = 5
+SNAPSHOT_INTERVAL_MINUTES = 30
+USER_CACHE_HOURS = 24
+FULL_HISTORY_DAYS = 30
+RECENT_WINDOW_HOURS = 24
+LEGACY_IMPORT_SOURCE = "legacy_desktop_db_v1"
+CHANGE_TABLES = {"new_followers", "lost_followers"}
+
+_DB_INIT_LOCK = Lock()
+_DB_INITIALIZED = False
+# _SYNC_LOCK prevents concurrent syncs within a single process. When running
+# with multiple worker processes (e.g. uvicorn --workers N), this lock cannot
+# coordinate across processes. To avoid SQLite "database is locked" errors in
+# that scenario, deploy with a single worker (uvicorn --workers 1) when using
+# the default SQLite backend.
+_SYNC_LOCK = Lock()
+
+
+def utcnow() -> datetime:
+ return datetime.utcnow().replace(microsecond=0)
+
+
+def isoformat(value: datetime) -> str:
+ return value.isoformat()
+
+
+def parse_datetime(value: str | None) -> datetime | None:
+ if not value:
+ return None
+ normalized = value.replace("Z", "+00:00")
+ parsed = datetime.fromisoformat(normalized)
+ if parsed.tzinfo is not None:
+ parsed = parsed.astimezone(timezone.utc).replace(tzinfo=None)
+ return parsed
+
+
+def build_headers() -> dict[str, str]:
+ headers = {"Accept": "application/vnd.github+json"}
+ if TOKEN:
+ headers["Authorization"] = f"Bearer {TOKEN}"
+ return headers
+
+
+def get_connection() -> sqlite3.Connection:
+ conn = sqlite3.connect(DB_PATH, timeout=SQLITE_TIMEOUT_SECONDS)
+ conn.execute(f"PRAGMA busy_timeout = {SQLITE_BUSY_TIMEOUT_MS}")
+ conn.row_factory = sqlite3.Row
+ return conn
+
+
+def init_db() -> None:
+ conn = get_connection()
+ try:
+ cursor = conn.cursor()
+ cursor.execute("PRAGMA journal_mode=WAL")
+ cursor.execute(
+ """
+ CREATE TABLE IF NOT EXISTS followers (
+ count INTEGER,
+ timestamp TEXT
+ )
+ """
+ )
+ cursor.execute(
+ """
+ CREATE TABLE IF NOT EXISTS new_followers (
+ username TEXT,
+ timestamp TEXT
+ )
+ """
+ )
+ cursor.execute(
+ """
+ CREATE TABLE IF NOT EXISTS lost_followers (
+ username TEXT,
+ timestamp TEXT
+ )
+ """
+ )
+ cursor.execute(
+ """
+ CREATE TABLE IF NOT EXISTS current_followers (
+ username TEXT PRIMARY KEY
+ )
+ """
+ )
+ cursor.execute(
+ """
+ CREATE TABLE IF NOT EXISTS user_cache (
+ username TEXT PRIMARY KEY,
+ name TEXT,
+ avatar_url TEXT,
+ html_url TEXT,
+ bio TEXT,
+ public_repos INTEGER DEFAULT 0,
+ followers INTEGER DEFAULT 0,
+ following INTEGER DEFAULT 0,
+ company TEXT,
+ location TEXT,
+ created_at TEXT,
+ cached_at TEXT NOT NULL
+ )
+ """
+ )
+ cursor.execute(
+ """
+ CREATE TABLE IF NOT EXISTS sync_runs (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ timestamp TEXT NOT NULL,
+ status TEXT NOT NULL,
+ error TEXT,
+ follower_count INTEGER,
+ new_count INTEGER DEFAULT 0,
+ lost_count INTEGER DEFAULT 0
+ )
+ """
+ )
+ cursor.execute(
+ """
+ CREATE TABLE IF NOT EXISTS data_imports (
+ source TEXT PRIMARY KEY,
+ imported_at TEXT NOT NULL
+ )
+ """
+ )
+ cursor.execute(
+ "CREATE INDEX IF NOT EXISTS idx_followers_timestamp ON followers(timestamp)"
+ )
+ cursor.execute(
+ "CREATE UNIQUE INDEX IF NOT EXISTS idx_followers_unique_timestamp ON followers(timestamp)"
+ )
+ cursor.execute(
+ "CREATE INDEX IF NOT EXISTS idx_new_followers_timestamp ON new_followers(timestamp)"
+ )
+ cursor.execute(
+ "CREATE UNIQUE INDEX IF NOT EXISTS idx_new_followers_unique ON new_followers(username, timestamp)"
+ )
+ cursor.execute(
+ "CREATE INDEX IF NOT EXISTS idx_lost_followers_timestamp ON lost_followers(timestamp)"
+ )
+ cursor.execute(
+ "CREATE UNIQUE INDEX IF NOT EXISTS idx_lost_followers_unique ON lost_followers(username, timestamp)"
+ )
+ cursor.execute(
+ "CREATE INDEX IF NOT EXISTS idx_sync_runs_timestamp ON sync_runs(timestamp)"
+ )
+ import_legacy_data(conn)
+ conn.commit()
+ finally:
+ conn.close()
+
+
+def initialize_tracker_db() -> None:
+ global _DB_INITIALIZED, USERNAME, TOKEN
+
+ if _DB_INITIALIZED:
+ return
+
+ with _DB_INIT_LOCK:
+ if _DB_INITIALIZED:
+ return
+ load_dotenv(os.path.join(REPO_ROOT, ".env"))
+ load_dotenv(os.path.join(BASE_DIR, ".env"), override=True)
+ USERNAME = os.getenv("GITHUB_USERNAME")
+ TOKEN = os.getenv("GITHUB_TOKEN")
+ init_db()
+ _DB_INITIALIZED = True
+
+
+def request_json(url: str) -> Any:
+ response = requests.get(url, headers=build_headers(), timeout=REQUEST_TIMEOUT)
+ response.raise_for_status()
+ return response.json()
+
+
+def fetch_github_profile_json() -> dict[str, Any]:
+ if not USERNAME:
+ raise RuntimeError("GITHUB_USERNAME is not configured.")
+ return request_json(f"{API_URL}/users/{USERNAME}")
+
+
+def fetch_followers() -> list[str]:
+ if not USERNAME:
+ raise RuntimeError("GITHUB_USERNAME is not configured.")
+
+ url = f"{API_URL}/users/{USERNAME}/followers?per_page=100"
+ followers: list[str] = []
+ while url:
+ response = requests.get(url, headers=build_headers(), timeout=REQUEST_TIMEOUT)
+ response.raise_for_status()
+ data = response.json()
+ followers.extend(entry["login"] for entry in data if entry.get("login"))
+ url = response.links.get("next", {}).get("url")
+ return sorted(set(followers))
+
+
+def fetch_user_json(username: str) -> dict[str, Any]:
+ return request_json(f"{API_URL}/users/{username}")
+
+
+def normalize_timestamp(value: str | None) -> str | None:
+ parsed = parse_datetime(value)
+ if parsed is None:
+ return None
+ return isoformat(parsed)
+
+
+def import_marker_exists(conn: sqlite3.Connection, source: str) -> bool:
+ row = conn.execute(
+ "SELECT 1 FROM data_imports WHERE source = ?",
+ (source,),
+ ).fetchone()
+ return row is not None
+
+
+def mark_import_complete(conn: sqlite3.Connection, source: str) -> None:
+ conn.execute(
+ """
+ INSERT INTO data_imports (source, imported_at)
+ VALUES (?, ?)
+ ON CONFLICT(source) DO UPDATE SET imported_at = excluded.imported_at
+ """,
+ (source, isoformat(utcnow())),
+ )
+
+
+def import_legacy_data(conn: sqlite3.Connection) -> None:
+ if import_marker_exists(conn, LEGACY_IMPORT_SOURCE):
+ return
+ if not os.path.exists(LEGACY_DB_PATH):
+ return
+
+ legacy = sqlite3.connect(LEGACY_DB_PATH)
+ legacy.row_factory = sqlite3.Row
+ try:
+ snapshot_rows = legacy.execute(
+ """
+ SELECT timestamp, COUNT(*) AS count
+ FROM followers
+ GROUP BY timestamp
+ ORDER BY timestamp
+ """
+ ).fetchall()
+
+ snapshot_sets: dict[str, set[str]] = {}
+ follower_rows = legacy.execute(
+ "SELECT username, timestamp FROM followers ORDER BY timestamp, username"
+ ).fetchall()
+ for row in follower_rows:
+ normalized = normalize_timestamp(row["timestamp"])
+ if not normalized:
+ continue
+ snapshot_sets.setdefault(normalized, set()).add(row["username"])
+
+ for row in snapshot_rows:
+ normalized = normalize_timestamp(row["timestamp"])
+ if not normalized:
+ continue
+ conn.execute(
+ "INSERT OR IGNORE INTO followers (count, timestamp) VALUES (?, ?)",
+ (int(row["count"]), normalized),
+ )
+
+ previous_followers: set[str] | None = None
+ latest_followers: set[str] = set()
+ for timestamp in sorted(snapshot_sets):
+ current_followers = snapshot_sets[timestamp]
+ latest_followers = current_followers
+ if previous_followers is None:
+ previous_followers = current_followers
+ continue
+
+ new_users = sorted(current_followers - previous_followers)
+ lost_users = sorted(previous_followers - current_followers)
+
+ if new_users:
+ conn.executemany(
+ "INSERT OR IGNORE INTO new_followers (username, timestamp) VALUES (?, ?)",
+ [(username, timestamp) for username in new_users],
+ )
+ if lost_users:
+ conn.executemany(
+ "INSERT OR IGNORE INTO lost_followers (username, timestamp) VALUES (?, ?)",
+ [(username, timestamp) for username in lost_users],
+ )
+ previous_followers = current_followers
+
+ try:
+ unfollower_rows = legacy.execute(
+ "SELECT username, timestamp FROM unfollowers"
+ ).fetchall()
+ if unfollower_rows:
+ conn.executemany(
+ "INSERT OR IGNORE INTO lost_followers (username, timestamp) VALUES (?, ?)",
+ [
+ (row["username"], normalized)
+ for row in unfollower_rows
+ if (normalized := normalize_timestamp(row["timestamp"])) is not None
+ ],
+ )
+ except sqlite3.Error:
+ pass
+
+ if latest_followers and not load_current_followers(conn):
+ replace_current_followers(conn, latest_followers)
+
+ mark_import_complete(conn, LEGACY_IMPORT_SOURCE)
+ finally:
+ legacy.close()
+
+
+def record_sync_run(
+ conn: sqlite3.Connection,
+ *,
+ status: str,
+ timestamp: datetime,
+ follower_count: int | None = None,
+ new_count: int = 0,
+ lost_count: int = 0,
+ error: str | None = None,
+) -> None:
+ conn.execute(
+ """
+ INSERT INTO sync_runs (timestamp, status, error, follower_count, new_count, lost_count)
+ VALUES (?, ?, ?, ?, ?, ?)
+ """,
+ (isoformat(timestamp), status, error, follower_count, new_count, lost_count),
+ )
+
+
+def load_cached_profile_row(conn: sqlite3.Connection, username: str) -> sqlite3.Row | None:
+ return conn.execute(
+ "SELECT * FROM user_cache WHERE username = ?",
+ (username,),
+ ).fetchone()
+
+
+def upsert_user_cache(conn: sqlite3.Connection, data: dict[str, Any]) -> None:
+ login = data.get("login")
+ if not login:
+ return
+
+ conn.execute(
+ """
+ INSERT INTO user_cache (
+ username, name, avatar_url, html_url, bio, public_repos, followers,
+ following, company, location, created_at, cached_at
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ON CONFLICT(username) DO UPDATE SET
+ name = excluded.name,
+ avatar_url = excluded.avatar_url,
+ html_url = excluded.html_url,
+ bio = excluded.bio,
+ public_repos = excluded.public_repos,
+ followers = excluded.followers,
+ following = excluded.following,
+ company = excluded.company,
+ location = excluded.location,
+ created_at = excluded.created_at,
+ cached_at = excluded.cached_at
+ """,
+ (
+ login,
+ data.get("name"),
+ data.get("avatar_url"),
+ data.get("html_url") or f"https://github.com/{login}",
+ data.get("bio"),
+ data.get("public_repos", 0),
+ data.get("followers", 0),
+ data.get("following", 0),
+ data.get("company"),
+ data.get("location"),
+ data.get("created_at"),
+ isoformat(utcnow()),
+ ),
+ )
+
+
+def should_refresh_user_cache(row: sqlite3.Row | None) -> bool:
+ if row is None:
+ return True
+ cached_at = parse_datetime(row["cached_at"])
+ if cached_at is None:
+ return True
+ return cached_at < utcnow() - timedelta(hours=USER_CACHE_HOURS)
+
+
+def ensure_user_cache(
+ conn: sqlite3.Connection,
+ username: str,
+ *,
+ allow_fetch: bool,
+) -> sqlite3.Row | None:
+ row = load_cached_profile_row(conn, username)
+ if allow_fetch and should_refresh_user_cache(row):
+ try:
+ upsert_user_cache(conn, fetch_user_json(username))
+ row = load_cached_profile_row(conn, username)
+ except Exception:
+ return row
+ return row
+
+
+def profile_from_row(row: sqlite3.Row | None, fallback_username: str | None = None) -> GitHubProfile:
+ username = fallback_username or (row["username"] if row else USERNAME) or "unknown"
+ html_url = row["html_url"] if row and row["html_url"] else f"https://github.com/{username}"
+ return GitHubProfile(
+ username=username,
+ name=row["name"] if row else None,
+ avatar_url=row["avatar_url"] if row else None,
+ html_url=html_url,
+ bio=row["bio"] if row else None,
+ public_repos=int(row["public_repos"] or 0) if row else 0,
+ following=int(row["following"] or 0) if row else 0,
+ followers=int(row["followers"] or 0) if row else 0,
+ company=row["company"] if row else None,
+ location=row["location"] if row else None,
+ created_at=parse_datetime(row["created_at"]) if row else None,
+ )
+
+
+def load_current_followers(conn: sqlite3.Connection) -> set[str]:
+ rows = conn.execute("SELECT username FROM current_followers").fetchall()
+ return {row["username"] for row in rows}
+
+
+def replace_current_followers(conn: sqlite3.Connection, followers: set[str]) -> None:
+ conn.execute("DELETE FROM current_followers")
+ conn.executemany(
+ "INSERT INTO current_followers (username) VALUES (?)",
+ [(username,) for username in sorted(followers)],
+ )
+
+
+def latest_successful_sync(conn: sqlite3.Connection) -> sqlite3.Row | None:
+ return conn.execute(
+ "SELECT * FROM sync_runs WHERE status = 'success' ORDER BY timestamp DESC LIMIT 1"
+ ).fetchone()
+
+
+def latest_snapshot(conn: sqlite3.Connection) -> sqlite3.Row | None:
+ return conn.execute(
+ "SELECT count, timestamp FROM followers ORDER BY timestamp DESC LIMIT 1"
+ ).fetchone()
+
+
+def should_insert_snapshot(conn: sqlite3.Connection, count: int, timestamp: datetime) -> bool:
+ row = latest_snapshot(conn)
+ if row is None:
+ return True
+ last_timestamp = parse_datetime(row["timestamp"])
+ last_count = int(row["count"])
+ if last_count != count:
+ return True
+ if last_timestamp is None:
+ return True
+ return last_timestamp <= timestamp - timedelta(minutes=SNAPSHOT_INTERVAL_MINUTES)
+
+
+def insert_snapshot(conn: sqlite3.Connection, count: int, timestamp: datetime) -> None:
+ conn.execute(
+ "INSERT OR IGNORE INTO followers (count, timestamp) VALUES (?, ?)",
+ (count, isoformat(timestamp)),
+ )
+
+
+def is_database_locked_error(exc: sqlite3.OperationalError) -> bool:
+ message = str(exc).lower()
+ return "database is locked" in message or "database table is locked" in message
+
+
+def successful_sync_since(timestamp: datetime) -> bool:
+ conn = get_connection()
+ try:
+ row = latest_successful_sync(conn)
+ if row is None:
+ return False
+ synced_at = parse_datetime(row["timestamp"])
+ return synced_at is not None and synced_at >= timestamp
+ finally:
+ conn.close()
+
+
+def sync_followers(*, force: bool = False) -> None:
+ """Sync follower data from the GitHub API.
+
+ Uses ``_SYNC_LOCK`` to prevent concurrent syncs within the same process.
+ When deployed with multiple worker processes (e.g. ``uvicorn --workers N``),
+ this lock cannot coordinate across processes and SQLite ``database is locked``
+ errors may occur. Run with a single worker (``uvicorn --workers 1``) when
+ using the default SQLite backend.
+ """
+ initialize_tracker_db()
+ requested_at = utcnow()
+
+ with _SYNC_LOCK:
+ if force:
+ try:
+ if successful_sync_since(requested_at):
+ return
+ except sqlite3.OperationalError as exc:
+ if not is_database_locked_error(exc):
+ raise
+
+ for attempt in range(SQLITE_WRITE_RETRY_ATTEMPTS + 1):
+ try:
+ _sync_followers_once(force=force)
+ return
+ except sqlite3.OperationalError as exc:
+ if not is_database_locked_error(exc) or attempt >= SQLITE_WRITE_RETRY_ATTEMPTS:
+ raise
+ time.sleep(SQLITE_WRITE_RETRY_BASE_SECONDS * (2**attempt))
+
+
+def _sync_followers_once(*, force: bool = False) -> None:
+ conn: sqlite3.Connection | None = None
+ now = utcnow()
+
+ try:
+ conn = get_connection()
+ latest_success = latest_successful_sync(conn)
+
+ if latest_success is not None and not force:
+ last_success = parse_datetime(latest_success["timestamp"])
+ if last_success and last_success >= now - timedelta(minutes=SYNC_INTERVAL_MINUTES):
+ return
+
+ profile_data = fetch_github_profile_json()
+ upsert_user_cache(conn, profile_data)
+
+ current_followers = set(fetch_followers())
+ previous_followers = load_current_followers(conn)
+
+ new_users = sorted(current_followers - previous_followers) if previous_followers else []
+ lost_users = sorted(previous_followers - current_followers) if previous_followers else []
+ current_count = int(profile_data.get("followers", len(current_followers)))
+
+ if should_insert_snapshot(conn, current_count, now):
+ insert_snapshot(conn, current_count, now)
+
+ replace_current_followers(conn, current_followers)
+
+ if previous_followers:
+ if new_users:
+ conn.executemany(
+ "INSERT OR IGNORE INTO new_followers (username, timestamp) VALUES (?, ?)",
+ [(username, isoformat(now)) for username in new_users],
+ )
+ if lost_users:
+ conn.executemany(
+ "INSERT OR IGNORE INTO lost_followers (username, timestamp) VALUES (?, ?)",
+ [(username, isoformat(now)) for username in lost_users],
+ )
+
+ for username in new_users + lost_users:
+ ensure_user_cache(conn, username, allow_fetch=True)
+
+ record_sync_run(
+ conn,
+ status="success",
+ timestamp=now,
+ follower_count=current_count,
+ new_count=len(new_users),
+ lost_count=len(lost_users),
+ )
+ conn.commit()
+ except Exception as exc:
+ if conn is not None:
+ try:
+ conn.rollback()
+ except sqlite3.Error:
+ pass
+ try:
+ record_sync_run(conn, status="failure", timestamp=now, error=str(exc))
+ conn.commit()
+ except sqlite3.Error:
+ pass
+ raise
+ finally:
+ if conn is not None:
+ conn.close()
+
+
+def load_trends(conn: sqlite3.Connection) -> Trends:
+ rows = conn.execute("SELECT timestamp, count FROM followers ORDER BY timestamp").fetchall()
+ labels: list[datetime] = []
+ history: list[int] = []
+ for row in rows:
+ parsed = parse_datetime(row["timestamp"])
+ if parsed is None:
+ continue
+ labels.append(parsed)
+ history.append(int(row["count"]))
+ return Trends(
+ labels=labels,
+ history=history,
+ )
+
+
+def load_changes(
+ conn: sqlite3.Connection,
+ table: str,
+ *,
+ since: datetime | None = None,
+) -> list[sqlite3.Row]:
+ if table not in CHANGE_TABLES:
+ raise ValueError(f"Unsupported change table: {table}")
+
+ query = f"SELECT username, timestamp FROM {table}"
+ params: tuple[Any, ...] = ()
+ if since is not None:
+ query += " WHERE timestamp >= ?"
+ params = (isoformat(since),)
+ query += " ORDER BY timestamp DESC"
+ return conn.execute(query, params).fetchall()
+
+
+def score_user(row: sqlite3.Row | None) -> tuple[float, str]:
+ if row is None:
+ return 0.0, "Emerging"
+
+ followers = int(row["followers"] or 0)
+ repos = int(row["public_repos"] or 0)
+ created_at = parse_datetime(row["created_at"])
+ account_age_days = (utcnow() - created_at).days if created_at else 0
+ score = 0.0
+ score += min(followers, 500) / 8
+ score += min(repos, 80) * 0.75
+ score += min(account_age_days / 365, 10) * 3
+ score += 5 if row["bio"] else 0
+ score += 4 if row["company"] else 0
+ score += 3 if row["location"] else 0
+ score = round(min(score, 100.0), 1)
+
+ if score >= 70:
+ label = "High-signal"
+ elif score >= 45:
+ label = "Notable"
+ else:
+ label = "Emerging"
+ return score, label
+
+
+def enrich_change_rows(
+ conn: sqlite3.Connection,
+ rows: list[sqlite3.Row],
+ *,
+ allow_fetch: bool,
+) -> list[EnrichedChange]:
+ enriched: list[EnrichedChange] = []
+ seen_fetches = 0
+ cache: dict[str, sqlite3.Row | None] = {}
+
+ for row in rows:
+ username = row["username"]
+ if username not in cache:
+ can_fetch = allow_fetch and seen_fetches < 24
+ cache[username] = ensure_user_cache(conn, username, allow_fetch=can_fetch)
+ if can_fetch:
+ seen_fetches += 1
+ user_row = cache[username]
+ score, label = score_user(user_row)
+ created_at = parse_datetime(user_row["created_at"]) if user_row else None
+ enriched.append(
+ EnrichedChange(
+ username=username,
+ timestamp=parse_datetime(row["timestamp"]) or utcnow(),
+ name=user_row["name"] if user_row else None,
+ avatar_url=user_row["avatar_url"] if user_row else None,
+ html_url=user_row["html_url"] if user_row and user_row["html_url"] else f"https://github.com/{username}",
+ bio=user_row["bio"] if user_row else None,
+ public_repos=int(user_row["public_repos"] or 0) if user_row else 0,
+ followers=int(user_row["followers"] or 0) if user_row else 0,
+ following=int(user_row["following"] or 0) if user_row else 0,
+ company=user_row["company"] if user_row else None,
+ location=user_row["location"] if user_row else None,
+ created_at=created_at,
+ signal_score=score,
+ signal_label=label,
+ )
+ )
+
+ return enriched
+
+
+def has_cached_dashboard_data() -> bool:
+ conn = get_connection()
+ try:
+ trends = load_trends(conn)
+ if trends.labels:
+ return True
+ cached_profile = load_cached_profile_row(conn, USERNAME or "")
+ return cached_profile is not None
+ finally:
+ conn.close()
+
+
+def trend_change_for_window(trends: Trends, days: int) -> int:
+ if not trends.labels or not trends.history:
+ return 0
+
+ latest_time = trends.labels[-1]
+ cutoff = latest_time - timedelta(days=days)
+ baseline = trends.history[0]
+ for timestamp, count in zip(trends.labels, trends.history):
+ if timestamp >= cutoff:
+ baseline = count
+ break
+ return trends.history[-1] - baseline
+
+
+def cadence_minutes(trends: Trends) -> tuple[int | None, int]:
+ if len(trends.labels) < 2:
+ return None, 0
+
+ deltas = [
+ int((current - previous).total_seconds() // 60)
+ for previous, current in zip(trends.labels, trends.labels[1:])
+ if current > previous
+ ]
+ if not deltas:
+ return None, 0
+
+ expected = max(1, int(median(deltas)))
+ missed = 0
+ for delta in deltas:
+ if delta > expected * 2:
+ missed += max(0, round(delta / expected) - 1)
+ return expected, missed
+
+
+def compute_metrics(
+ profile: GitHubProfile,
+ trends: Trends,
+ new_24h_count: int,
+ lost_24h_count: int,
+ all_new_count: int,
+ all_lost_count: int,
+) -> DashboardMetrics:
+ daily_changes = [
+ trends.history[index] - trends.history[index - 1]
+ for index in range(1, len(trends.history))
+ ]
+ average_daily_growth = round(mean(daily_changes), 2) if daily_changes else 0.0
+ volatility = pstdev(daily_changes) if len(daily_changes) > 1 else 0.0
+ volatility_score = round(min(100.0, volatility * 18), 1)
+ stability_score = round(max(0.0, 100.0 - volatility_score), 1)
+ churn_rate = round((all_lost_count / max(profile.followers, 1)) * 100, 2)
+
+ return DashboardMetrics(
+ total_followers=profile.followers,
+ following=profile.following,
+ net_24h=new_24h_count - lost_24h_count,
+ net_7d=trend_change_for_window(trends, 7),
+ net_30d=trend_change_for_window(trends, 30),
+ average_daily_growth=average_daily_growth,
+ churn_rate=churn_rate,
+ volatility_score=volatility_score,
+ stability_score=stability_score,
+ snapshot_count=len(trends.history),
+ change_records_30d=all_new_count + all_lost_count,
+ )
+
+
+def compute_health(
+ conn: sqlite3.Connection,
+ trends: Trends,
+ *,
+ partial_data: bool,
+ last_error_override: str | None = None,
+) -> DashboardHealth:
+ success_row = conn.execute(
+ "SELECT timestamp FROM sync_runs WHERE status = 'success' ORDER BY timestamp DESC LIMIT 1"
+ ).fetchone()
+ failure_row = conn.execute(
+ "SELECT timestamp, error FROM sync_runs WHERE status = 'failure' ORDER BY timestamp DESC LIMIT 1"
+ ).fetchone()
+
+ last_success = parse_datetime(success_row["timestamp"]) if success_row else None
+ last_failure = parse_datetime(failure_row["timestamp"]) if failure_row else None
+ expected_cadence, missed_snapshots = cadence_minutes(trends)
+ freshness_minutes = None
+ stale = False
+
+ if trends.labels:
+ freshness_minutes = int((utcnow() - trends.labels[-1]).total_seconds() // 60)
+ threshold = expected_cadence * 3 if expected_cadence else 720
+ stale = freshness_minutes > max(threshold, 90)
+
+ last_error = last_error_override or (failure_row["error"] if failure_row else None)
+ if not trends.labels and last_error:
+ api_status = "error"
+ elif partial_data or stale or last_error:
+ api_status = "degraded"
+ else:
+ api_status = "healthy"
+
+ return DashboardHealth(
+ api_status=api_status,
+ partial_data=partial_data,
+ stale_data=stale,
+ last_successful_sync=last_success,
+ last_failed_sync=last_failure,
+ last_error=last_error,
+ snapshot_count=len(trends.history),
+ expected_cadence_minutes=expected_cadence,
+ missed_snapshots=missed_snapshots,
+ data_freshness_minutes=freshness_minutes,
+ )
+
+
+def build_annotations(
+ trends: Trends,
+ new_24h_count: int,
+ lost_24h_count: int,
+) -> list[ChartAnnotation]:
+ annotations: list[ChartAnnotation] = []
+ if not trends.labels or not trends.history:
+ return annotations
+
+ peak_value = max(trends.history)
+ low_value = min(trends.history)
+ peak_index = max(index for index, value in enumerate(trends.history) if value == peak_value)
+ low_index = max(index for index, value in enumerate(trends.history) if value == low_value)
+
+ annotations.append(
+ ChartAnnotation(
+ timestamp=trends.labels[peak_index],
+ kind="peak",
+ label="Peak audience",
+ value=peak_value,
+ magnitude=0,
+ )
+ )
+ annotations.append(
+ ChartAnnotation(
+ timestamp=trends.labels[low_index],
+ kind="low",
+ label="Low point",
+ value=low_value,
+ magnitude=0,
+ )
+ )
+
+ if len(trends.history) > 1:
+ deltas = [trends.history[index] - trends.history[index - 1] for index in range(1, len(trends.history))]
+ max_delta = max(deltas)
+ min_delta = min(deltas)
+
+ if max_delta > 0:
+ spike_index = deltas.index(max_delta) + 1
+ annotations.append(
+ ChartAnnotation(
+ timestamp=trends.labels[spike_index],
+ kind="spike",
+ label="Biggest spike",
+ value=trends.history[spike_index],
+ magnitude=max_delta,
+ )
+ )
+ if min_delta < 0:
+ dip_index = deltas.index(min_delta) + 1
+ annotations.append(
+ ChartAnnotation(
+ timestamp=trends.labels[dip_index],
+ kind="dip",
+ label="Largest drop",
+ value=trends.history[dip_index],
+ magnitude=abs(min_delta),
+ )
+ )
+
+ latest_timestamp = trends.labels[-1]
+ latest_value = trends.history[-1]
+ if new_24h_count > 0:
+ annotations.append(
+ ChartAnnotation(
+ timestamp=latest_timestamp,
+ kind="gain",
+ label=f"{new_24h_count} gains in 24h",
+ value=latest_value,
+ magnitude=new_24h_count,
+ )
+ )
+ if lost_24h_count > 0:
+ annotations.append(
+ ChartAnnotation(
+ timestamp=latest_timestamp,
+ kind="loss",
+ label=f"{lost_24h_count} losses in 24h",
+ value=latest_value,
+ magnitude=lost_24h_count,
+ )
+ )
+
+ return annotations
+
+
+def fallback_profile(conn: sqlite3.Connection, trends: Trends) -> GitHubProfile:
+ cached = load_cached_profile_row(conn, USERNAME or "")
+ if cached:
+ return profile_from_row(cached, USERNAME)
+
+ latest_count = trends.history[-1] if trends.history else 0
+ username = USERNAME or "unknown"
+ return GitHubProfile(
+ username=username,
+ html_url=f"https://github.com/{username}",
+ followers=latest_count,
+ )
+
+
+def get_dashboard_data(*, refresh: bool = False) -> DashboardData:
+ initialize_tracker_db()
+
+ partial_data = False
+ last_error = None
+
+ should_sync = refresh or not has_cached_dashboard_data()
+ if should_sync:
+ try:
+ sync_followers(force=refresh)
+ except Exception as exc:
+ partial_data = True
+ last_error = str(exc)
+
+ conn = get_connection()
+ try:
+ trends = load_trends(conn)
+ profile = fallback_profile(conn, trends)
+ recent_cutoff = utcnow() - timedelta(hours=RECENT_WINDOW_HOURS)
+ history_cutoff = utcnow() - timedelta(days=FULL_HISTORY_DAYS)
+
+ recent_new_rows = load_changes(conn, "new_followers", since=recent_cutoff)
+ recent_lost_rows = load_changes(conn, "lost_followers", since=recent_cutoff)
+ all_new_rows = load_changes(conn, "new_followers", since=history_cutoff)
+ all_lost_rows = load_changes(conn, "lost_followers", since=history_cutoff)
+
+ recent_new = enrich_change_rows(conn, recent_new_rows, allow_fetch=refresh)
+ recent_lost = enrich_change_rows(conn, recent_lost_rows, allow_fetch=refresh)
+ all_new = enrich_change_rows(conn, all_new_rows, allow_fetch=refresh)
+ all_lost = enrich_change_rows(conn, all_lost_rows, allow_fetch=refresh)
+
+ if refresh:
+ conn.commit()
+
+ high_signal_new = sorted(
+ all_new,
+ key=lambda item: (item.signal_score, item.followers, item.public_repos),
+ reverse=True,
+ )[:5]
+
+ stats = Stats(
+ total_followers=profile.followers or (trends.history[-1] if trends.history else 0),
+ new_followers=len(recent_new),
+ unfollowers=len(recent_lost),
+ net_change=len(recent_new) - len(recent_lost),
+ )
+ metrics = compute_metrics(
+ profile,
+ trends,
+ len(recent_new),
+ len(recent_lost),
+ len(all_new),
+ len(all_lost),
+ )
+ health = compute_health(conn, trends, partial_data=partial_data, last_error_override=last_error)
+ annotations = build_annotations(trends, len(recent_new), len(recent_lost))
+
+ result = DashboardData(
+ generated_at=utcnow(),
+ profile=profile,
+ stats=stats,
+ metrics=metrics,
+ trends=trends,
+ health=health,
+ recent_new_followers=recent_new,
+ recent_lost_followers=recent_lost,
+ all_new_followers=all_new,
+ all_lost_followers=all_lost,
+ high_signal_new_followers=high_signal_new,
+ annotations=annotations,
+ )
+ return result
+ finally:
+ conn.close()
+
+
+def get_follower_stats(*, refresh: bool = False) -> Stats:
+ return get_dashboard_data(refresh=refresh).stats
+
+
+def get_github_profile(*, refresh: bool = False) -> GitHubProfile:
+ return get_dashboard_data(refresh=refresh).profile
+
+
+def get_follower_trends(*, refresh: bool = False) -> Trends:
+ return get_dashboard_data(refresh=refresh).trends
+
+
+def get_change_history(change_type: str, *, days: int = FULL_HISTORY_DAYS, refresh: bool = False) -> list[Change]:
+ if change_type == "new":
+ table = "new_followers"
+ elif change_type == "lost":
+ table = "lost_followers"
+ else:
+ raise ValueError("change_type must be 'new' or 'lost'")
+
+ sync_followers(force=refresh)
+ since = utcnow() - timedelta(days=days)
+
+ conn = get_connection()
+ try:
+ rows = load_changes(conn, table, since=since)
+ return [
+ Change(
+ username=row["username"],
+ timestamp=parse_datetime(row["timestamp"]) or utcnow(),
+ )
+ for row in rows
+ ]
+ finally:
+ conn.close()
diff --git a/utils.py b/backend/app/services/utils.py
similarity index 100%
rename from utils.py
rename to backend/app/services/utils.py
diff --git a/backend/node_modules/.bin/loose-envify b/backend/node_modules/.bin/loose-envify
new file mode 100644
index 0000000..076f91b
--- /dev/null
+++ b/backend/node_modules/.bin/loose-envify
@@ -0,0 +1,16 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+ *CYGWIN*|*MINGW*|*MSYS*)
+ if command -v cygpath > /dev/null 2>&1; then
+ basedir=`cygpath -w "$basedir"`
+ fi
+ ;;
+esac
+
+if [ -x "$basedir/node" ]; then
+ exec "$basedir/node" "$basedir/../loose-envify/cli.js" "$@"
+else
+ exec node "$basedir/../loose-envify/cli.js" "$@"
+fi
diff --git a/backend/node_modules/.bin/loose-envify.cmd b/backend/node_modules/.bin/loose-envify.cmd
new file mode 100644
index 0000000..599576f
--- /dev/null
+++ b/backend/node_modules/.bin/loose-envify.cmd
@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+ SET "_prog=%dp0%\node.exe"
+) ELSE (
+ SET "_prog=node"
+ SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\loose-envify\cli.js" %*
diff --git a/backend/node_modules/.bin/loose-envify.ps1 b/backend/node_modules/.bin/loose-envify.ps1
new file mode 100644
index 0000000..eb866fc
--- /dev/null
+++ b/backend/node_modules/.bin/loose-envify.ps1
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+ # Fix case when both the Windows and Linux builds of Node
+ # are installed in the same directory
+ $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "$basedir/node$exe" "$basedir/../loose-envify/cli.js" $args
+ } else {
+ & "$basedir/node$exe" "$basedir/../loose-envify/cli.js" $args
+ }
+ $ret=$LASTEXITCODE
+} else {
+ # Support pipeline input
+ if ($MyInvocation.ExpectingInput) {
+ $input | & "node$exe" "$basedir/../loose-envify/cli.js" $args
+ } else {
+ & "node$exe" "$basedir/../loose-envify/cli.js" $args
+ }
+ $ret=$LASTEXITCODE
+}
+exit $ret
diff --git a/backend/node_modules/.package-lock.json b/backend/node_modules/.package-lock.json
new file mode 100644
index 0000000..989f650
--- /dev/null
+++ b/backend/node_modules/.package-lock.json
@@ -0,0 +1,388 @@
+{
+ "name": "backend",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "node_modules/@babel/runtime": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz",
+ "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@types/d3-array": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz",
+ "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="
+ },
+ "node_modules/@types/d3-color": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz",
+ "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="
+ },
+ "node_modules/@types/d3-ease": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz",
+ "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="
+ },
+ "node_modules/@types/d3-interpolate": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz",
+ "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==",
+ "dependencies": {
+ "@types/d3-color": "*"
+ }
+ },
+ "node_modules/@types/d3-path": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz",
+ "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="
+ },
+ "node_modules/@types/d3-scale": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz",
+ "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==",
+ "dependencies": {
+ "@types/d3-time": "*"
+ }
+ },
+ "node_modules/@types/d3-shape": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz",
+ "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==",
+ "dependencies": {
+ "@types/d3-path": "*"
+ }
+ },
+ "node_modules/@types/d3-time": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz",
+ "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="
+ },
+ "node_modules/@types/d3-timer": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
+ "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="
+ },
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
+ },
+ "node_modules/d3-array": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
+ "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
+ "dependencies": {
+ "internmap": "1 - 2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-color": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
+ "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-ease": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
+ "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-format": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
+ "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-interpolate": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
+ "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
+ "dependencies": {
+ "d3-color": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
+ "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-scale": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
+ "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
+ "dependencies": {
+ "d3-array": "2.10.0 - 3",
+ "d3-format": "1 - 3",
+ "d3-interpolate": "1.2.0 - 3",
+ "d3-time": "2.1.1 - 3",
+ "d3-time-format": "2 - 4"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-shape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
+ "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
+ "dependencies": {
+ "d3-path": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
+ "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
+ "dependencies": {
+ "d3-array": "2 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-time-format": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
+ "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
+ "dependencies": {
+ "d3-time": "1 - 3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/d3-timer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/decimal.js-light": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
+ "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
+ },
+ "node_modules/dom-helpers": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+ "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+ "dependencies": {
+ "@babel/runtime": "^7.8.7",
+ "csstype": "^3.0.2"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ },
+ "node_modules/fast-equals": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz",
+ "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/internmap": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
+ "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "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=="
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "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==",
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/prop-types": {
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
+ "dependencies": {
+ "loose-envify": "^1.4.0",
+ "object-assign": "^4.1.1",
+ "react-is": "^16.13.1"
+ }
+ },
+ "node_modules/prop-types/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ },
+ "node_modules/react": {
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
+ "integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.1.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
+ "integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
+ "peer": true,
+ "dependencies": {
+ "scheduler": "^0.26.0"
+ },
+ "peerDependencies": {
+ "react": "^19.1.0"
+ }
+ },
+ "node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
+ },
+ "node_modules/react-smooth": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz",
+ "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==",
+ "dependencies": {
+ "fast-equals": "^5.0.1",
+ "prop-types": "^15.8.1",
+ "react-transition-group": "^4.4.5"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/react-transition-group": {
+ "version": "4.4.5",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
+ "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
+ "dependencies": {
+ "@babel/runtime": "^7.5.5",
+ "dom-helpers": "^5.0.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.6.0",
+ "react-dom": ">=16.6.0"
+ }
+ },
+ "node_modules/recharts": {
+ "version": "2.15.3",
+ "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.3.tgz",
+ "integrity": "sha512-EdOPzTwcFSuqtvkDoaM5ws/Km1+WTAO2eizL7rqiG0V2UVhTnz0m7J2i0CjVPUCdEkZImaWvXLbZDS2H5t6GFQ==",
+ "dependencies": {
+ "clsx": "^2.0.0",
+ "eventemitter3": "^4.0.1",
+ "lodash": "^4.17.21",
+ "react-is": "^18.3.1",
+ "react-smooth": "^4.0.4",
+ "recharts-scale": "^0.4.4",
+ "tiny-invariant": "^1.3.1",
+ "victory-vendor": "^36.6.8"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "peerDependencies": {
+ "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/recharts-scale": {
+ "version": "0.4.5",
+ "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
+ "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
+ "dependencies": {
+ "decimal.js-light": "^2.4.1"
+ }
+ },
+ "node_modules/scheduler": {
+ "version": "0.26.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
+ "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
+ "peer": true
+ },
+ "node_modules/tiny-invariant": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
+ },
+ "node_modules/victory-vendor": {
+ "version": "36.9.2",
+ "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz",
+ "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==",
+ "dependencies": {
+ "@types/d3-array": "^3.0.3",
+ "@types/d3-ease": "^3.0.0",
+ "@types/d3-interpolate": "^3.0.1",
+ "@types/d3-scale": "^4.0.2",
+ "@types/d3-shape": "^3.1.0",
+ "@types/d3-time": "^3.0.0",
+ "@types/d3-timer": "^3.0.0",
+ "d3-array": "^3.1.6",
+ "d3-ease": "^3.0.1",
+ "d3-interpolate": "^3.0.1",
+ "d3-scale": "^4.0.2",
+ "d3-shape": "^3.1.0",
+ "d3-time": "^3.0.0",
+ "d3-timer": "^3.0.1"
+ }
+ }
+ }
+}
diff --git a/backend/node_modules/@babel/runtime/LICENSE b/backend/node_modules/@babel/runtime/LICENSE
new file mode 100644
index 0000000..f31575e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/LICENSE
@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2014-present Sebastian McKenzie and other contributors
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/backend/node_modules/@babel/runtime/README.md b/backend/node_modules/@babel/runtime/README.md
new file mode 100644
index 0000000..2f3368e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/README.md
@@ -0,0 +1,19 @@
+# @babel/runtime
+
+> babel's modular runtime helpers
+
+See our website [@babel/runtime](https://babeljs.io/docs/babel-runtime) for more information.
+
+## Install
+
+Using npm:
+
+```sh
+npm install --save @babel/runtime
+```
+
+or using yarn:
+
+```sh
+yarn add @babel/runtime
+```
diff --git a/backend/node_modules/@babel/runtime/helpers/AwaitValue.js b/backend/node_modules/@babel/runtime/helpers/AwaitValue.js
new file mode 100644
index 0000000..52a7e69
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/AwaitValue.js
@@ -0,0 +1,4 @@
+function _AwaitValue(t) {
+ this.wrapped = t;
+}
+module.exports = _AwaitValue, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/OverloadYield.js b/backend/node_modules/@babel/runtime/helpers/OverloadYield.js
new file mode 100644
index 0000000..0eca88c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/OverloadYield.js
@@ -0,0 +1,4 @@
+function _OverloadYield(e, d) {
+ this.v = e, this.k = d;
+}
+module.exports = _OverloadYield, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/applyDecoratedDescriptor.js b/backend/node_modules/@babel/runtime/helpers/applyDecoratedDescriptor.js
new file mode 100644
index 0000000..0ff780e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/applyDecoratedDescriptor.js
@@ -0,0 +1,9 @@
+function _applyDecoratedDescriptor(i, e, r, n, l) {
+ var a = {};
+ return Object.keys(n).forEach(function (i) {
+ a[i] = n[i];
+ }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce(function (r, n) {
+ return n(i, e, r) || r;
+ }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a;
+}
+module.exports = _applyDecoratedDescriptor, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/applyDecs.js b/backend/node_modules/@babel/runtime/helpers/applyDecs.js
new file mode 100644
index 0000000..3770c5a
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/applyDecs.js
@@ -0,0 +1,236 @@
+var _typeof = require("./typeof.js")["default"];
+var setFunctionName = require("./setFunctionName.js");
+var toPropertyKey = require("./toPropertyKey.js");
+function old_createMetadataMethodsForProperty(e, t, a, r) {
+ return {
+ getMetadata: function getMetadata(o) {
+ old_assertNotFinished(r, "getMetadata"), old_assertMetadataKey(o);
+ var i = e[o];
+ if (void 0 !== i) if (1 === t) {
+ var n = i["public"];
+ if (void 0 !== n) return n[a];
+ } else if (2 === t) {
+ var l = i["private"];
+ if (void 0 !== l) return l.get(a);
+ } else if (Object.hasOwnProperty.call(i, "constructor")) return i.constructor;
+ },
+ setMetadata: function setMetadata(o, i) {
+ old_assertNotFinished(r, "setMetadata"), old_assertMetadataKey(o);
+ var n = e[o];
+ if (void 0 === n && (n = e[o] = {}), 1 === t) {
+ var l = n["public"];
+ void 0 === l && (l = n["public"] = {}), l[a] = i;
+ } else if (2 === t) {
+ var s = n.priv;
+ void 0 === s && (s = n["private"] = new Map()), s.set(a, i);
+ } else n.constructor = i;
+ }
+ };
+}
+function old_convertMetadataMapToFinal(e, t) {
+ var a = e[Symbol.metadata || Symbol["for"]("Symbol.metadata")],
+ r = Object.getOwnPropertySymbols(t);
+ if (0 !== r.length) {
+ for (var o = 0; o < r.length; o++) {
+ var i = r[o],
+ n = t[i],
+ l = a ? a[i] : null,
+ s = n["public"],
+ c = l ? l["public"] : null;
+ s && c && Object.setPrototypeOf(s, c);
+ var d = n["private"];
+ if (d) {
+ var u = Array.from(d.values()),
+ f = l ? l["private"] : null;
+ f && (u = u.concat(f)), n["private"] = u;
+ }
+ l && Object.setPrototypeOf(n, l);
+ }
+ a && Object.setPrototypeOf(t, a), e[Symbol.metadata || Symbol["for"]("Symbol.metadata")] = t;
+ }
+}
+function old_createAddInitializerMethod(e, t) {
+ return function (a) {
+ old_assertNotFinished(t, "addInitializer"), old_assertCallable(a, "An initializer"), e.push(a);
+ };
+}
+function old_memberDec(e, t, a, r, o, i, n, l, s) {
+ var c;
+ switch (i) {
+ case 1:
+ c = "accessor";
+ break;
+ case 2:
+ c = "method";
+ break;
+ case 3:
+ c = "getter";
+ break;
+ case 4:
+ c = "setter";
+ break;
+ default:
+ c = "field";
+ }
+ var d,
+ u,
+ f = {
+ kind: c,
+ name: l ? "#" + t : toPropertyKey(t),
+ isStatic: n,
+ isPrivate: l
+ },
+ p = {
+ v: !1
+ };
+ if (0 !== i && (f.addInitializer = old_createAddInitializerMethod(o, p)), l) {
+ d = 2, u = Symbol(t);
+ var v = {};
+ 0 === i ? (v.get = a.get, v.set = a.set) : 2 === i ? v.get = function () {
+ return a.value;
+ } : (1 !== i && 3 !== i || (v.get = function () {
+ return a.get.call(this);
+ }), 1 !== i && 4 !== i || (v.set = function (e) {
+ a.set.call(this, e);
+ })), f.access = v;
+ } else d = 1, u = t;
+ try {
+ return e(s, Object.assign(f, old_createMetadataMethodsForProperty(r, d, u, p)));
+ } finally {
+ p.v = !0;
+ }
+}
+function old_assertNotFinished(e, t) {
+ if (e.v) throw Error("attempted to call " + t + " after decoration was finished");
+}
+function old_assertMetadataKey(e) {
+ if ("symbol" != _typeof(e)) throw new TypeError("Metadata keys must be symbols, received: " + e);
+}
+function old_assertCallable(e, t) {
+ if ("function" != typeof e) throw new TypeError(t + " must be a function");
+}
+function old_assertValidReturnValue(e, t) {
+ var a = _typeof(t);
+ if (1 === e) {
+ if ("object" !== a || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ void 0 !== t.get && old_assertCallable(t.get, "accessor.get"), void 0 !== t.set && old_assertCallable(t.set, "accessor.set"), void 0 !== t.init && old_assertCallable(t.init, "accessor.init"), void 0 !== t.initializer && old_assertCallable(t.initializer, "accessor.initializer");
+ } else if ("function" !== a) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
+}
+function old_getInit(e) {
+ var t;
+ return null == (t = e.init) && (t = e.initializer) && void 0 !== console && console.warn(".initializer has been renamed to .init as of March 2022"), t;
+}
+function old_applyMemberDec(e, t, a, r, o, i, n, l, s) {
+ var c,
+ d,
+ u,
+ f,
+ p,
+ v,
+ y,
+ h = a[0];
+ if (n ? (0 === o || 1 === o ? (c = {
+ get: a[3],
+ set: a[4]
+ }, u = "get") : 3 === o ? (c = {
+ get: a[3]
+ }, u = "get") : 4 === o ? (c = {
+ set: a[3]
+ }, u = "set") : c = {
+ value: a[3]
+ }, 0 !== o && (1 === o && setFunctionName(a[4], "#" + r, "set"), setFunctionName(a[3], "#" + r, u))) : 0 !== o && (c = Object.getOwnPropertyDescriptor(t, r)), 1 === o ? f = {
+ get: c.get,
+ set: c.set
+ } : 2 === o ? f = c.value : 3 === o ? f = c.get : 4 === o && (f = c.set), "function" == typeof h) void 0 !== (p = old_memberDec(h, r, c, l, s, o, i, n, f)) && (old_assertValidReturnValue(o, p), 0 === o ? d = p : 1 === o ? (d = old_getInit(p), v = p.get || f.get, y = p.set || f.set, f = {
+ get: v,
+ set: y
+ }) : f = p);else for (var m = h.length - 1; m >= 0; m--) {
+ var b;
+ void 0 !== (p = old_memberDec(h[m], r, c, l, s, o, i, n, f)) && (old_assertValidReturnValue(o, p), 0 === o ? b = p : 1 === o ? (b = old_getInit(p), v = p.get || f.get, y = p.set || f.set, f = {
+ get: v,
+ set: y
+ }) : f = p, void 0 !== b && (void 0 === d ? d = b : "function" == typeof d ? d = [d, b] : d.push(b)));
+ }
+ if (0 === o || 1 === o) {
+ if (void 0 === d) d = function d(e, t) {
+ return t;
+ };else if ("function" != typeof d) {
+ var g = d;
+ d = function d(e, t) {
+ for (var a = t, r = 0; r < g.length; r++) a = g[r].call(e, a);
+ return a;
+ };
+ } else {
+ var _ = d;
+ d = function d(e, t) {
+ return _.call(e, t);
+ };
+ }
+ e.push(d);
+ }
+ 0 !== o && (1 === o ? (c.get = f.get, c.set = f.set) : 2 === o ? c.value = f : 3 === o ? c.get = f : 4 === o && (c.set = f), n ? 1 === o ? (e.push(function (e, t) {
+ return f.get.call(e, t);
+ }), e.push(function (e, t) {
+ return f.set.call(e, t);
+ })) : 2 === o ? e.push(f) : e.push(function (e, t) {
+ return f.call(e, t);
+ }) : Object.defineProperty(t, r, c));
+}
+function old_applyMemberDecs(e, t, a, r, o) {
+ for (var i, n, l = new Map(), s = new Map(), c = 0; c < o.length; c++) {
+ var d = o[c];
+ if (Array.isArray(d)) {
+ var u,
+ f,
+ p,
+ v = d[1],
+ y = d[2],
+ h = d.length > 3,
+ m = v >= 5;
+ if (m ? (u = t, f = r, 0 != (v -= 5) && (p = n = n || [])) : (u = t.prototype, f = a, 0 !== v && (p = i = i || [])), 0 !== v && !h) {
+ var b = m ? s : l,
+ g = b.get(y) || 0;
+ if (!0 === g || 3 === g && 4 !== v || 4 === g && 3 !== v) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + y);
+ !g && v > 2 ? b.set(y, v) : b.set(y, !0);
+ }
+ old_applyMemberDec(e, u, d, y, v, m, h, f, p);
+ }
+ }
+ old_pushInitializers(e, i), old_pushInitializers(e, n);
+}
+function old_pushInitializers(e, t) {
+ t && e.push(function (e) {
+ for (var a = 0; a < t.length; a++) t[a].call(e);
+ return e;
+ });
+}
+function old_applyClassDecs(e, t, a, r) {
+ if (r.length > 0) {
+ for (var o = [], i = t, n = t.name, l = r.length - 1; l >= 0; l--) {
+ var s = {
+ v: !1
+ };
+ try {
+ var c = Object.assign({
+ kind: "class",
+ name: n,
+ addInitializer: old_createAddInitializerMethod(o, s)
+ }, old_createMetadataMethodsForProperty(a, 0, n, s)),
+ d = r[l](i, c);
+ } finally {
+ s.v = !0;
+ }
+ void 0 !== d && (old_assertValidReturnValue(10, d), i = d);
+ }
+ e.push(i, function () {
+ for (var e = 0; e < o.length; e++) o[e].call(i);
+ });
+ }
+}
+function applyDecs(e, t, a) {
+ var r = [],
+ o = {},
+ i = {};
+ return old_applyMemberDecs(r, e, i, o, t), old_convertMetadataMapToFinal(e.prototype, i), old_applyClassDecs(r, e, o, a), old_convertMetadataMapToFinal(e, o), r;
+}
+module.exports = applyDecs, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/applyDecs2203.js b/backend/node_modules/@babel/runtime/helpers/applyDecs2203.js
new file mode 100644
index 0000000..d3da333
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/applyDecs2203.js
@@ -0,0 +1,184 @@
+var _typeof = require("./typeof.js")["default"];
+function applyDecs2203Factory() {
+ function createAddInitializerMethod(e, t) {
+ return function (r) {
+ !function (e, t) {
+ if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
+ }(t), assertCallable(r, "An initializer"), e.push(r);
+ };
+ }
+ function memberDec(e, t, r, a, n, i, s, o) {
+ var c;
+ switch (n) {
+ case 1:
+ c = "accessor";
+ break;
+ case 2:
+ c = "method";
+ break;
+ case 3:
+ c = "getter";
+ break;
+ case 4:
+ c = "setter";
+ break;
+ default:
+ c = "field";
+ }
+ var l,
+ u,
+ f = {
+ kind: c,
+ name: s ? "#" + t : t,
+ "static": i,
+ "private": s
+ },
+ p = {
+ v: !1
+ };
+ 0 !== n && (f.addInitializer = createAddInitializerMethod(a, p)), 0 === n ? s ? (l = r.get, u = r.set) : (l = function l() {
+ return this[t];
+ }, u = function u(e) {
+ this[t] = e;
+ }) : 2 === n ? l = function l() {
+ return r.value;
+ } : (1 !== n && 3 !== n || (l = function l() {
+ return r.get.call(this);
+ }), 1 !== n && 4 !== n || (u = function u(e) {
+ r.set.call(this, e);
+ })), f.access = l && u ? {
+ get: l,
+ set: u
+ } : l ? {
+ get: l
+ } : {
+ set: u
+ };
+ try {
+ return e(o, f);
+ } finally {
+ p.v = !0;
+ }
+ }
+ function assertCallable(e, t) {
+ if ("function" != typeof e) throw new TypeError(t + " must be a function");
+ }
+ function assertValidReturnValue(e, t) {
+ var r = _typeof(t);
+ if (1 === e) {
+ if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
+ } else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
+ }
+ function applyMemberDec(e, t, r, a, n, i, s, o) {
+ var c,
+ l,
+ u,
+ f,
+ p,
+ d,
+ h = r[0];
+ if (s ? c = 0 === n || 1 === n ? {
+ get: r[3],
+ set: r[4]
+ } : 3 === n ? {
+ get: r[3]
+ } : 4 === n ? {
+ set: r[3]
+ } : {
+ value: r[3]
+ } : 0 !== n && (c = Object.getOwnPropertyDescriptor(t, a)), 1 === n ? u = {
+ get: c.get,
+ set: c.set
+ } : 2 === n ? u = c.value : 3 === n ? u = c.get : 4 === n && (u = c.set), "function" == typeof h) void 0 !== (f = memberDec(h, a, c, o, n, i, s, u)) && (assertValidReturnValue(n, f), 0 === n ? l = f : 1 === n ? (l = f.init, p = f.get || u.get, d = f.set || u.set, u = {
+ get: p,
+ set: d
+ }) : u = f);else for (var v = h.length - 1; v >= 0; v--) {
+ var g;
+ void 0 !== (f = memberDec(h[v], a, c, o, n, i, s, u)) && (assertValidReturnValue(n, f), 0 === n ? g = f : 1 === n ? (g = f.init, p = f.get || u.get, d = f.set || u.set, u = {
+ get: p,
+ set: d
+ }) : u = f, void 0 !== g && (void 0 === l ? l = g : "function" == typeof l ? l = [l, g] : l.push(g)));
+ }
+ if (0 === n || 1 === n) {
+ if (void 0 === l) l = function l(e, t) {
+ return t;
+ };else if ("function" != typeof l) {
+ var y = l;
+ l = function l(e, t) {
+ for (var r = t, a = 0; a < y.length; a++) r = y[a].call(e, r);
+ return r;
+ };
+ } else {
+ var m = l;
+ l = function l(e, t) {
+ return m.call(e, t);
+ };
+ }
+ e.push(l);
+ }
+ 0 !== n && (1 === n ? (c.get = u.get, c.set = u.set) : 2 === n ? c.value = u : 3 === n ? c.get = u : 4 === n && (c.set = u), s ? 1 === n ? (e.push(function (e, t) {
+ return u.get.call(e, t);
+ }), e.push(function (e, t) {
+ return u.set.call(e, t);
+ })) : 2 === n ? e.push(u) : e.push(function (e, t) {
+ return u.call(e, t);
+ }) : Object.defineProperty(t, a, c));
+ }
+ function pushInitializers(e, t) {
+ t && e.push(function (e) {
+ for (var r = 0; r < t.length; r++) t[r].call(e);
+ return e;
+ });
+ }
+ return function (e, t, r) {
+ var a = [];
+ return function (e, t, r) {
+ for (var a, n, i = new Map(), s = new Map(), o = 0; o < r.length; o++) {
+ var c = r[o];
+ if (Array.isArray(c)) {
+ var l,
+ u,
+ f = c[1],
+ p = c[2],
+ d = c.length > 3,
+ h = f >= 5;
+ if (h ? (l = t, 0 != (f -= 5) && (u = n = n || [])) : (l = t.prototype, 0 !== f && (u = a = a || [])), 0 !== f && !d) {
+ var v = h ? s : i,
+ g = v.get(p) || 0;
+ if (!0 === g || 3 === g && 4 !== f || 4 === g && 3 !== f) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + p);
+ !g && f > 2 ? v.set(p, f) : v.set(p, !0);
+ }
+ applyMemberDec(e, l, c, p, f, h, d, u);
+ }
+ }
+ pushInitializers(e, a), pushInitializers(e, n);
+ }(a, e, t), function (e, t, r) {
+ if (r.length > 0) {
+ for (var a = [], n = t, i = t.name, s = r.length - 1; s >= 0; s--) {
+ var o = {
+ v: !1
+ };
+ try {
+ var c = r[s](n, {
+ kind: "class",
+ name: i,
+ addInitializer: createAddInitializerMethod(a, o)
+ });
+ } finally {
+ o.v = !0;
+ }
+ void 0 !== c && (assertValidReturnValue(10, c), n = c);
+ }
+ e.push(n, function () {
+ for (var e = 0; e < a.length; e++) a[e].call(n);
+ });
+ }
+ }(a, e, r), a;
+ };
+}
+var applyDecs2203Impl;
+function applyDecs2203(e, t, r) {
+ return (applyDecs2203Impl = applyDecs2203Impl || applyDecs2203Factory())(e, t, r);
+}
+module.exports = applyDecs2203, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/applyDecs2203R.js b/backend/node_modules/@babel/runtime/helpers/applyDecs2203R.js
new file mode 100644
index 0000000..725419b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/applyDecs2203R.js
@@ -0,0 +1,191 @@
+var _typeof = require("./typeof.js")["default"];
+var setFunctionName = require("./setFunctionName.js");
+var toPropertyKey = require("./toPropertyKey.js");
+function applyDecs2203RFactory() {
+ function createAddInitializerMethod(e, t) {
+ return function (r) {
+ !function (e, t) {
+ if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
+ }(t), assertCallable(r, "An initializer"), e.push(r);
+ };
+ }
+ function memberDec(e, t, r, n, a, i, o, s) {
+ var c;
+ switch (a) {
+ case 1:
+ c = "accessor";
+ break;
+ case 2:
+ c = "method";
+ break;
+ case 3:
+ c = "getter";
+ break;
+ case 4:
+ c = "setter";
+ break;
+ default:
+ c = "field";
+ }
+ var l,
+ u,
+ f = {
+ kind: c,
+ name: o ? "#" + t : toPropertyKey(t),
+ "static": i,
+ "private": o
+ },
+ p = {
+ v: !1
+ };
+ 0 !== a && (f.addInitializer = createAddInitializerMethod(n, p)), 0 === a ? o ? (l = r.get, u = r.set) : (l = function l() {
+ return this[t];
+ }, u = function u(e) {
+ this[t] = e;
+ }) : 2 === a ? l = function l() {
+ return r.value;
+ } : (1 !== a && 3 !== a || (l = function l() {
+ return r.get.call(this);
+ }), 1 !== a && 4 !== a || (u = function u(e) {
+ r.set.call(this, e);
+ })), f.access = l && u ? {
+ get: l,
+ set: u
+ } : l ? {
+ get: l
+ } : {
+ set: u
+ };
+ try {
+ return e(s, f);
+ } finally {
+ p.v = !0;
+ }
+ }
+ function assertCallable(e, t) {
+ if ("function" != typeof e) throw new TypeError(t + " must be a function");
+ }
+ function assertValidReturnValue(e, t) {
+ var r = _typeof(t);
+ if (1 === e) {
+ if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
+ } else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
+ }
+ function applyMemberDec(e, t, r, n, a, i, o, s) {
+ var c,
+ l,
+ u,
+ f,
+ p,
+ d,
+ h,
+ v = r[0];
+ if (o ? (0 === a || 1 === a ? (c = {
+ get: r[3],
+ set: r[4]
+ }, u = "get") : 3 === a ? (c = {
+ get: r[3]
+ }, u = "get") : 4 === a ? (c = {
+ set: r[3]
+ }, u = "set") : c = {
+ value: r[3]
+ }, 0 !== a && (1 === a && setFunctionName(r[4], "#" + n, "set"), setFunctionName(r[3], "#" + n, u))) : 0 !== a && (c = Object.getOwnPropertyDescriptor(t, n)), 1 === a ? f = {
+ get: c.get,
+ set: c.set
+ } : 2 === a ? f = c.value : 3 === a ? f = c.get : 4 === a && (f = c.set), "function" == typeof v) void 0 !== (p = memberDec(v, n, c, s, a, i, o, f)) && (assertValidReturnValue(a, p), 0 === a ? l = p : 1 === a ? (l = p.init, d = p.get || f.get, h = p.set || f.set, f = {
+ get: d,
+ set: h
+ }) : f = p);else for (var g = v.length - 1; g >= 0; g--) {
+ var y;
+ void 0 !== (p = memberDec(v[g], n, c, s, a, i, o, f)) && (assertValidReturnValue(a, p), 0 === a ? y = p : 1 === a ? (y = p.init, d = p.get || f.get, h = p.set || f.set, f = {
+ get: d,
+ set: h
+ }) : f = p, void 0 !== y && (void 0 === l ? l = y : "function" == typeof l ? l = [l, y] : l.push(y)));
+ }
+ if (0 === a || 1 === a) {
+ if (void 0 === l) l = function l(e, t) {
+ return t;
+ };else if ("function" != typeof l) {
+ var m = l;
+ l = function l(e, t) {
+ for (var r = t, n = 0; n < m.length; n++) r = m[n].call(e, r);
+ return r;
+ };
+ } else {
+ var b = l;
+ l = function l(e, t) {
+ return b.call(e, t);
+ };
+ }
+ e.push(l);
+ }
+ 0 !== a && (1 === a ? (c.get = f.get, c.set = f.set) : 2 === a ? c.value = f : 3 === a ? c.get = f : 4 === a && (c.set = f), o ? 1 === a ? (e.push(function (e, t) {
+ return f.get.call(e, t);
+ }), e.push(function (e, t) {
+ return f.set.call(e, t);
+ })) : 2 === a ? e.push(f) : e.push(function (e, t) {
+ return f.call(e, t);
+ }) : Object.defineProperty(t, n, c));
+ }
+ function applyMemberDecs(e, t) {
+ for (var r, n, a = [], i = new Map(), o = new Map(), s = 0; s < t.length; s++) {
+ var c = t[s];
+ if (Array.isArray(c)) {
+ var l,
+ u,
+ f = c[1],
+ p = c[2],
+ d = c.length > 3,
+ h = f >= 5;
+ if (h ? (l = e, 0 != (f -= 5) && (u = n = n || [])) : (l = e.prototype, 0 !== f && (u = r = r || [])), 0 !== f && !d) {
+ var v = h ? o : i,
+ g = v.get(p) || 0;
+ if (!0 === g || 3 === g && 4 !== f || 4 === g && 3 !== f) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + p);
+ !g && f > 2 ? v.set(p, f) : v.set(p, !0);
+ }
+ applyMemberDec(a, l, c, p, f, h, d, u);
+ }
+ }
+ return pushInitializers(a, r), pushInitializers(a, n), a;
+ }
+ function pushInitializers(e, t) {
+ t && e.push(function (e) {
+ for (var r = 0; r < t.length; r++) t[r].call(e);
+ return e;
+ });
+ }
+ return function (e, t, r) {
+ return {
+ e: applyMemberDecs(e, t),
+ get c() {
+ return function (e, t) {
+ if (t.length > 0) {
+ for (var r = [], n = e, a = e.name, i = t.length - 1; i >= 0; i--) {
+ var o = {
+ v: !1
+ };
+ try {
+ var s = t[i](n, {
+ kind: "class",
+ name: a,
+ addInitializer: createAddInitializerMethod(r, o)
+ });
+ } finally {
+ o.v = !0;
+ }
+ void 0 !== s && (assertValidReturnValue(10, s), n = s);
+ }
+ return [n, function () {
+ for (var e = 0; e < r.length; e++) r[e].call(n);
+ }];
+ }
+ }(e, r);
+ }
+ };
+ };
+}
+function applyDecs2203R(e, t, r) {
+ return (module.exports = applyDecs2203R = applyDecs2203RFactory(), module.exports.__esModule = true, module.exports["default"] = module.exports)(e, t, r);
+}
+module.exports = applyDecs2203R, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/applyDecs2301.js b/backend/node_modules/@babel/runtime/helpers/applyDecs2301.js
new file mode 100644
index 0000000..fc2c130
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/applyDecs2301.js
@@ -0,0 +1,222 @@
+var _typeof = require("./typeof.js")["default"];
+var checkInRHS = require("./checkInRHS.js");
+var setFunctionName = require("./setFunctionName.js");
+var toPropertyKey = require("./toPropertyKey.js");
+function applyDecs2301Factory() {
+ function createAddInitializerMethod(e, t) {
+ return function (r) {
+ !function (e, t) {
+ if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
+ }(t), assertCallable(r, "An initializer"), e.push(r);
+ };
+ }
+ function assertInstanceIfPrivate(e, t) {
+ if (!e(t)) throw new TypeError("Attempted to access private element on non-instance");
+ }
+ function memberDec(e, t, r, n, a, i, s, o, c) {
+ var u;
+ switch (a) {
+ case 1:
+ u = "accessor";
+ break;
+ case 2:
+ u = "method";
+ break;
+ case 3:
+ u = "getter";
+ break;
+ case 4:
+ u = "setter";
+ break;
+ default:
+ u = "field";
+ }
+ var l,
+ f,
+ p = {
+ kind: u,
+ name: s ? "#" + t : toPropertyKey(t),
+ "static": i,
+ "private": s
+ },
+ d = {
+ v: !1
+ };
+ if (0 !== a && (p.addInitializer = createAddInitializerMethod(n, d)), s || 0 !== a && 2 !== a) {
+ if (2 === a) l = function l(e) {
+ return assertInstanceIfPrivate(c, e), r.value;
+ };else {
+ var h = 0 === a || 1 === a;
+ (h || 3 === a) && (l = s ? function (e) {
+ return assertInstanceIfPrivate(c, e), r.get.call(e);
+ } : function (e) {
+ return r.get.call(e);
+ }), (h || 4 === a) && (f = s ? function (e, t) {
+ assertInstanceIfPrivate(c, e), r.set.call(e, t);
+ } : function (e, t) {
+ r.set.call(e, t);
+ });
+ }
+ } else l = function l(e) {
+ return e[t];
+ }, 0 === a && (f = function f(e, r) {
+ e[t] = r;
+ });
+ var v = s ? c.bind() : function (e) {
+ return t in e;
+ };
+ p.access = l && f ? {
+ get: l,
+ set: f,
+ has: v
+ } : l ? {
+ get: l,
+ has: v
+ } : {
+ set: f,
+ has: v
+ };
+ try {
+ return e(o, p);
+ } finally {
+ d.v = !0;
+ }
+ }
+ function assertCallable(e, t) {
+ if ("function" != typeof e) throw new TypeError(t + " must be a function");
+ }
+ function assertValidReturnValue(e, t) {
+ var r = _typeof(t);
+ if (1 === e) {
+ if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
+ } else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
+ }
+ function curryThis2(e) {
+ return function (t) {
+ e(this, t);
+ };
+ }
+ function applyMemberDec(e, t, r, n, a, i, s, o, c) {
+ var u,
+ l,
+ f,
+ p,
+ d,
+ h,
+ v,
+ y,
+ g = r[0];
+ if (s ? (0 === a || 1 === a ? (u = {
+ get: (d = r[3], function () {
+ return d(this);
+ }),
+ set: curryThis2(r[4])
+ }, f = "get") : 3 === a ? (u = {
+ get: r[3]
+ }, f = "get") : 4 === a ? (u = {
+ set: r[3]
+ }, f = "set") : u = {
+ value: r[3]
+ }, 0 !== a && (1 === a && setFunctionName(u.set, "#" + n, "set"), setFunctionName(u[f || "value"], "#" + n, f))) : 0 !== a && (u = Object.getOwnPropertyDescriptor(t, n)), 1 === a ? p = {
+ get: u.get,
+ set: u.set
+ } : 2 === a ? p = u.value : 3 === a ? p = u.get : 4 === a && (p = u.set), "function" == typeof g) void 0 !== (h = memberDec(g, n, u, o, a, i, s, p, c)) && (assertValidReturnValue(a, h), 0 === a ? l = h : 1 === a ? (l = h.init, v = h.get || p.get, y = h.set || p.set, p = {
+ get: v,
+ set: y
+ }) : p = h);else for (var m = g.length - 1; m >= 0; m--) {
+ var b;
+ void 0 !== (h = memberDec(g[m], n, u, o, a, i, s, p, c)) && (assertValidReturnValue(a, h), 0 === a ? b = h : 1 === a ? (b = h.init, v = h.get || p.get, y = h.set || p.set, p = {
+ get: v,
+ set: y
+ }) : p = h, void 0 !== b && (void 0 === l ? l = b : "function" == typeof l ? l = [l, b] : l.push(b)));
+ }
+ if (0 === a || 1 === a) {
+ if (void 0 === l) l = function l(e, t) {
+ return t;
+ };else if ("function" != typeof l) {
+ var I = l;
+ l = function l(e, t) {
+ for (var r = t, n = 0; n < I.length; n++) r = I[n].call(e, r);
+ return r;
+ };
+ } else {
+ var w = l;
+ l = function l(e, t) {
+ return w.call(e, t);
+ };
+ }
+ e.push(l);
+ }
+ 0 !== a && (1 === a ? (u.get = p.get, u.set = p.set) : 2 === a ? u.value = p : 3 === a ? u.get = p : 4 === a && (u.set = p), s ? 1 === a ? (e.push(function (e, t) {
+ return p.get.call(e, t);
+ }), e.push(function (e, t) {
+ return p.set.call(e, t);
+ })) : 2 === a ? e.push(p) : e.push(function (e, t) {
+ return p.call(e, t);
+ }) : Object.defineProperty(t, n, u));
+ }
+ function applyMemberDecs(e, t, r) {
+ for (var n, a, i, s = [], o = new Map(), c = new Map(), u = 0; u < t.length; u++) {
+ var l = t[u];
+ if (Array.isArray(l)) {
+ var f,
+ p,
+ d = l[1],
+ h = l[2],
+ v = l.length > 3,
+ y = d >= 5,
+ g = r;
+ if (y ? (f = e, 0 != (d -= 5) && (p = a = a || []), v && !i && (i = function i(t) {
+ return checkInRHS(t) === e;
+ }), g = i) : (f = e.prototype, 0 !== d && (p = n = n || [])), 0 !== d && !v) {
+ var m = y ? c : o,
+ b = m.get(h) || 0;
+ if (!0 === b || 3 === b && 4 !== d || 4 === b && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h);
+ !b && d > 2 ? m.set(h, d) : m.set(h, !0);
+ }
+ applyMemberDec(s, f, l, h, d, y, v, p, g);
+ }
+ }
+ return pushInitializers(s, n), pushInitializers(s, a), s;
+ }
+ function pushInitializers(e, t) {
+ t && e.push(function (e) {
+ for (var r = 0; r < t.length; r++) t[r].call(e);
+ return e;
+ });
+ }
+ return function (e, t, r, n) {
+ return {
+ e: applyMemberDecs(e, t, n),
+ get c() {
+ return function (e, t) {
+ if (t.length > 0) {
+ for (var r = [], n = e, a = e.name, i = t.length - 1; i >= 0; i--) {
+ var s = {
+ v: !1
+ };
+ try {
+ var o = t[i](n, {
+ kind: "class",
+ name: a,
+ addInitializer: createAddInitializerMethod(r, s)
+ });
+ } finally {
+ s.v = !0;
+ }
+ void 0 !== o && (assertValidReturnValue(10, o), n = o);
+ }
+ return [n, function () {
+ for (var e = 0; e < r.length; e++) r[e].call(n);
+ }];
+ }
+ }(e, r);
+ }
+ };
+ };
+}
+function applyDecs2301(e, t, r, n) {
+ return (module.exports = applyDecs2301 = applyDecs2301Factory(), module.exports.__esModule = true, module.exports["default"] = module.exports)(e, t, r, n);
+}
+module.exports = applyDecs2301, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/applyDecs2305.js b/backend/node_modules/@babel/runtime/helpers/applyDecs2305.js
new file mode 100644
index 0000000..744c352
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/applyDecs2305.js
@@ -0,0 +1,133 @@
+var _typeof = require("./typeof.js")["default"];
+var checkInRHS = require("./checkInRHS.js");
+var setFunctionName = require("./setFunctionName.js");
+var toPropertyKey = require("./toPropertyKey.js");
+function applyDecs2305(e, t, r, n, o, a) {
+ function i(e, t, r) {
+ return function (n, o) {
+ return r && r(n), e[t].call(n, o);
+ };
+ }
+ function c(e, t) {
+ for (var r = 0; r < e.length; r++) e[r].call(t);
+ return t;
+ }
+ function s(e, t, r, n) {
+ if ("function" != typeof e && (n || void 0 !== e)) throw new TypeError(t + " must " + (r || "be") + " a function" + (n ? "" : " or undefined"));
+ return e;
+ }
+ function applyDec(e, t, r, n, o, a, c, u, l, f, p, d, h) {
+ function m(e) {
+ if (!h(e)) throw new TypeError("Attempted to access private element on non-instance");
+ }
+ var y,
+ v = t[0],
+ g = t[3],
+ b = !u;
+ if (!b) {
+ r || Array.isArray(v) || (v = [v]);
+ var w = {},
+ S = [],
+ A = 3 === o ? "get" : 4 === o || d ? "set" : "value";
+ f ? (p || d ? w = {
+ get: setFunctionName(function () {
+ return g(this);
+ }, n, "get"),
+ set: function set(e) {
+ t[4](this, e);
+ }
+ } : w[A] = g, p || setFunctionName(w[A], n, 2 === o ? "" : A)) : p || (w = Object.getOwnPropertyDescriptor(e, n));
+ }
+ for (var P = e, j = v.length - 1; j >= 0; j -= r ? 2 : 1) {
+ var D = v[j],
+ E = r ? v[j - 1] : void 0,
+ I = {},
+ O = {
+ kind: ["field", "accessor", "method", "getter", "setter", "class"][o],
+ name: n,
+ metadata: a,
+ addInitializer: function (e, t) {
+ if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
+ s(t, "An initializer", "be", !0), c.push(t);
+ }.bind(null, I)
+ };
+ try {
+ if (b) (y = s(D.call(E, P, O), "class decorators", "return")) && (P = y);else {
+ var k, F;
+ O["static"] = l, O["private"] = f, f ? 2 === o ? k = function k(e) {
+ return m(e), w.value;
+ } : (o < 4 && (k = i(w, "get", m)), 3 !== o && (F = i(w, "set", m))) : (k = function k(e) {
+ return e[n];
+ }, (o < 2 || 4 === o) && (F = function F(e, t) {
+ e[n] = t;
+ }));
+ var N = O.access = {
+ has: f ? h.bind() : function (e) {
+ return n in e;
+ }
+ };
+ if (k && (N.get = k), F && (N.set = F), P = D.call(E, d ? {
+ get: w.get,
+ set: w.set
+ } : w[A], O), d) {
+ if ("object" == _typeof(P) && P) (y = s(P.get, "accessor.get")) && (w.get = y), (y = s(P.set, "accessor.set")) && (w.set = y), (y = s(P.init, "accessor.init")) && S.push(y);else if (void 0 !== P) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ } else s(P, (p ? "field" : "method") + " decorators", "return") && (p ? S.push(P) : w[A] = P);
+ }
+ } finally {
+ I.v = !0;
+ }
+ }
+ return (p || d) && u.push(function (e, t) {
+ for (var r = S.length - 1; r >= 0; r--) t = S[r].call(e, t);
+ return t;
+ }), p || b || (f ? d ? u.push(i(w, "get"), i(w, "set")) : u.push(2 === o ? w[A] : i.call.bind(w[A])) : Object.defineProperty(e, n, w)), P;
+ }
+ function u(e, t) {
+ return Object.defineProperty(e, Symbol.metadata || Symbol["for"]("Symbol.metadata"), {
+ configurable: !0,
+ enumerable: !0,
+ value: t
+ });
+ }
+ if (arguments.length >= 6) var l = a[Symbol.metadata || Symbol["for"]("Symbol.metadata")];
+ var f = Object.create(null == l ? null : l),
+ p = function (e, t, r, n) {
+ var o,
+ a,
+ i = [],
+ s = function s(t) {
+ return checkInRHS(t) === e;
+ },
+ u = new Map();
+ function l(e) {
+ e && i.push(c.bind(null, e));
+ }
+ for (var f = 0; f < t.length; f++) {
+ var p = t[f];
+ if (Array.isArray(p)) {
+ var d = p[1],
+ h = p[2],
+ m = p.length > 3,
+ y = 16 & d,
+ v = !!(8 & d),
+ g = 0 == (d &= 7),
+ b = h + "/" + v;
+ if (!g && !m) {
+ var w = u.get(b);
+ if (!0 === w || 3 === w && 4 !== d || 4 === w && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h);
+ u.set(b, !(d > 2) || d);
+ }
+ applyDec(v ? e : e.prototype, p, y, m ? "#" + h : toPropertyKey(h), d, n, v ? a = a || [] : o = o || [], i, v, m, g, 1 === d, v && m ? s : r);
+ }
+ }
+ return l(o), l(a), i;
+ }(e, t, o, f);
+ return r.length || u(e, f), {
+ e: p,
+ get c() {
+ var t = [];
+ return r.length && [u(applyDec(e, [r], n, e.name, 5, f, t), f), c.bind(null, t, e)];
+ }
+ };
+}
+module.exports = applyDecs2305, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/applyDecs2311.js b/backend/node_modules/@babel/runtime/helpers/applyDecs2311.js
new file mode 100644
index 0000000..5f00a31
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/applyDecs2311.js
@@ -0,0 +1,124 @@
+var _typeof = require("./typeof.js")["default"];
+var checkInRHS = require("./checkInRHS.js");
+var setFunctionName = require("./setFunctionName.js");
+var toPropertyKey = require("./toPropertyKey.js");
+function applyDecs2311(e, t, n, r, o, i) {
+ var a,
+ c,
+ u,
+ s,
+ f,
+ l,
+ p,
+ d = Symbol.metadata || Symbol["for"]("Symbol.metadata"),
+ m = Object.defineProperty,
+ h = Object.create,
+ y = [h(null), h(null)],
+ v = t.length;
+ function g(t, n, r) {
+ return function (o, i) {
+ n && (i = o, o = e);
+ for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []);
+ return r ? i : o;
+ };
+ }
+ function b(e, t, n, r) {
+ if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined"));
+ return e;
+ }
+ function applyDec(e, t, n, r, o, i, u, s, f, l, p) {
+ function d(e) {
+ if (!p(e)) throw new TypeError("Attempted to access private element on non-instance");
+ }
+ var h = [].concat(t[0]),
+ v = t[3],
+ w = !u,
+ D = 1 === o,
+ S = 3 === o,
+ j = 4 === o,
+ E = 2 === o;
+ function I(t, n, r) {
+ return function (o, i) {
+ return n && (i = o, o = e), r && r(o), P[t].call(o, i);
+ };
+ }
+ if (!w) {
+ var P = {},
+ k = [],
+ F = S ? "get" : j || D ? "set" : "value";
+ if (f ? (l || D ? P = {
+ get: setFunctionName(function () {
+ return v(this);
+ }, r, "get"),
+ set: function set(e) {
+ t[4](this, e);
+ }
+ } : P[F] = v, l || setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) {
+ if ((c = y[+s][r]) && 7 != (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet");
+ y[+s][r] = o < 3 ? 1 : o;
+ }
+ }
+ for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) {
+ var T = b(h[O], "A decorator", "be", !0),
+ z = n ? h[O - 1] : void 0,
+ A = {},
+ H = {
+ kind: ["field", "accessor", "method", "getter", "setter", "class"][o],
+ name: r,
+ metadata: a,
+ addInitializer: function (e, t) {
+ if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished");
+ b(t, "An initializer", "be", !0), i.push(t);
+ }.bind(null, A)
+ };
+ if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H["static"] = s, H["private"] = f, c = H.access = {
+ has: f ? p.bind() : function (e) {
+ return r in e;
+ }
+ }, j || (c.get = f ? E ? function (e) {
+ return d(e), P.value;
+ } : I("get", 0, d) : function (e) {
+ return e[r];
+ }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) {
+ e[r] = t;
+ }), N = T.call(z, D ? {
+ get: P.get,
+ set: P.set
+ } : P[F], H), A.v = 1, D) {
+ if ("object" == _typeof(N) && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined");
+ } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N);
+ }
+ return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N;
+ }
+ function w(e) {
+ return m(e, d, {
+ configurable: !0,
+ enumerable: !0,
+ value: a
+ });
+ }
+ return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function l(e) {
+ e && f.push(g(e));
+ }, p = function p(t, r) {
+ for (var i = 0; i < n.length; i++) {
+ var a = n[i],
+ c = a[1],
+ l = 7 & c;
+ if ((8 & c) == t && !l == r) {
+ var p = a[2],
+ d = !!a[3],
+ m = 16 & c;
+ applyDec(t ? e : e.prototype, a, m, d ? "#" + p : toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) {
+ return checkInRHS(t) === e;
+ } : o);
+ }
+ }
+ }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), {
+ e: c,
+ get c() {
+ var n = [];
+ return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)];
+ }
+ };
+}
+module.exports = applyDecs2311, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/arrayLikeToArray.js b/backend/node_modules/@babel/runtime/helpers/arrayLikeToArray.js
new file mode 100644
index 0000000..19787e3
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/arrayLikeToArray.js
@@ -0,0 +1,6 @@
+function _arrayLikeToArray(r, a) {
+ (null == a || a > r.length) && (a = r.length);
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
+ return n;
+}
+module.exports = _arrayLikeToArray, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/arrayWithHoles.js b/backend/node_modules/@babel/runtime/helpers/arrayWithHoles.js
new file mode 100644
index 0000000..78bdd93
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/arrayWithHoles.js
@@ -0,0 +1,4 @@
+function _arrayWithHoles(r) {
+ if (Array.isArray(r)) return r;
+}
+module.exports = _arrayWithHoles, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/arrayWithoutHoles.js b/backend/node_modules/@babel/runtime/helpers/arrayWithoutHoles.js
new file mode 100644
index 0000000..42218f5
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/arrayWithoutHoles.js
@@ -0,0 +1,5 @@
+var arrayLikeToArray = require("./arrayLikeToArray.js");
+function _arrayWithoutHoles(r) {
+ if (Array.isArray(r)) return arrayLikeToArray(r);
+}
+module.exports = _arrayWithoutHoles, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/assertClassBrand.js b/backend/node_modules/@babel/runtime/helpers/assertClassBrand.js
new file mode 100644
index 0000000..e63ed8f
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/assertClassBrand.js
@@ -0,0 +1,5 @@
+function _assertClassBrand(e, t, n) {
+ if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
+ throw new TypeError("Private element is not present on this object");
+}
+module.exports = _assertClassBrand, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/assertThisInitialized.js b/backend/node_modules/@babel/runtime/helpers/assertThisInitialized.js
new file mode 100644
index 0000000..02594fb
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/assertThisInitialized.js
@@ -0,0 +1,5 @@
+function _assertThisInitialized(e) {
+ if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return e;
+}
+module.exports = _assertThisInitialized, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/asyncGeneratorDelegate.js b/backend/node_modules/@babel/runtime/helpers/asyncGeneratorDelegate.js
new file mode 100644
index 0000000..023568e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/asyncGeneratorDelegate.js
@@ -0,0 +1,24 @@
+var OverloadYield = require("./OverloadYield.js");
+function _asyncGeneratorDelegate(t) {
+ var e = {},
+ n = !1;
+ function pump(e, r) {
+ return n = !0, r = new Promise(function (n) {
+ n(t[e](r));
+ }), {
+ done: !1,
+ value: new OverloadYield(r, 1)
+ };
+ }
+ return e["undefined" != typeof Symbol && Symbol.iterator || "@@iterator"] = function () {
+ return this;
+ }, e.next = function (t) {
+ return n ? (n = !1, t) : pump("next", t);
+ }, "function" == typeof t["throw"] && (e["throw"] = function (t) {
+ if (n) throw n = !1, t;
+ return pump("throw", t);
+ }), "function" == typeof t["return"] && (e["return"] = function (t) {
+ return n ? (n = !1, t) : pump("return", t);
+ }), e;
+}
+module.exports = _asyncGeneratorDelegate, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/asyncIterator.js b/backend/node_modules/@babel/runtime/helpers/asyncIterator.js
new file mode 100644
index 0000000..9c0c95c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/asyncIterator.js
@@ -0,0 +1,45 @@
+function _asyncIterator(r) {
+ var n,
+ t,
+ o,
+ e = 2;
+ for ("undefined" != typeof Symbol && (t = Symbol.asyncIterator, o = Symbol.iterator); e--;) {
+ if (t && null != (n = r[t])) return n.call(r);
+ if (o && null != (n = r[o])) return new AsyncFromSyncIterator(n.call(r));
+ t = "@@asyncIterator", o = "@@iterator";
+ }
+ throw new TypeError("Object is not async iterable");
+}
+function AsyncFromSyncIterator(r) {
+ function AsyncFromSyncIteratorContinuation(r) {
+ if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object."));
+ var n = r.done;
+ return Promise.resolve(r.value).then(function (r) {
+ return {
+ value: r,
+ done: n
+ };
+ });
+ }
+ return AsyncFromSyncIterator = function AsyncFromSyncIterator(r) {
+ this.s = r, this.n = r.next;
+ }, AsyncFromSyncIterator.prototype = {
+ s: null,
+ n: null,
+ next: function next() {
+ return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));
+ },
+ "return": function _return(r) {
+ var n = this.s["return"];
+ return void 0 === n ? Promise.resolve({
+ value: r,
+ done: !0
+ }) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments));
+ },
+ "throw": function _throw(r) {
+ var n = this.s["return"];
+ return void 0 === n ? Promise.reject(r) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments));
+ }
+ }, new AsyncFromSyncIterator(r);
+}
+module.exports = _asyncIterator, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/asyncToGenerator.js b/backend/node_modules/@babel/runtime/helpers/asyncToGenerator.js
new file mode 100644
index 0000000..a080339
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/asyncToGenerator.js
@@ -0,0 +1,26 @@
+function asyncGeneratorStep(n, t, e, r, o, a, c) {
+ try {
+ var i = n[a](c),
+ u = i.value;
+ } catch (n) {
+ return void e(n);
+ }
+ i.done ? t(u) : Promise.resolve(u).then(r, o);
+}
+function _asyncToGenerator(n) {
+ return function () {
+ var t = this,
+ e = arguments;
+ return new Promise(function (r, o) {
+ var a = n.apply(t, e);
+ function _next(n) {
+ asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
+ }
+ function _throw(n) {
+ asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
+ }
+ _next(void 0);
+ });
+ };
+}
+module.exports = _asyncToGenerator, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/awaitAsyncGenerator.js b/backend/node_modules/@babel/runtime/helpers/awaitAsyncGenerator.js
new file mode 100644
index 0000000..2d6fab9
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/awaitAsyncGenerator.js
@@ -0,0 +1,5 @@
+var OverloadYield = require("./OverloadYield.js");
+function _awaitAsyncGenerator(e) {
+ return new OverloadYield(e, 0);
+}
+module.exports = _awaitAsyncGenerator, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/callSuper.js b/backend/node_modules/@babel/runtime/helpers/callSuper.js
new file mode 100644
index 0000000..38eaf7f
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/callSuper.js
@@ -0,0 +1,7 @@
+var getPrototypeOf = require("./getPrototypeOf.js");
+var isNativeReflectConstruct = require("./isNativeReflectConstruct.js");
+var possibleConstructorReturn = require("./possibleConstructorReturn.js");
+function _callSuper(t, o, e) {
+ return o = getPrototypeOf(o), possibleConstructorReturn(t, isNativeReflectConstruct() ? Reflect.construct(o, e || [], getPrototypeOf(t).constructor) : o.apply(t, e));
+}
+module.exports = _callSuper, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/checkInRHS.js b/backend/node_modules/@babel/runtime/helpers/checkInRHS.js
new file mode 100644
index 0000000..4eea13d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/checkInRHS.js
@@ -0,0 +1,6 @@
+var _typeof = require("./typeof.js")["default"];
+function _checkInRHS(e) {
+ if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? _typeof(e) : "null"));
+ return e;
+}
+module.exports = _checkInRHS, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/checkPrivateRedeclaration.js b/backend/node_modules/@babel/runtime/helpers/checkPrivateRedeclaration.js
new file mode 100644
index 0000000..33ad54c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/checkPrivateRedeclaration.js
@@ -0,0 +1,4 @@
+function _checkPrivateRedeclaration(e, t) {
+ if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
+}
+module.exports = _checkPrivateRedeclaration, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classApplyDescriptorDestructureSet.js b/backend/node_modules/@babel/runtime/helpers/classApplyDescriptorDestructureSet.js
new file mode 100644
index 0000000..9998b83
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classApplyDescriptorDestructureSet.js
@@ -0,0 +1,10 @@
+function _classApplyDescriptorDestructureSet(e, t) {
+ if (t.set) return "__destrObj" in t || (t.__destrObj = {
+ set value(r) {
+ t.set.call(e, r);
+ }
+ }), t.__destrObj;
+ if (!t.writable) throw new TypeError("attempted to set read only private field");
+ return t;
+}
+module.exports = _classApplyDescriptorDestructureSet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classApplyDescriptorGet.js b/backend/node_modules/@babel/runtime/helpers/classApplyDescriptorGet.js
new file mode 100644
index 0000000..ab62724
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classApplyDescriptorGet.js
@@ -0,0 +1,4 @@
+function _classApplyDescriptorGet(e, t) {
+ return t.get ? t.get.call(e) : t.value;
+}
+module.exports = _classApplyDescriptorGet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classApplyDescriptorSet.js b/backend/node_modules/@babel/runtime/helpers/classApplyDescriptorSet.js
new file mode 100644
index 0000000..0975f95
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classApplyDescriptorSet.js
@@ -0,0 +1,7 @@
+function _classApplyDescriptorSet(e, t, l) {
+ if (t.set) t.set.call(e, l);else {
+ if (!t.writable) throw new TypeError("attempted to set read only private field");
+ t.value = l;
+ }
+}
+module.exports = _classApplyDescriptorSet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classCallCheck.js b/backend/node_modules/@babel/runtime/helpers/classCallCheck.js
new file mode 100644
index 0000000..21b8390
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classCallCheck.js
@@ -0,0 +1,4 @@
+function _classCallCheck(a, n) {
+ if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
+}
+module.exports = _classCallCheck, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classCheckPrivateStaticAccess.js b/backend/node_modules/@babel/runtime/helpers/classCheckPrivateStaticAccess.js
new file mode 100644
index 0000000..7520f74
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classCheckPrivateStaticAccess.js
@@ -0,0 +1,5 @@
+var assertClassBrand = require("./assertClassBrand.js");
+function _classCheckPrivateStaticAccess(s, a, r) {
+ return assertClassBrand(a, s, r);
+}
+module.exports = _classCheckPrivateStaticAccess, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classCheckPrivateStaticFieldDescriptor.js b/backend/node_modules/@babel/runtime/helpers/classCheckPrivateStaticFieldDescriptor.js
new file mode 100644
index 0000000..7f70395
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classCheckPrivateStaticFieldDescriptor.js
@@ -0,0 +1,4 @@
+function _classCheckPrivateStaticFieldDescriptor(t, e) {
+ if (void 0 === t) throw new TypeError("attempted to " + e + " private static field before its declaration");
+}
+module.exports = _classCheckPrivateStaticFieldDescriptor, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classExtractFieldDescriptor.js b/backend/node_modules/@babel/runtime/helpers/classExtractFieldDescriptor.js
new file mode 100644
index 0000000..be855be
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classExtractFieldDescriptor.js
@@ -0,0 +1,5 @@
+var classPrivateFieldGet2 = require("./classPrivateFieldGet2.js");
+function _classExtractFieldDescriptor(e, t) {
+ return classPrivateFieldGet2(t, e);
+}
+module.exports = _classExtractFieldDescriptor, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classNameTDZError.js b/backend/node_modules/@babel/runtime/helpers/classNameTDZError.js
new file mode 100644
index 0000000..8141ff8
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classNameTDZError.js
@@ -0,0 +1,4 @@
+function _classNameTDZError(e) {
+ throw new ReferenceError('Class "' + e + '" cannot be referenced in computed property keys.');
+}
+module.exports = _classNameTDZError, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateFieldDestructureSet.js b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldDestructureSet.js
new file mode 100644
index 0000000..97c764d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldDestructureSet.js
@@ -0,0 +1,7 @@
+var classApplyDescriptorDestructureSet = require("./classApplyDescriptorDestructureSet.js");
+var classPrivateFieldGet2 = require("./classPrivateFieldGet2.js");
+function _classPrivateFieldDestructureSet(e, t) {
+ var r = classPrivateFieldGet2(t, e);
+ return classApplyDescriptorDestructureSet(e, r);
+}
+module.exports = _classPrivateFieldDestructureSet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateFieldGet.js b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldGet.js
new file mode 100644
index 0000000..bbee142
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldGet.js
@@ -0,0 +1,7 @@
+var classApplyDescriptorGet = require("./classApplyDescriptorGet.js");
+var classPrivateFieldGet2 = require("./classPrivateFieldGet2.js");
+function _classPrivateFieldGet(e, t) {
+ var r = classPrivateFieldGet2(t, e);
+ return classApplyDescriptorGet(e, r);
+}
+module.exports = _classPrivateFieldGet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateFieldGet2.js b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldGet2.js
new file mode 100644
index 0000000..d4c271c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldGet2.js
@@ -0,0 +1,5 @@
+var assertClassBrand = require("./assertClassBrand.js");
+function _classPrivateFieldGet2(s, a) {
+ return s.get(assertClassBrand(s, a));
+}
+module.exports = _classPrivateFieldGet2, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateFieldInitSpec.js b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldInitSpec.js
new file mode 100644
index 0000000..a290c19
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldInitSpec.js
@@ -0,0 +1,5 @@
+var checkPrivateRedeclaration = require("./checkPrivateRedeclaration.js");
+function _classPrivateFieldInitSpec(e, t, a) {
+ checkPrivateRedeclaration(e, t), t.set(e, a);
+}
+module.exports = _classPrivateFieldInitSpec, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateFieldLooseBase.js b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldLooseBase.js
new file mode 100644
index 0000000..f9e46f2
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldLooseBase.js
@@ -0,0 +1,5 @@
+function _classPrivateFieldBase(e, t) {
+ if (!{}.hasOwnProperty.call(e, t)) throw new TypeError("attempted to use private field on non-instance");
+ return e;
+}
+module.exports = _classPrivateFieldBase, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateFieldLooseKey.js b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldLooseKey.js
new file mode 100644
index 0000000..5dc687f
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldLooseKey.js
@@ -0,0 +1,5 @@
+var id = 0;
+function _classPrivateFieldKey(e) {
+ return "__private_" + id++ + "_" + e;
+}
+module.exports = _classPrivateFieldKey, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateFieldSet.js b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldSet.js
new file mode 100644
index 0000000..f3746e7
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldSet.js
@@ -0,0 +1,7 @@
+var classApplyDescriptorSet = require("./classApplyDescriptorSet.js");
+var classPrivateFieldGet2 = require("./classPrivateFieldGet2.js");
+function _classPrivateFieldSet(e, t, r) {
+ var s = classPrivateFieldGet2(t, e);
+ return classApplyDescriptorSet(e, s, r), r;
+}
+module.exports = _classPrivateFieldSet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateFieldSet2.js b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldSet2.js
new file mode 100644
index 0000000..25c60ca
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateFieldSet2.js
@@ -0,0 +1,5 @@
+var assertClassBrand = require("./assertClassBrand.js");
+function _classPrivateFieldSet2(s, a, r) {
+ return s.set(assertClassBrand(s, a), r), r;
+}
+module.exports = _classPrivateFieldSet2, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateGetter.js b/backend/node_modules/@babel/runtime/helpers/classPrivateGetter.js
new file mode 100644
index 0000000..1b3cf30
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateGetter.js
@@ -0,0 +1,5 @@
+var assertClassBrand = require("./assertClassBrand.js");
+function _classPrivateGetter(s, r, a) {
+ return a(assertClassBrand(s, r));
+}
+module.exports = _classPrivateGetter, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateMethodGet.js b/backend/node_modules/@babel/runtime/helpers/classPrivateMethodGet.js
new file mode 100644
index 0000000..e4af387
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateMethodGet.js
@@ -0,0 +1,5 @@
+var assertClassBrand = require("./assertClassBrand.js");
+function _classPrivateMethodGet(s, a, r) {
+ return assertClassBrand(a, s), r;
+}
+module.exports = _classPrivateMethodGet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateMethodInitSpec.js b/backend/node_modules/@babel/runtime/helpers/classPrivateMethodInitSpec.js
new file mode 100644
index 0000000..821c8ed
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateMethodInitSpec.js
@@ -0,0 +1,5 @@
+var checkPrivateRedeclaration = require("./checkPrivateRedeclaration.js");
+function _classPrivateMethodInitSpec(e, a) {
+ checkPrivateRedeclaration(e, a), a.add(e);
+}
+module.exports = _classPrivateMethodInitSpec, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateMethodSet.js b/backend/node_modules/@babel/runtime/helpers/classPrivateMethodSet.js
new file mode 100644
index 0000000..a44fd78
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateMethodSet.js
@@ -0,0 +1,4 @@
+function _classPrivateMethodSet() {
+ throw new TypeError("attempted to reassign private method");
+}
+module.exports = _classPrivateMethodSet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classPrivateSetter.js b/backend/node_modules/@babel/runtime/helpers/classPrivateSetter.js
new file mode 100644
index 0000000..494f81f
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classPrivateSetter.js
@@ -0,0 +1,5 @@
+var assertClassBrand = require("./assertClassBrand.js");
+function _classPrivateSetter(s, r, a, t) {
+ return r(assertClassBrand(s, a), t), t;
+}
+module.exports = _classPrivateSetter, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classStaticPrivateFieldDestructureSet.js b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateFieldDestructureSet.js
new file mode 100644
index 0000000..2bb6e8b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateFieldDestructureSet.js
@@ -0,0 +1,7 @@
+var classApplyDescriptorDestructureSet = require("./classApplyDescriptorDestructureSet.js");
+var assertClassBrand = require("./assertClassBrand.js");
+var classCheckPrivateStaticFieldDescriptor = require("./classCheckPrivateStaticFieldDescriptor.js");
+function _classStaticPrivateFieldDestructureSet(t, r, s) {
+ return assertClassBrand(r, t), classCheckPrivateStaticFieldDescriptor(s, "set"), classApplyDescriptorDestructureSet(t, s);
+}
+module.exports = _classStaticPrivateFieldDestructureSet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classStaticPrivateFieldSpecGet.js b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateFieldSpecGet.js
new file mode 100644
index 0000000..eb2365f
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateFieldSpecGet.js
@@ -0,0 +1,7 @@
+var classApplyDescriptorGet = require("./classApplyDescriptorGet.js");
+var assertClassBrand = require("./assertClassBrand.js");
+var classCheckPrivateStaticFieldDescriptor = require("./classCheckPrivateStaticFieldDescriptor.js");
+function _classStaticPrivateFieldSpecGet(t, s, r) {
+ return assertClassBrand(s, t), classCheckPrivateStaticFieldDescriptor(r, "get"), classApplyDescriptorGet(t, r);
+}
+module.exports = _classStaticPrivateFieldSpecGet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classStaticPrivateFieldSpecSet.js b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateFieldSpecSet.js
new file mode 100644
index 0000000..7783cd8
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateFieldSpecSet.js
@@ -0,0 +1,7 @@
+var classApplyDescriptorSet = require("./classApplyDescriptorSet.js");
+var assertClassBrand = require("./assertClassBrand.js");
+var classCheckPrivateStaticFieldDescriptor = require("./classCheckPrivateStaticFieldDescriptor.js");
+function _classStaticPrivateFieldSpecSet(s, t, r, e) {
+ return assertClassBrand(t, s), classCheckPrivateStaticFieldDescriptor(r, "set"), classApplyDescriptorSet(s, r, e), e;
+}
+module.exports = _classStaticPrivateFieldSpecSet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classStaticPrivateMethodGet.js b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateMethodGet.js
new file mode 100644
index 0000000..c895be5
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateMethodGet.js
@@ -0,0 +1,5 @@
+var assertClassBrand = require("./assertClassBrand.js");
+function _classStaticPrivateMethodGet(s, a, t) {
+ return assertClassBrand(a, s), t;
+}
+module.exports = _classStaticPrivateMethodGet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/classStaticPrivateMethodSet.js b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateMethodSet.js
new file mode 100644
index 0000000..72560e6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/classStaticPrivateMethodSet.js
@@ -0,0 +1,4 @@
+function _classStaticPrivateMethodSet() {
+ throw new TypeError("attempted to set read only static private field");
+}
+module.exports = _classStaticPrivateMethodSet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/construct.js b/backend/node_modules/@babel/runtime/helpers/construct.js
new file mode 100644
index 0000000..aee8e70
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/construct.js
@@ -0,0 +1,10 @@
+var isNativeReflectConstruct = require("./isNativeReflectConstruct.js");
+var setPrototypeOf = require("./setPrototypeOf.js");
+function _construct(t, e, r) {
+ if (isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
+ var o = [null];
+ o.push.apply(o, e);
+ var p = new (t.bind.apply(t, o))();
+ return r && setPrototypeOf(p, r.prototype), p;
+}
+module.exports = _construct, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/createClass.js b/backend/node_modules/@babel/runtime/helpers/createClass.js
new file mode 100644
index 0000000..8757f9e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/createClass.js
@@ -0,0 +1,13 @@
+var toPropertyKey = require("./toPropertyKey.js");
+function _defineProperties(e, r) {
+ for (var t = 0; t < r.length; t++) {
+ var o = r[t];
+ o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, toPropertyKey(o.key), o);
+ }
+}
+function _createClass(e, r, t) {
+ return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
+ writable: !1
+ }), e;
+}
+module.exports = _createClass, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/createForOfIteratorHelper.js b/backend/node_modules/@babel/runtime/helpers/createForOfIteratorHelper.js
new file mode 100644
index 0000000..2778307
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/createForOfIteratorHelper.js
@@ -0,0 +1,50 @@
+var unsupportedIterableToArray = require("./unsupportedIterableToArray.js");
+function _createForOfIteratorHelper(r, e) {
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
+ if (!t) {
+ if (Array.isArray(r) || (t = unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
+ t && (r = t);
+ var _n = 0,
+ F = function F() {};
+ return {
+ s: F,
+ n: function n() {
+ return _n >= r.length ? {
+ done: !0
+ } : {
+ done: !1,
+ value: r[_n++]
+ };
+ },
+ e: function e(r) {
+ throw r;
+ },
+ f: F
+ };
+ }
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+ }
+ var o,
+ a = !0,
+ u = !1;
+ return {
+ s: function s() {
+ t = t.call(r);
+ },
+ n: function n() {
+ var r = t.next();
+ return a = r.done, r;
+ },
+ e: function e(r) {
+ u = !0, o = r;
+ },
+ f: function f() {
+ try {
+ a || null == t["return"] || t["return"]();
+ } finally {
+ if (u) throw o;
+ }
+ }
+ };
+}
+module.exports = _createForOfIteratorHelper, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/createForOfIteratorHelperLoose.js b/backend/node_modules/@babel/runtime/helpers/createForOfIteratorHelperLoose.js
new file mode 100644
index 0000000..bc81b1c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/createForOfIteratorHelperLoose.js
@@ -0,0 +1,19 @@
+var unsupportedIterableToArray = require("./unsupportedIterableToArray.js");
+function _createForOfIteratorHelperLoose(r, e) {
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
+ if (t) return (t = t.call(r)).next.bind(t);
+ if (Array.isArray(r) || (t = unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
+ t && (r = t);
+ var o = 0;
+ return function () {
+ return o >= r.length ? {
+ done: !0
+ } : {
+ done: !1,
+ value: r[o++]
+ };
+ };
+ }
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+}
+module.exports = _createForOfIteratorHelperLoose, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/createSuper.js b/backend/node_modules/@babel/runtime/helpers/createSuper.js
new file mode 100644
index 0000000..b1869e6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/createSuper.js
@@ -0,0 +1,16 @@
+var getPrototypeOf = require("./getPrototypeOf.js");
+var isNativeReflectConstruct = require("./isNativeReflectConstruct.js");
+var possibleConstructorReturn = require("./possibleConstructorReturn.js");
+function _createSuper(t) {
+ var r = isNativeReflectConstruct();
+ return function () {
+ var e,
+ o = getPrototypeOf(t);
+ if (r) {
+ var s = getPrototypeOf(this).constructor;
+ e = Reflect.construct(o, arguments, s);
+ } else e = o.apply(this, arguments);
+ return possibleConstructorReturn(this, e);
+ };
+}
+module.exports = _createSuper, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/decorate.js b/backend/node_modules/@babel/runtime/helpers/decorate.js
new file mode 100644
index 0000000..bc22acf
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/decorate.js
@@ -0,0 +1,250 @@
+var toArray = require("./toArray.js");
+var toPropertyKey = require("./toPropertyKey.js");
+function _decorate(e, r, t, i) {
+ var o = _getDecoratorsApi();
+ if (i) for (var n = 0; n < i.length; n++) o = i[n](o);
+ var s = r(function (e) {
+ o.initializeInstanceElements(e, a.elements);
+ }, t),
+ a = o.decorateClass(_coalesceClassElements(s.d.map(_createElementDescriptor)), e);
+ return o.initializeClassElements(s.F, a.elements), o.runClassFinishers(s.F, a.finishers);
+}
+function _getDecoratorsApi() {
+ _getDecoratorsApi = function _getDecoratorsApi() {
+ return e;
+ };
+ var e = {
+ elementsDefinitionOrder: [["method"], ["field"]],
+ initializeInstanceElements: function initializeInstanceElements(e, r) {
+ ["method", "field"].forEach(function (t) {
+ r.forEach(function (r) {
+ r.kind === t && "own" === r.placement && this.defineClassElement(e, r);
+ }, this);
+ }, this);
+ },
+ initializeClassElements: function initializeClassElements(e, r) {
+ var t = e.prototype;
+ ["method", "field"].forEach(function (i) {
+ r.forEach(function (r) {
+ var o = r.placement;
+ if (r.kind === i && ("static" === o || "prototype" === o)) {
+ var n = "static" === o ? e : t;
+ this.defineClassElement(n, r);
+ }
+ }, this);
+ }, this);
+ },
+ defineClassElement: function defineClassElement(e, r) {
+ var t = r.descriptor;
+ if ("field" === r.kind) {
+ var i = r.initializer;
+ t = {
+ enumerable: t.enumerable,
+ writable: t.writable,
+ configurable: t.configurable,
+ value: void 0 === i ? void 0 : i.call(e)
+ };
+ }
+ Object.defineProperty(e, r.key, t);
+ },
+ decorateClass: function decorateClass(e, r) {
+ var t = [],
+ i = [],
+ o = {
+ "static": [],
+ prototype: [],
+ own: []
+ };
+ if (e.forEach(function (e) {
+ this.addElementPlacement(e, o);
+ }, this), e.forEach(function (e) {
+ if (!_hasDecorators(e)) return t.push(e);
+ var r = this.decorateElement(e, o);
+ t.push(r.element), t.push.apply(t, r.extras), i.push.apply(i, r.finishers);
+ }, this), !r) return {
+ elements: t,
+ finishers: i
+ };
+ var n = this.decorateConstructor(t, r);
+ return i.push.apply(i, n.finishers), n.finishers = i, n;
+ },
+ addElementPlacement: function addElementPlacement(e, r, t) {
+ var i = r[e.placement];
+ if (!t && -1 !== i.indexOf(e.key)) throw new TypeError("Duplicated element (" + e.key + ")");
+ i.push(e.key);
+ },
+ decorateElement: function decorateElement(e, r) {
+ for (var t = [], i = [], o = e.decorators, n = o.length - 1; n >= 0; n--) {
+ var s = r[e.placement];
+ s.splice(s.indexOf(e.key), 1);
+ var a = this.fromElementDescriptor(e),
+ l = this.toElementFinisherExtras((0, o[n])(a) || a);
+ e = l.element, this.addElementPlacement(e, r), l.finisher && i.push(l.finisher);
+ var c = l.extras;
+ if (c) {
+ for (var p = 0; p < c.length; p++) this.addElementPlacement(c[p], r);
+ t.push.apply(t, c);
+ }
+ }
+ return {
+ element: e,
+ finishers: i,
+ extras: t
+ };
+ },
+ decorateConstructor: function decorateConstructor(e, r) {
+ for (var t = [], i = r.length - 1; i >= 0; i--) {
+ var o = this.fromClassDescriptor(e),
+ n = this.toClassDescriptor((0, r[i])(o) || o);
+ if (void 0 !== n.finisher && t.push(n.finisher), void 0 !== n.elements) {
+ e = n.elements;
+ for (var s = 0; s < e.length - 1; s++) for (var a = s + 1; a < e.length; a++) if (e[s].key === e[a].key && e[s].placement === e[a].placement) throw new TypeError("Duplicated element (" + e[s].key + ")");
+ }
+ }
+ return {
+ elements: e,
+ finishers: t
+ };
+ },
+ fromElementDescriptor: function fromElementDescriptor(e) {
+ var r = {
+ kind: e.kind,
+ key: e.key,
+ placement: e.placement,
+ descriptor: e.descriptor
+ };
+ return Object.defineProperty(r, Symbol.toStringTag, {
+ value: "Descriptor",
+ configurable: !0
+ }), "field" === e.kind && (r.initializer = e.initializer), r;
+ },
+ toElementDescriptors: function toElementDescriptors(e) {
+ if (void 0 !== e) return toArray(e).map(function (e) {
+ var r = this.toElementDescriptor(e);
+ return this.disallowProperty(e, "finisher", "An element descriptor"), this.disallowProperty(e, "extras", "An element descriptor"), r;
+ }, this);
+ },
+ toElementDescriptor: function toElementDescriptor(e) {
+ var r = e.kind + "";
+ if ("method" !== r && "field" !== r) throw new TypeError('An element descriptor\'s .kind property must be either "method" or "field", but a decorator created an element descriptor with .kind "' + r + '"');
+ var t = toPropertyKey(e.key),
+ i = e.placement + "";
+ if ("static" !== i && "prototype" !== i && "own" !== i) throw new TypeError('An element descriptor\'s .placement property must be one of "static", "prototype" or "own", but a decorator created an element descriptor with .placement "' + i + '"');
+ var o = e.descriptor;
+ this.disallowProperty(e, "elements", "An element descriptor");
+ var n = {
+ kind: r,
+ key: t,
+ placement: i,
+ descriptor: Object.assign({}, o)
+ };
+ return "field" !== r ? this.disallowProperty(e, "initializer", "A method descriptor") : (this.disallowProperty(o, "get", "The property descriptor of a field descriptor"), this.disallowProperty(o, "set", "The property descriptor of a field descriptor"), this.disallowProperty(o, "value", "The property descriptor of a field descriptor"), n.initializer = e.initializer), n;
+ },
+ toElementFinisherExtras: function toElementFinisherExtras(e) {
+ return {
+ element: this.toElementDescriptor(e),
+ finisher: _optionalCallableProperty(e, "finisher"),
+ extras: this.toElementDescriptors(e.extras)
+ };
+ },
+ fromClassDescriptor: function fromClassDescriptor(e) {
+ var r = {
+ kind: "class",
+ elements: e.map(this.fromElementDescriptor, this)
+ };
+ return Object.defineProperty(r, Symbol.toStringTag, {
+ value: "Descriptor",
+ configurable: !0
+ }), r;
+ },
+ toClassDescriptor: function toClassDescriptor(e) {
+ var r = e.kind + "";
+ if ("class" !== r) throw new TypeError('A class descriptor\'s .kind property must be "class", but a decorator created a class descriptor with .kind "' + r + '"');
+ this.disallowProperty(e, "key", "A class descriptor"), this.disallowProperty(e, "placement", "A class descriptor"), this.disallowProperty(e, "descriptor", "A class descriptor"), this.disallowProperty(e, "initializer", "A class descriptor"), this.disallowProperty(e, "extras", "A class descriptor");
+ var t = _optionalCallableProperty(e, "finisher");
+ return {
+ elements: this.toElementDescriptors(e.elements),
+ finisher: t
+ };
+ },
+ runClassFinishers: function runClassFinishers(e, r) {
+ for (var t = 0; t < r.length; t++) {
+ var i = (0, r[t])(e);
+ if (void 0 !== i) {
+ if ("function" != typeof i) throw new TypeError("Finishers must return a constructor.");
+ e = i;
+ }
+ }
+ return e;
+ },
+ disallowProperty: function disallowProperty(e, r, t) {
+ if (void 0 !== e[r]) throw new TypeError(t + " can't have a ." + r + " property.");
+ }
+ };
+ return e;
+}
+function _createElementDescriptor(e) {
+ var r,
+ t = toPropertyKey(e.key);
+ "method" === e.kind ? r = {
+ value: e.value,
+ writable: !0,
+ configurable: !0,
+ enumerable: !1
+ } : "get" === e.kind ? r = {
+ get: e.value,
+ configurable: !0,
+ enumerable: !1
+ } : "set" === e.kind ? r = {
+ set: e.value,
+ configurable: !0,
+ enumerable: !1
+ } : "field" === e.kind && (r = {
+ configurable: !0,
+ writable: !0,
+ enumerable: !0
+ });
+ var i = {
+ kind: "field" === e.kind ? "field" : "method",
+ key: t,
+ placement: e["static"] ? "static" : "field" === e.kind ? "own" : "prototype",
+ descriptor: r
+ };
+ return e.decorators && (i.decorators = e.decorators), "field" === e.kind && (i.initializer = e.value), i;
+}
+function _coalesceGetterSetter(e, r) {
+ void 0 !== e.descriptor.get ? r.descriptor.get = e.descriptor.get : r.descriptor.set = e.descriptor.set;
+}
+function _coalesceClassElements(e) {
+ for (var r = [], isSameElement = function isSameElement(e) {
+ return "method" === e.kind && e.key === o.key && e.placement === o.placement;
+ }, t = 0; t < e.length; t++) {
+ var i,
+ o = e[t];
+ if ("method" === o.kind && (i = r.find(isSameElement))) {
+ if (_isDataDescriptor(o.descriptor) || _isDataDescriptor(i.descriptor)) {
+ if (_hasDecorators(o) || _hasDecorators(i)) throw new ReferenceError("Duplicated methods (" + o.key + ") can't be decorated.");
+ i.descriptor = o.descriptor;
+ } else {
+ if (_hasDecorators(o)) {
+ if (_hasDecorators(i)) throw new ReferenceError("Decorators can't be placed on different accessors with for the same property (" + o.key + ").");
+ i.decorators = o.decorators;
+ }
+ _coalesceGetterSetter(o, i);
+ }
+ } else r.push(o);
+ }
+ return r;
+}
+function _hasDecorators(e) {
+ return e.decorators && e.decorators.length;
+}
+function _isDataDescriptor(e) {
+ return void 0 !== e && !(void 0 === e.value && void 0 === e.writable);
+}
+function _optionalCallableProperty(e, r) {
+ var t = e[r];
+ if (void 0 !== t && "function" != typeof t) throw new TypeError("Expected '" + r + "' to be a function");
+ return t;
+}
+module.exports = _decorate, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/defaults.js b/backend/node_modules/@babel/runtime/helpers/defaults.js
new file mode 100644
index 0000000..dfdbbb0
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/defaults.js
@@ -0,0 +1,9 @@
+function _defaults(e, r) {
+ for (var t = Object.getOwnPropertyNames(r), o = 0; o < t.length; o++) {
+ var n = t[o],
+ a = Object.getOwnPropertyDescriptor(r, n);
+ a && a.configurable && void 0 === e[n] && Object.defineProperty(e, n, a);
+ }
+ return e;
+}
+module.exports = _defaults, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/defineAccessor.js b/backend/node_modules/@babel/runtime/helpers/defineAccessor.js
new file mode 100644
index 0000000..dc065f0
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/defineAccessor.js
@@ -0,0 +1,8 @@
+function _defineAccessor(e, r, n, t) {
+ var c = {
+ configurable: !0,
+ enumerable: !0
+ };
+ return c[e] = t, Object.defineProperty(r, n, c);
+}
+module.exports = _defineAccessor, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/defineEnumerableProperties.js b/backend/node_modules/@babel/runtime/helpers/defineEnumerableProperties.js
new file mode 100644
index 0000000..ab9f43c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/defineEnumerableProperties.js
@@ -0,0 +1,12 @@
+function _defineEnumerableProperties(e, r) {
+ for (var t in r) {
+ var n = r[t];
+ n.configurable = n.enumerable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, t, n);
+ }
+ if (Object.getOwnPropertySymbols) for (var a = Object.getOwnPropertySymbols(r), b = 0; b < a.length; b++) {
+ var i = a[b];
+ (n = r[i]).configurable = n.enumerable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, i, n);
+ }
+ return e;
+}
+module.exports = _defineEnumerableProperties, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/defineProperty.js b/backend/node_modules/@babel/runtime/helpers/defineProperty.js
new file mode 100644
index 0000000..2c2ff1e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/defineProperty.js
@@ -0,0 +1,10 @@
+var toPropertyKey = require("./toPropertyKey.js");
+function _defineProperty(e, r, t) {
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
+ value: t,
+ enumerable: !0,
+ configurable: !0,
+ writable: !0
+ }) : e[r] = t, e;
+}
+module.exports = _defineProperty, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/dispose.js b/backend/node_modules/@babel/runtime/helpers/dispose.js
new file mode 100644
index 0000000..c20193c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/dispose.js
@@ -0,0 +1,28 @@
+function dispose_SuppressedError(r, e) {
+ return "undefined" != typeof SuppressedError ? dispose_SuppressedError = SuppressedError : (dispose_SuppressedError = function dispose_SuppressedError(r, e) {
+ this.suppressed = e, this.error = r, this.stack = Error().stack;
+ }, dispose_SuppressedError.prototype = Object.create(Error.prototype, {
+ constructor: {
+ value: dispose_SuppressedError,
+ writable: !0,
+ configurable: !0
+ }
+ })), new dispose_SuppressedError(r, e);
+}
+function _dispose(r, e, s) {
+ function next() {
+ for (; r.length > 0;) try {
+ var o = r.pop(),
+ p = o.d.call(o.v);
+ if (o.a) return Promise.resolve(p).then(next, err);
+ } catch (r) {
+ return err(r);
+ }
+ if (s) throw e;
+ }
+ function err(r) {
+ return e = s ? new dispose_SuppressedError(e, r) : r, s = !0, next();
+ }
+ return next();
+}
+module.exports = _dispose, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/AwaitValue.js b/backend/node_modules/@babel/runtime/helpers/esm/AwaitValue.js
new file mode 100644
index 0000000..6f210c9
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/AwaitValue.js
@@ -0,0 +1,4 @@
+function _AwaitValue(t) {
+ this.wrapped = t;
+}
+export { _AwaitValue as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/OverloadYield.js b/backend/node_modules/@babel/runtime/helpers/esm/OverloadYield.js
new file mode 100644
index 0000000..d7753a6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/OverloadYield.js
@@ -0,0 +1,4 @@
+function _OverloadYield(e, d) {
+ this.v = e, this.k = d;
+}
+export { _OverloadYield as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js b/backend/node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
new file mode 100644
index 0000000..0f33483
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/applyDecoratedDescriptor.js
@@ -0,0 +1,9 @@
+function _applyDecoratedDescriptor(i, e, r, n, l) {
+ var a = {};
+ return Object.keys(n).forEach(function (i) {
+ a[i] = n[i];
+ }), a.enumerable = !!a.enumerable, a.configurable = !!a.configurable, ("value" in a || a.initializer) && (a.writable = !0), a = r.slice().reverse().reduce(function (r, n) {
+ return n(i, e, r) || r;
+ }, a), l && void 0 !== a.initializer && (a.value = a.initializer ? a.initializer.call(l) : void 0, a.initializer = void 0), void 0 === a.initializer ? (Object.defineProperty(i, e, a), null) : a;
+}
+export { _applyDecoratedDescriptor as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/applyDecs.js b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs.js
new file mode 100644
index 0000000..2b75dfd
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs.js
@@ -0,0 +1,236 @@
+import _typeof from "./typeof.js";
+import setFunctionName from "./setFunctionName.js";
+import toPropertyKey from "./toPropertyKey.js";
+function old_createMetadataMethodsForProperty(e, t, a, r) {
+ return {
+ getMetadata: function getMetadata(o) {
+ old_assertNotFinished(r, "getMetadata"), old_assertMetadataKey(o);
+ var i = e[o];
+ if (void 0 !== i) if (1 === t) {
+ var n = i["public"];
+ if (void 0 !== n) return n[a];
+ } else if (2 === t) {
+ var l = i["private"];
+ if (void 0 !== l) return l.get(a);
+ } else if (Object.hasOwnProperty.call(i, "constructor")) return i.constructor;
+ },
+ setMetadata: function setMetadata(o, i) {
+ old_assertNotFinished(r, "setMetadata"), old_assertMetadataKey(o);
+ var n = e[o];
+ if (void 0 === n && (n = e[o] = {}), 1 === t) {
+ var l = n["public"];
+ void 0 === l && (l = n["public"] = {}), l[a] = i;
+ } else if (2 === t) {
+ var s = n.priv;
+ void 0 === s && (s = n["private"] = new Map()), s.set(a, i);
+ } else n.constructor = i;
+ }
+ };
+}
+function old_convertMetadataMapToFinal(e, t) {
+ var a = e[Symbol.metadata || Symbol["for"]("Symbol.metadata")],
+ r = Object.getOwnPropertySymbols(t);
+ if (0 !== r.length) {
+ for (var o = 0; o < r.length; o++) {
+ var i = r[o],
+ n = t[i],
+ l = a ? a[i] : null,
+ s = n["public"],
+ c = l ? l["public"] : null;
+ s && c && Object.setPrototypeOf(s, c);
+ var d = n["private"];
+ if (d) {
+ var u = Array.from(d.values()),
+ f = l ? l["private"] : null;
+ f && (u = u.concat(f)), n["private"] = u;
+ }
+ l && Object.setPrototypeOf(n, l);
+ }
+ a && Object.setPrototypeOf(t, a), e[Symbol.metadata || Symbol["for"]("Symbol.metadata")] = t;
+ }
+}
+function old_createAddInitializerMethod(e, t) {
+ return function (a) {
+ old_assertNotFinished(t, "addInitializer"), old_assertCallable(a, "An initializer"), e.push(a);
+ };
+}
+function old_memberDec(e, t, a, r, o, i, n, l, s) {
+ var c;
+ switch (i) {
+ case 1:
+ c = "accessor";
+ break;
+ case 2:
+ c = "method";
+ break;
+ case 3:
+ c = "getter";
+ break;
+ case 4:
+ c = "setter";
+ break;
+ default:
+ c = "field";
+ }
+ var d,
+ u,
+ f = {
+ kind: c,
+ name: l ? "#" + t : toPropertyKey(t),
+ isStatic: n,
+ isPrivate: l
+ },
+ p = {
+ v: !1
+ };
+ if (0 !== i && (f.addInitializer = old_createAddInitializerMethod(o, p)), l) {
+ d = 2, u = Symbol(t);
+ var v = {};
+ 0 === i ? (v.get = a.get, v.set = a.set) : 2 === i ? v.get = function () {
+ return a.value;
+ } : (1 !== i && 3 !== i || (v.get = function () {
+ return a.get.call(this);
+ }), 1 !== i && 4 !== i || (v.set = function (e) {
+ a.set.call(this, e);
+ })), f.access = v;
+ } else d = 1, u = t;
+ try {
+ return e(s, Object.assign(f, old_createMetadataMethodsForProperty(r, d, u, p)));
+ } finally {
+ p.v = !0;
+ }
+}
+function old_assertNotFinished(e, t) {
+ if (e.v) throw Error("attempted to call " + t + " after decoration was finished");
+}
+function old_assertMetadataKey(e) {
+ if ("symbol" != _typeof(e)) throw new TypeError("Metadata keys must be symbols, received: " + e);
+}
+function old_assertCallable(e, t) {
+ if ("function" != typeof e) throw new TypeError(t + " must be a function");
+}
+function old_assertValidReturnValue(e, t) {
+ var a = _typeof(t);
+ if (1 === e) {
+ if ("object" !== a || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ void 0 !== t.get && old_assertCallable(t.get, "accessor.get"), void 0 !== t.set && old_assertCallable(t.set, "accessor.set"), void 0 !== t.init && old_assertCallable(t.init, "accessor.init"), void 0 !== t.initializer && old_assertCallable(t.initializer, "accessor.initializer");
+ } else if ("function" !== a) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
+}
+function old_getInit(e) {
+ var t;
+ return null == (t = e.init) && (t = e.initializer) && void 0 !== console && console.warn(".initializer has been renamed to .init as of March 2022"), t;
+}
+function old_applyMemberDec(e, t, a, r, o, i, n, l, s) {
+ var c,
+ d,
+ u,
+ f,
+ p,
+ v,
+ y,
+ h = a[0];
+ if (n ? (0 === o || 1 === o ? (c = {
+ get: a[3],
+ set: a[4]
+ }, u = "get") : 3 === o ? (c = {
+ get: a[3]
+ }, u = "get") : 4 === o ? (c = {
+ set: a[3]
+ }, u = "set") : c = {
+ value: a[3]
+ }, 0 !== o && (1 === o && setFunctionName(a[4], "#" + r, "set"), setFunctionName(a[3], "#" + r, u))) : 0 !== o && (c = Object.getOwnPropertyDescriptor(t, r)), 1 === o ? f = {
+ get: c.get,
+ set: c.set
+ } : 2 === o ? f = c.value : 3 === o ? f = c.get : 4 === o && (f = c.set), "function" == typeof h) void 0 !== (p = old_memberDec(h, r, c, l, s, o, i, n, f)) && (old_assertValidReturnValue(o, p), 0 === o ? d = p : 1 === o ? (d = old_getInit(p), v = p.get || f.get, y = p.set || f.set, f = {
+ get: v,
+ set: y
+ }) : f = p);else for (var m = h.length - 1; m >= 0; m--) {
+ var b;
+ void 0 !== (p = old_memberDec(h[m], r, c, l, s, o, i, n, f)) && (old_assertValidReturnValue(o, p), 0 === o ? b = p : 1 === o ? (b = old_getInit(p), v = p.get || f.get, y = p.set || f.set, f = {
+ get: v,
+ set: y
+ }) : f = p, void 0 !== b && (void 0 === d ? d = b : "function" == typeof d ? d = [d, b] : d.push(b)));
+ }
+ if (0 === o || 1 === o) {
+ if (void 0 === d) d = function d(e, t) {
+ return t;
+ };else if ("function" != typeof d) {
+ var g = d;
+ d = function d(e, t) {
+ for (var a = t, r = 0; r < g.length; r++) a = g[r].call(e, a);
+ return a;
+ };
+ } else {
+ var _ = d;
+ d = function d(e, t) {
+ return _.call(e, t);
+ };
+ }
+ e.push(d);
+ }
+ 0 !== o && (1 === o ? (c.get = f.get, c.set = f.set) : 2 === o ? c.value = f : 3 === o ? c.get = f : 4 === o && (c.set = f), n ? 1 === o ? (e.push(function (e, t) {
+ return f.get.call(e, t);
+ }), e.push(function (e, t) {
+ return f.set.call(e, t);
+ })) : 2 === o ? e.push(f) : e.push(function (e, t) {
+ return f.call(e, t);
+ }) : Object.defineProperty(t, r, c));
+}
+function old_applyMemberDecs(e, t, a, r, o) {
+ for (var i, n, l = new Map(), s = new Map(), c = 0; c < o.length; c++) {
+ var d = o[c];
+ if (Array.isArray(d)) {
+ var u,
+ f,
+ p,
+ v = d[1],
+ y = d[2],
+ h = d.length > 3,
+ m = v >= 5;
+ if (m ? (u = t, f = r, 0 != (v -= 5) && (p = n = n || [])) : (u = t.prototype, f = a, 0 !== v && (p = i = i || [])), 0 !== v && !h) {
+ var b = m ? s : l,
+ g = b.get(y) || 0;
+ if (!0 === g || 3 === g && 4 !== v || 4 === g && 3 !== v) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + y);
+ !g && v > 2 ? b.set(y, v) : b.set(y, !0);
+ }
+ old_applyMemberDec(e, u, d, y, v, m, h, f, p);
+ }
+ }
+ old_pushInitializers(e, i), old_pushInitializers(e, n);
+}
+function old_pushInitializers(e, t) {
+ t && e.push(function (e) {
+ for (var a = 0; a < t.length; a++) t[a].call(e);
+ return e;
+ });
+}
+function old_applyClassDecs(e, t, a, r) {
+ if (r.length > 0) {
+ for (var o = [], i = t, n = t.name, l = r.length - 1; l >= 0; l--) {
+ var s = {
+ v: !1
+ };
+ try {
+ var c = Object.assign({
+ kind: "class",
+ name: n,
+ addInitializer: old_createAddInitializerMethod(o, s)
+ }, old_createMetadataMethodsForProperty(a, 0, n, s)),
+ d = r[l](i, c);
+ } finally {
+ s.v = !0;
+ }
+ void 0 !== d && (old_assertValidReturnValue(10, d), i = d);
+ }
+ e.push(i, function () {
+ for (var e = 0; e < o.length; e++) o[e].call(i);
+ });
+ }
+}
+function applyDecs(e, t, a) {
+ var r = [],
+ o = {},
+ i = {};
+ return old_applyMemberDecs(r, e, i, o, t), old_convertMetadataMapToFinal(e.prototype, i), old_applyClassDecs(r, e, o, a), old_convertMetadataMapToFinal(e, o), r;
+}
+export { applyDecs as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2203.js b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2203.js
new file mode 100644
index 0000000..bddb51d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2203.js
@@ -0,0 +1,184 @@
+import _typeof from "./typeof.js";
+function applyDecs2203Factory() {
+ function createAddInitializerMethod(e, t) {
+ return function (r) {
+ !function (e, t) {
+ if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
+ }(t), assertCallable(r, "An initializer"), e.push(r);
+ };
+ }
+ function memberDec(e, t, r, a, n, i, s, o) {
+ var c;
+ switch (n) {
+ case 1:
+ c = "accessor";
+ break;
+ case 2:
+ c = "method";
+ break;
+ case 3:
+ c = "getter";
+ break;
+ case 4:
+ c = "setter";
+ break;
+ default:
+ c = "field";
+ }
+ var l,
+ u,
+ f = {
+ kind: c,
+ name: s ? "#" + t : t,
+ "static": i,
+ "private": s
+ },
+ p = {
+ v: !1
+ };
+ 0 !== n && (f.addInitializer = createAddInitializerMethod(a, p)), 0 === n ? s ? (l = r.get, u = r.set) : (l = function l() {
+ return this[t];
+ }, u = function u(e) {
+ this[t] = e;
+ }) : 2 === n ? l = function l() {
+ return r.value;
+ } : (1 !== n && 3 !== n || (l = function l() {
+ return r.get.call(this);
+ }), 1 !== n && 4 !== n || (u = function u(e) {
+ r.set.call(this, e);
+ })), f.access = l && u ? {
+ get: l,
+ set: u
+ } : l ? {
+ get: l
+ } : {
+ set: u
+ };
+ try {
+ return e(o, f);
+ } finally {
+ p.v = !0;
+ }
+ }
+ function assertCallable(e, t) {
+ if ("function" != typeof e) throw new TypeError(t + " must be a function");
+ }
+ function assertValidReturnValue(e, t) {
+ var r = _typeof(t);
+ if (1 === e) {
+ if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
+ } else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
+ }
+ function applyMemberDec(e, t, r, a, n, i, s, o) {
+ var c,
+ l,
+ u,
+ f,
+ p,
+ d,
+ h = r[0];
+ if (s ? c = 0 === n || 1 === n ? {
+ get: r[3],
+ set: r[4]
+ } : 3 === n ? {
+ get: r[3]
+ } : 4 === n ? {
+ set: r[3]
+ } : {
+ value: r[3]
+ } : 0 !== n && (c = Object.getOwnPropertyDescriptor(t, a)), 1 === n ? u = {
+ get: c.get,
+ set: c.set
+ } : 2 === n ? u = c.value : 3 === n ? u = c.get : 4 === n && (u = c.set), "function" == typeof h) void 0 !== (f = memberDec(h, a, c, o, n, i, s, u)) && (assertValidReturnValue(n, f), 0 === n ? l = f : 1 === n ? (l = f.init, p = f.get || u.get, d = f.set || u.set, u = {
+ get: p,
+ set: d
+ }) : u = f);else for (var v = h.length - 1; v >= 0; v--) {
+ var g;
+ void 0 !== (f = memberDec(h[v], a, c, o, n, i, s, u)) && (assertValidReturnValue(n, f), 0 === n ? g = f : 1 === n ? (g = f.init, p = f.get || u.get, d = f.set || u.set, u = {
+ get: p,
+ set: d
+ }) : u = f, void 0 !== g && (void 0 === l ? l = g : "function" == typeof l ? l = [l, g] : l.push(g)));
+ }
+ if (0 === n || 1 === n) {
+ if (void 0 === l) l = function l(e, t) {
+ return t;
+ };else if ("function" != typeof l) {
+ var y = l;
+ l = function l(e, t) {
+ for (var r = t, a = 0; a < y.length; a++) r = y[a].call(e, r);
+ return r;
+ };
+ } else {
+ var m = l;
+ l = function l(e, t) {
+ return m.call(e, t);
+ };
+ }
+ e.push(l);
+ }
+ 0 !== n && (1 === n ? (c.get = u.get, c.set = u.set) : 2 === n ? c.value = u : 3 === n ? c.get = u : 4 === n && (c.set = u), s ? 1 === n ? (e.push(function (e, t) {
+ return u.get.call(e, t);
+ }), e.push(function (e, t) {
+ return u.set.call(e, t);
+ })) : 2 === n ? e.push(u) : e.push(function (e, t) {
+ return u.call(e, t);
+ }) : Object.defineProperty(t, a, c));
+ }
+ function pushInitializers(e, t) {
+ t && e.push(function (e) {
+ for (var r = 0; r < t.length; r++) t[r].call(e);
+ return e;
+ });
+ }
+ return function (e, t, r) {
+ var a = [];
+ return function (e, t, r) {
+ for (var a, n, i = new Map(), s = new Map(), o = 0; o < r.length; o++) {
+ var c = r[o];
+ if (Array.isArray(c)) {
+ var l,
+ u,
+ f = c[1],
+ p = c[2],
+ d = c.length > 3,
+ h = f >= 5;
+ if (h ? (l = t, 0 != (f -= 5) && (u = n = n || [])) : (l = t.prototype, 0 !== f && (u = a = a || [])), 0 !== f && !d) {
+ var v = h ? s : i,
+ g = v.get(p) || 0;
+ if (!0 === g || 3 === g && 4 !== f || 4 === g && 3 !== f) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + p);
+ !g && f > 2 ? v.set(p, f) : v.set(p, !0);
+ }
+ applyMemberDec(e, l, c, p, f, h, d, u);
+ }
+ }
+ pushInitializers(e, a), pushInitializers(e, n);
+ }(a, e, t), function (e, t, r) {
+ if (r.length > 0) {
+ for (var a = [], n = t, i = t.name, s = r.length - 1; s >= 0; s--) {
+ var o = {
+ v: !1
+ };
+ try {
+ var c = r[s](n, {
+ kind: "class",
+ name: i,
+ addInitializer: createAddInitializerMethod(a, o)
+ });
+ } finally {
+ o.v = !0;
+ }
+ void 0 !== c && (assertValidReturnValue(10, c), n = c);
+ }
+ e.push(n, function () {
+ for (var e = 0; e < a.length; e++) a[e].call(n);
+ });
+ }
+ }(a, e, r), a;
+ };
+}
+var applyDecs2203Impl;
+function applyDecs2203(e, t, r) {
+ return (applyDecs2203Impl = applyDecs2203Impl || applyDecs2203Factory())(e, t, r);
+}
+export { applyDecs2203 as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2203R.js b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2203R.js
new file mode 100644
index 0000000..3944bf4
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2203R.js
@@ -0,0 +1,191 @@
+import _typeof from "./typeof.js";
+import setFunctionName from "./setFunctionName.js";
+import toPropertyKey from "./toPropertyKey.js";
+function applyDecs2203RFactory() {
+ function createAddInitializerMethod(e, t) {
+ return function (r) {
+ !function (e, t) {
+ if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
+ }(t), assertCallable(r, "An initializer"), e.push(r);
+ };
+ }
+ function memberDec(e, t, r, n, a, i, o, s) {
+ var c;
+ switch (a) {
+ case 1:
+ c = "accessor";
+ break;
+ case 2:
+ c = "method";
+ break;
+ case 3:
+ c = "getter";
+ break;
+ case 4:
+ c = "setter";
+ break;
+ default:
+ c = "field";
+ }
+ var l,
+ u,
+ f = {
+ kind: c,
+ name: o ? "#" + t : toPropertyKey(t),
+ "static": i,
+ "private": o
+ },
+ p = {
+ v: !1
+ };
+ 0 !== a && (f.addInitializer = createAddInitializerMethod(n, p)), 0 === a ? o ? (l = r.get, u = r.set) : (l = function l() {
+ return this[t];
+ }, u = function u(e) {
+ this[t] = e;
+ }) : 2 === a ? l = function l() {
+ return r.value;
+ } : (1 !== a && 3 !== a || (l = function l() {
+ return r.get.call(this);
+ }), 1 !== a && 4 !== a || (u = function u(e) {
+ r.set.call(this, e);
+ })), f.access = l && u ? {
+ get: l,
+ set: u
+ } : l ? {
+ get: l
+ } : {
+ set: u
+ };
+ try {
+ return e(s, f);
+ } finally {
+ p.v = !0;
+ }
+ }
+ function assertCallable(e, t) {
+ if ("function" != typeof e) throw new TypeError(t + " must be a function");
+ }
+ function assertValidReturnValue(e, t) {
+ var r = _typeof(t);
+ if (1 === e) {
+ if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
+ } else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
+ }
+ function applyMemberDec(e, t, r, n, a, i, o, s) {
+ var c,
+ l,
+ u,
+ f,
+ p,
+ d,
+ h,
+ v = r[0];
+ if (o ? (0 === a || 1 === a ? (c = {
+ get: r[3],
+ set: r[4]
+ }, u = "get") : 3 === a ? (c = {
+ get: r[3]
+ }, u = "get") : 4 === a ? (c = {
+ set: r[3]
+ }, u = "set") : c = {
+ value: r[3]
+ }, 0 !== a && (1 === a && setFunctionName(r[4], "#" + n, "set"), setFunctionName(r[3], "#" + n, u))) : 0 !== a && (c = Object.getOwnPropertyDescriptor(t, n)), 1 === a ? f = {
+ get: c.get,
+ set: c.set
+ } : 2 === a ? f = c.value : 3 === a ? f = c.get : 4 === a && (f = c.set), "function" == typeof v) void 0 !== (p = memberDec(v, n, c, s, a, i, o, f)) && (assertValidReturnValue(a, p), 0 === a ? l = p : 1 === a ? (l = p.init, d = p.get || f.get, h = p.set || f.set, f = {
+ get: d,
+ set: h
+ }) : f = p);else for (var g = v.length - 1; g >= 0; g--) {
+ var y;
+ void 0 !== (p = memberDec(v[g], n, c, s, a, i, o, f)) && (assertValidReturnValue(a, p), 0 === a ? y = p : 1 === a ? (y = p.init, d = p.get || f.get, h = p.set || f.set, f = {
+ get: d,
+ set: h
+ }) : f = p, void 0 !== y && (void 0 === l ? l = y : "function" == typeof l ? l = [l, y] : l.push(y)));
+ }
+ if (0 === a || 1 === a) {
+ if (void 0 === l) l = function l(e, t) {
+ return t;
+ };else if ("function" != typeof l) {
+ var m = l;
+ l = function l(e, t) {
+ for (var r = t, n = 0; n < m.length; n++) r = m[n].call(e, r);
+ return r;
+ };
+ } else {
+ var b = l;
+ l = function l(e, t) {
+ return b.call(e, t);
+ };
+ }
+ e.push(l);
+ }
+ 0 !== a && (1 === a ? (c.get = f.get, c.set = f.set) : 2 === a ? c.value = f : 3 === a ? c.get = f : 4 === a && (c.set = f), o ? 1 === a ? (e.push(function (e, t) {
+ return f.get.call(e, t);
+ }), e.push(function (e, t) {
+ return f.set.call(e, t);
+ })) : 2 === a ? e.push(f) : e.push(function (e, t) {
+ return f.call(e, t);
+ }) : Object.defineProperty(t, n, c));
+ }
+ function applyMemberDecs(e, t) {
+ for (var r, n, a = [], i = new Map(), o = new Map(), s = 0; s < t.length; s++) {
+ var c = t[s];
+ if (Array.isArray(c)) {
+ var l,
+ u,
+ f = c[1],
+ p = c[2],
+ d = c.length > 3,
+ h = f >= 5;
+ if (h ? (l = e, 0 != (f -= 5) && (u = n = n || [])) : (l = e.prototype, 0 !== f && (u = r = r || [])), 0 !== f && !d) {
+ var v = h ? o : i,
+ g = v.get(p) || 0;
+ if (!0 === g || 3 === g && 4 !== f || 4 === g && 3 !== f) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + p);
+ !g && f > 2 ? v.set(p, f) : v.set(p, !0);
+ }
+ applyMemberDec(a, l, c, p, f, h, d, u);
+ }
+ }
+ return pushInitializers(a, r), pushInitializers(a, n), a;
+ }
+ function pushInitializers(e, t) {
+ t && e.push(function (e) {
+ for (var r = 0; r < t.length; r++) t[r].call(e);
+ return e;
+ });
+ }
+ return function (e, t, r) {
+ return {
+ e: applyMemberDecs(e, t),
+ get c() {
+ return function (e, t) {
+ if (t.length > 0) {
+ for (var r = [], n = e, a = e.name, i = t.length - 1; i >= 0; i--) {
+ var o = {
+ v: !1
+ };
+ try {
+ var s = t[i](n, {
+ kind: "class",
+ name: a,
+ addInitializer: createAddInitializerMethod(r, o)
+ });
+ } finally {
+ o.v = !0;
+ }
+ void 0 !== s && (assertValidReturnValue(10, s), n = s);
+ }
+ return [n, function () {
+ for (var e = 0; e < r.length; e++) r[e].call(n);
+ }];
+ }
+ }(e, r);
+ }
+ };
+ };
+}
+function applyDecs2203R(e, t, r) {
+ return (applyDecs2203R = applyDecs2203RFactory())(e, t, r);
+}
+export { applyDecs2203R as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2301.js b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2301.js
new file mode 100644
index 0000000..bb4fbe6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2301.js
@@ -0,0 +1,222 @@
+import _typeof from "./typeof.js";
+import checkInRHS from "./checkInRHS.js";
+import setFunctionName from "./setFunctionName.js";
+import toPropertyKey from "./toPropertyKey.js";
+function applyDecs2301Factory() {
+ function createAddInitializerMethod(e, t) {
+ return function (r) {
+ !function (e, t) {
+ if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
+ }(t), assertCallable(r, "An initializer"), e.push(r);
+ };
+ }
+ function assertInstanceIfPrivate(e, t) {
+ if (!e(t)) throw new TypeError("Attempted to access private element on non-instance");
+ }
+ function memberDec(e, t, r, n, a, i, s, o, c) {
+ var u;
+ switch (a) {
+ case 1:
+ u = "accessor";
+ break;
+ case 2:
+ u = "method";
+ break;
+ case 3:
+ u = "getter";
+ break;
+ case 4:
+ u = "setter";
+ break;
+ default:
+ u = "field";
+ }
+ var l,
+ f,
+ p = {
+ kind: u,
+ name: s ? "#" + t : toPropertyKey(t),
+ "static": i,
+ "private": s
+ },
+ d = {
+ v: !1
+ };
+ if (0 !== a && (p.addInitializer = createAddInitializerMethod(n, d)), s || 0 !== a && 2 !== a) {
+ if (2 === a) l = function l(e) {
+ return assertInstanceIfPrivate(c, e), r.value;
+ };else {
+ var h = 0 === a || 1 === a;
+ (h || 3 === a) && (l = s ? function (e) {
+ return assertInstanceIfPrivate(c, e), r.get.call(e);
+ } : function (e) {
+ return r.get.call(e);
+ }), (h || 4 === a) && (f = s ? function (e, t) {
+ assertInstanceIfPrivate(c, e), r.set.call(e, t);
+ } : function (e, t) {
+ r.set.call(e, t);
+ });
+ }
+ } else l = function l(e) {
+ return e[t];
+ }, 0 === a && (f = function f(e, r) {
+ e[t] = r;
+ });
+ var v = s ? c.bind() : function (e) {
+ return t in e;
+ };
+ p.access = l && f ? {
+ get: l,
+ set: f,
+ has: v
+ } : l ? {
+ get: l,
+ has: v
+ } : {
+ set: f,
+ has: v
+ };
+ try {
+ return e(o, p);
+ } finally {
+ d.v = !0;
+ }
+ }
+ function assertCallable(e, t) {
+ if ("function" != typeof e) throw new TypeError(t + " must be a function");
+ }
+ function assertValidReturnValue(e, t) {
+ var r = _typeof(t);
+ if (1 === e) {
+ if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
+ } else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
+ }
+ function curryThis2(e) {
+ return function (t) {
+ e(this, t);
+ };
+ }
+ function applyMemberDec(e, t, r, n, a, i, s, o, c) {
+ var u,
+ l,
+ f,
+ p,
+ d,
+ h,
+ v,
+ y,
+ g = r[0];
+ if (s ? (0 === a || 1 === a ? (u = {
+ get: (d = r[3], function () {
+ return d(this);
+ }),
+ set: curryThis2(r[4])
+ }, f = "get") : 3 === a ? (u = {
+ get: r[3]
+ }, f = "get") : 4 === a ? (u = {
+ set: r[3]
+ }, f = "set") : u = {
+ value: r[3]
+ }, 0 !== a && (1 === a && setFunctionName(u.set, "#" + n, "set"), setFunctionName(u[f || "value"], "#" + n, f))) : 0 !== a && (u = Object.getOwnPropertyDescriptor(t, n)), 1 === a ? p = {
+ get: u.get,
+ set: u.set
+ } : 2 === a ? p = u.value : 3 === a ? p = u.get : 4 === a && (p = u.set), "function" == typeof g) void 0 !== (h = memberDec(g, n, u, o, a, i, s, p, c)) && (assertValidReturnValue(a, h), 0 === a ? l = h : 1 === a ? (l = h.init, v = h.get || p.get, y = h.set || p.set, p = {
+ get: v,
+ set: y
+ }) : p = h);else for (var m = g.length - 1; m >= 0; m--) {
+ var b;
+ void 0 !== (h = memberDec(g[m], n, u, o, a, i, s, p, c)) && (assertValidReturnValue(a, h), 0 === a ? b = h : 1 === a ? (b = h.init, v = h.get || p.get, y = h.set || p.set, p = {
+ get: v,
+ set: y
+ }) : p = h, void 0 !== b && (void 0 === l ? l = b : "function" == typeof l ? l = [l, b] : l.push(b)));
+ }
+ if (0 === a || 1 === a) {
+ if (void 0 === l) l = function l(e, t) {
+ return t;
+ };else if ("function" != typeof l) {
+ var I = l;
+ l = function l(e, t) {
+ for (var r = t, n = 0; n < I.length; n++) r = I[n].call(e, r);
+ return r;
+ };
+ } else {
+ var w = l;
+ l = function l(e, t) {
+ return w.call(e, t);
+ };
+ }
+ e.push(l);
+ }
+ 0 !== a && (1 === a ? (u.get = p.get, u.set = p.set) : 2 === a ? u.value = p : 3 === a ? u.get = p : 4 === a && (u.set = p), s ? 1 === a ? (e.push(function (e, t) {
+ return p.get.call(e, t);
+ }), e.push(function (e, t) {
+ return p.set.call(e, t);
+ })) : 2 === a ? e.push(p) : e.push(function (e, t) {
+ return p.call(e, t);
+ }) : Object.defineProperty(t, n, u));
+ }
+ function applyMemberDecs(e, t, r) {
+ for (var n, a, i, s = [], o = new Map(), c = new Map(), u = 0; u < t.length; u++) {
+ var l = t[u];
+ if (Array.isArray(l)) {
+ var f,
+ p,
+ d = l[1],
+ h = l[2],
+ v = l.length > 3,
+ y = d >= 5,
+ g = r;
+ if (y ? (f = e, 0 != (d -= 5) && (p = a = a || []), v && !i && (i = function i(t) {
+ return checkInRHS(t) === e;
+ }), g = i) : (f = e.prototype, 0 !== d && (p = n = n || [])), 0 !== d && !v) {
+ var m = y ? c : o,
+ b = m.get(h) || 0;
+ if (!0 === b || 3 === b && 4 !== d || 4 === b && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h);
+ !b && d > 2 ? m.set(h, d) : m.set(h, !0);
+ }
+ applyMemberDec(s, f, l, h, d, y, v, p, g);
+ }
+ }
+ return pushInitializers(s, n), pushInitializers(s, a), s;
+ }
+ function pushInitializers(e, t) {
+ t && e.push(function (e) {
+ for (var r = 0; r < t.length; r++) t[r].call(e);
+ return e;
+ });
+ }
+ return function (e, t, r, n) {
+ return {
+ e: applyMemberDecs(e, t, n),
+ get c() {
+ return function (e, t) {
+ if (t.length > 0) {
+ for (var r = [], n = e, a = e.name, i = t.length - 1; i >= 0; i--) {
+ var s = {
+ v: !1
+ };
+ try {
+ var o = t[i](n, {
+ kind: "class",
+ name: a,
+ addInitializer: createAddInitializerMethod(r, s)
+ });
+ } finally {
+ s.v = !0;
+ }
+ void 0 !== o && (assertValidReturnValue(10, o), n = o);
+ }
+ return [n, function () {
+ for (var e = 0; e < r.length; e++) r[e].call(n);
+ }];
+ }
+ }(e, r);
+ }
+ };
+ };
+}
+function applyDecs2301(e, t, r, n) {
+ return (applyDecs2301 = applyDecs2301Factory())(e, t, r, n);
+}
+export { applyDecs2301 as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2305.js b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2305.js
new file mode 100644
index 0000000..a11b2b9
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2305.js
@@ -0,0 +1,133 @@
+import _typeof from "./typeof.js";
+import checkInRHS from "./checkInRHS.js";
+import setFunctionName from "./setFunctionName.js";
+import toPropertyKey from "./toPropertyKey.js";
+function applyDecs2305(e, t, r, n, o, a) {
+ function i(e, t, r) {
+ return function (n, o) {
+ return r && r(n), e[t].call(n, o);
+ };
+ }
+ function c(e, t) {
+ for (var r = 0; r < e.length; r++) e[r].call(t);
+ return t;
+ }
+ function s(e, t, r, n) {
+ if ("function" != typeof e && (n || void 0 !== e)) throw new TypeError(t + " must " + (r || "be") + " a function" + (n ? "" : " or undefined"));
+ return e;
+ }
+ function applyDec(e, t, r, n, o, a, c, u, l, f, p, d, h) {
+ function m(e) {
+ if (!h(e)) throw new TypeError("Attempted to access private element on non-instance");
+ }
+ var y,
+ v = t[0],
+ g = t[3],
+ b = !u;
+ if (!b) {
+ r || Array.isArray(v) || (v = [v]);
+ var w = {},
+ S = [],
+ A = 3 === o ? "get" : 4 === o || d ? "set" : "value";
+ f ? (p || d ? w = {
+ get: setFunctionName(function () {
+ return g(this);
+ }, n, "get"),
+ set: function set(e) {
+ t[4](this, e);
+ }
+ } : w[A] = g, p || setFunctionName(w[A], n, 2 === o ? "" : A)) : p || (w = Object.getOwnPropertyDescriptor(e, n));
+ }
+ for (var P = e, j = v.length - 1; j >= 0; j -= r ? 2 : 1) {
+ var D = v[j],
+ E = r ? v[j - 1] : void 0,
+ I = {},
+ O = {
+ kind: ["field", "accessor", "method", "getter", "setter", "class"][o],
+ name: n,
+ metadata: a,
+ addInitializer: function (e, t) {
+ if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
+ s(t, "An initializer", "be", !0), c.push(t);
+ }.bind(null, I)
+ };
+ try {
+ if (b) (y = s(D.call(E, P, O), "class decorators", "return")) && (P = y);else {
+ var k, F;
+ O["static"] = l, O["private"] = f, f ? 2 === o ? k = function k(e) {
+ return m(e), w.value;
+ } : (o < 4 && (k = i(w, "get", m)), 3 !== o && (F = i(w, "set", m))) : (k = function k(e) {
+ return e[n];
+ }, (o < 2 || 4 === o) && (F = function F(e, t) {
+ e[n] = t;
+ }));
+ var N = O.access = {
+ has: f ? h.bind() : function (e) {
+ return n in e;
+ }
+ };
+ if (k && (N.get = k), F && (N.set = F), P = D.call(E, d ? {
+ get: w.get,
+ set: w.set
+ } : w[A], O), d) {
+ if ("object" == _typeof(P) && P) (y = s(P.get, "accessor.get")) && (w.get = y), (y = s(P.set, "accessor.set")) && (w.set = y), (y = s(P.init, "accessor.init")) && S.push(y);else if (void 0 !== P) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
+ } else s(P, (p ? "field" : "method") + " decorators", "return") && (p ? S.push(P) : w[A] = P);
+ }
+ } finally {
+ I.v = !0;
+ }
+ }
+ return (p || d) && u.push(function (e, t) {
+ for (var r = S.length - 1; r >= 0; r--) t = S[r].call(e, t);
+ return t;
+ }), p || b || (f ? d ? u.push(i(w, "get"), i(w, "set")) : u.push(2 === o ? w[A] : i.call.bind(w[A])) : Object.defineProperty(e, n, w)), P;
+ }
+ function u(e, t) {
+ return Object.defineProperty(e, Symbol.metadata || Symbol["for"]("Symbol.metadata"), {
+ configurable: !0,
+ enumerable: !0,
+ value: t
+ });
+ }
+ if (arguments.length >= 6) var l = a[Symbol.metadata || Symbol["for"]("Symbol.metadata")];
+ var f = Object.create(null == l ? null : l),
+ p = function (e, t, r, n) {
+ var o,
+ a,
+ i = [],
+ s = function s(t) {
+ return checkInRHS(t) === e;
+ },
+ u = new Map();
+ function l(e) {
+ e && i.push(c.bind(null, e));
+ }
+ for (var f = 0; f < t.length; f++) {
+ var p = t[f];
+ if (Array.isArray(p)) {
+ var d = p[1],
+ h = p[2],
+ m = p.length > 3,
+ y = 16 & d,
+ v = !!(8 & d),
+ g = 0 == (d &= 7),
+ b = h + "/" + v;
+ if (!g && !m) {
+ var w = u.get(b);
+ if (!0 === w || 3 === w && 4 !== d || 4 === w && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h);
+ u.set(b, !(d > 2) || d);
+ }
+ applyDec(v ? e : e.prototype, p, y, m ? "#" + h : toPropertyKey(h), d, n, v ? a = a || [] : o = o || [], i, v, m, g, 1 === d, v && m ? s : r);
+ }
+ }
+ return l(o), l(a), i;
+ }(e, t, o, f);
+ return r.length || u(e, f), {
+ e: p,
+ get c() {
+ var t = [];
+ return r.length && [u(applyDec(e, [r], n, e.name, 5, f, t), f), c.bind(null, t, e)];
+ }
+ };
+}
+export { applyDecs2305 as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2311.js b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2311.js
new file mode 100644
index 0000000..41b2c48
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/applyDecs2311.js
@@ -0,0 +1,124 @@
+import _typeof from "./typeof.js";
+import checkInRHS from "./checkInRHS.js";
+import setFunctionName from "./setFunctionName.js";
+import toPropertyKey from "./toPropertyKey.js";
+function applyDecs2311(e, t, n, r, o, i) {
+ var a,
+ c,
+ u,
+ s,
+ f,
+ l,
+ p,
+ d = Symbol.metadata || Symbol["for"]("Symbol.metadata"),
+ m = Object.defineProperty,
+ h = Object.create,
+ y = [h(null), h(null)],
+ v = t.length;
+ function g(t, n, r) {
+ return function (o, i) {
+ n && (i = o, o = e);
+ for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []);
+ return r ? i : o;
+ };
+ }
+ function b(e, t, n, r) {
+ if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined"));
+ return e;
+ }
+ function applyDec(e, t, n, r, o, i, u, s, f, l, p) {
+ function d(e) {
+ if (!p(e)) throw new TypeError("Attempted to access private element on non-instance");
+ }
+ var h = [].concat(t[0]),
+ v = t[3],
+ w = !u,
+ D = 1 === o,
+ S = 3 === o,
+ j = 4 === o,
+ E = 2 === o;
+ function I(t, n, r) {
+ return function (o, i) {
+ return n && (i = o, o = e), r && r(o), P[t].call(o, i);
+ };
+ }
+ if (!w) {
+ var P = {},
+ k = [],
+ F = S ? "get" : j || D ? "set" : "value";
+ if (f ? (l || D ? P = {
+ get: setFunctionName(function () {
+ return v(this);
+ }, r, "get"),
+ set: function set(e) {
+ t[4](this, e);
+ }
+ } : P[F] = v, l || setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) {
+ if ((c = y[+s][r]) && 7 != (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet");
+ y[+s][r] = o < 3 ? 1 : o;
+ }
+ }
+ for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) {
+ var T = b(h[O], "A decorator", "be", !0),
+ z = n ? h[O - 1] : void 0,
+ A = {},
+ H = {
+ kind: ["field", "accessor", "method", "getter", "setter", "class"][o],
+ name: r,
+ metadata: a,
+ addInitializer: function (e, t) {
+ if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished");
+ b(t, "An initializer", "be", !0), i.push(t);
+ }.bind(null, A)
+ };
+ if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H["static"] = s, H["private"] = f, c = H.access = {
+ has: f ? p.bind() : function (e) {
+ return r in e;
+ }
+ }, j || (c.get = f ? E ? function (e) {
+ return d(e), P.value;
+ } : I("get", 0, d) : function (e) {
+ return e[r];
+ }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) {
+ e[r] = t;
+ }), N = T.call(z, D ? {
+ get: P.get,
+ set: P.set
+ } : P[F], H), A.v = 1, D) {
+ if ("object" == _typeof(N) && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined");
+ } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N);
+ }
+ return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N;
+ }
+ function w(e) {
+ return m(e, d, {
+ configurable: !0,
+ enumerable: !0,
+ value: a
+ });
+ }
+ return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function l(e) {
+ e && f.push(g(e));
+ }, p = function p(t, r) {
+ for (var i = 0; i < n.length; i++) {
+ var a = n[i],
+ c = a[1],
+ l = 7 & c;
+ if ((8 & c) == t && !l == r) {
+ var p = a[2],
+ d = !!a[3],
+ m = 16 & c;
+ applyDec(t ? e : e.prototype, a, m, d ? "#" + p : toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) {
+ return checkInRHS(t) === e;
+ } : o);
+ }
+ }
+ }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), {
+ e: c,
+ get c() {
+ var n = [];
+ return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)];
+ }
+ };
+}
+export { applyDecs2311 as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js b/backend/node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js
new file mode 100644
index 0000000..9ace772
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/arrayLikeToArray.js
@@ -0,0 +1,6 @@
+function _arrayLikeToArray(r, a) {
+ (null == a || a > r.length) && (a = r.length);
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
+ return n;
+}
+export { _arrayLikeToArray as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/arrayWithHoles.js b/backend/node_modules/@babel/runtime/helpers/esm/arrayWithHoles.js
new file mode 100644
index 0000000..99fa715
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/arrayWithHoles.js
@@ -0,0 +1,4 @@
+function _arrayWithHoles(r) {
+ if (Array.isArray(r)) return r;
+}
+export { _arrayWithHoles as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js b/backend/node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js
new file mode 100644
index 0000000..1ce6f21
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/arrayWithoutHoles.js
@@ -0,0 +1,5 @@
+import arrayLikeToArray from "./arrayLikeToArray.js";
+function _arrayWithoutHoles(r) {
+ if (Array.isArray(r)) return arrayLikeToArray(r);
+}
+export { _arrayWithoutHoles as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/assertClassBrand.js b/backend/node_modules/@babel/runtime/helpers/esm/assertClassBrand.js
new file mode 100644
index 0000000..ae7b712
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/assertClassBrand.js
@@ -0,0 +1,5 @@
+function _assertClassBrand(e, t, n) {
+ if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
+ throw new TypeError("Private element is not present on this object");
+}
+export { _assertClassBrand as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js b/backend/node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js
new file mode 100644
index 0000000..4a41bde
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js
@@ -0,0 +1,5 @@
+function _assertThisInitialized(e) {
+ if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
+ return e;
+}
+export { _assertThisInitialized as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/asyncGeneratorDelegate.js b/backend/node_modules/@babel/runtime/helpers/esm/asyncGeneratorDelegate.js
new file mode 100644
index 0000000..e026689
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/asyncGeneratorDelegate.js
@@ -0,0 +1,24 @@
+import OverloadYield from "./OverloadYield.js";
+function _asyncGeneratorDelegate(t) {
+ var e = {},
+ n = !1;
+ function pump(e, r) {
+ return n = !0, r = new Promise(function (n) {
+ n(t[e](r));
+ }), {
+ done: !1,
+ value: new OverloadYield(r, 1)
+ };
+ }
+ return e["undefined" != typeof Symbol && Symbol.iterator || "@@iterator"] = function () {
+ return this;
+ }, e.next = function (t) {
+ return n ? (n = !1, t) : pump("next", t);
+ }, "function" == typeof t["throw"] && (e["throw"] = function (t) {
+ if (n) throw n = !1, t;
+ return pump("throw", t);
+ }), "function" == typeof t["return"] && (e["return"] = function (t) {
+ return n ? (n = !1, t) : pump("return", t);
+ }), e;
+}
+export { _asyncGeneratorDelegate as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/asyncIterator.js b/backend/node_modules/@babel/runtime/helpers/esm/asyncIterator.js
new file mode 100644
index 0000000..2ed00b7
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/asyncIterator.js
@@ -0,0 +1,45 @@
+function _asyncIterator(r) {
+ var n,
+ t,
+ o,
+ e = 2;
+ for ("undefined" != typeof Symbol && (t = Symbol.asyncIterator, o = Symbol.iterator); e--;) {
+ if (t && null != (n = r[t])) return n.call(r);
+ if (o && null != (n = r[o])) return new AsyncFromSyncIterator(n.call(r));
+ t = "@@asyncIterator", o = "@@iterator";
+ }
+ throw new TypeError("Object is not async iterable");
+}
+function AsyncFromSyncIterator(r) {
+ function AsyncFromSyncIteratorContinuation(r) {
+ if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object."));
+ var n = r.done;
+ return Promise.resolve(r.value).then(function (r) {
+ return {
+ value: r,
+ done: n
+ };
+ });
+ }
+ return AsyncFromSyncIterator = function AsyncFromSyncIterator(r) {
+ this.s = r, this.n = r.next;
+ }, AsyncFromSyncIterator.prototype = {
+ s: null,
+ n: null,
+ next: function next() {
+ return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));
+ },
+ "return": function _return(r) {
+ var n = this.s["return"];
+ return void 0 === n ? Promise.resolve({
+ value: r,
+ done: !0
+ }) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments));
+ },
+ "throw": function _throw(r) {
+ var n = this.s["return"];
+ return void 0 === n ? Promise.reject(r) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments));
+ }
+ }, new AsyncFromSyncIterator(r);
+}
+export { _asyncIterator as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js b/backend/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js
new file mode 100644
index 0000000..00f29b1
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js
@@ -0,0 +1,26 @@
+function asyncGeneratorStep(n, t, e, r, o, a, c) {
+ try {
+ var i = n[a](c),
+ u = i.value;
+ } catch (n) {
+ return void e(n);
+ }
+ i.done ? t(u) : Promise.resolve(u).then(r, o);
+}
+function _asyncToGenerator(n) {
+ return function () {
+ var t = this,
+ e = arguments;
+ return new Promise(function (r, o) {
+ var a = n.apply(t, e);
+ function _next(n) {
+ asyncGeneratorStep(a, r, o, _next, _throw, "next", n);
+ }
+ function _throw(n) {
+ asyncGeneratorStep(a, r, o, _next, _throw, "throw", n);
+ }
+ _next(void 0);
+ });
+ };
+}
+export { _asyncToGenerator as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/awaitAsyncGenerator.js b/backend/node_modules/@babel/runtime/helpers/esm/awaitAsyncGenerator.js
new file mode 100644
index 0000000..097c88c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/awaitAsyncGenerator.js
@@ -0,0 +1,5 @@
+import OverloadYield from "./OverloadYield.js";
+function _awaitAsyncGenerator(e) {
+ return new OverloadYield(e, 0);
+}
+export { _awaitAsyncGenerator as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/callSuper.js b/backend/node_modules/@babel/runtime/helpers/esm/callSuper.js
new file mode 100644
index 0000000..6d17a4e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/callSuper.js
@@ -0,0 +1,7 @@
+import getPrototypeOf from "./getPrototypeOf.js";
+import isNativeReflectConstruct from "./isNativeReflectConstruct.js";
+import possibleConstructorReturn from "./possibleConstructorReturn.js";
+function _callSuper(t, o, e) {
+ return o = getPrototypeOf(o), possibleConstructorReturn(t, isNativeReflectConstruct() ? Reflect.construct(o, e || [], getPrototypeOf(t).constructor) : o.apply(t, e));
+}
+export { _callSuper as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/checkInRHS.js b/backend/node_modules/@babel/runtime/helpers/esm/checkInRHS.js
new file mode 100644
index 0000000..12f59b4
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/checkInRHS.js
@@ -0,0 +1,6 @@
+import _typeof from "./typeof.js";
+function _checkInRHS(e) {
+ if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? _typeof(e) : "null"));
+ return e;
+}
+export { _checkInRHS as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/checkPrivateRedeclaration.js b/backend/node_modules/@babel/runtime/helpers/esm/checkPrivateRedeclaration.js
new file mode 100644
index 0000000..e9e6b3b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/checkPrivateRedeclaration.js
@@ -0,0 +1,4 @@
+function _checkPrivateRedeclaration(e, t) {
+ if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
+}
+export { _checkPrivateRedeclaration as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classApplyDescriptorDestructureSet.js b/backend/node_modules/@babel/runtime/helpers/esm/classApplyDescriptorDestructureSet.js
new file mode 100644
index 0000000..5623419
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classApplyDescriptorDestructureSet.js
@@ -0,0 +1,10 @@
+function _classApplyDescriptorDestructureSet(e, t) {
+ if (t.set) return "__destrObj" in t || (t.__destrObj = {
+ set value(r) {
+ t.set.call(e, r);
+ }
+ }), t.__destrObj;
+ if (!t.writable) throw new TypeError("attempted to set read only private field");
+ return t;
+}
+export { _classApplyDescriptorDestructureSet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classApplyDescriptorGet.js b/backend/node_modules/@babel/runtime/helpers/esm/classApplyDescriptorGet.js
new file mode 100644
index 0000000..b9259d3
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classApplyDescriptorGet.js
@@ -0,0 +1,4 @@
+function _classApplyDescriptorGet(e, t) {
+ return t.get ? t.get.call(e) : t.value;
+}
+export { _classApplyDescriptorGet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classApplyDescriptorSet.js b/backend/node_modules/@babel/runtime/helpers/esm/classApplyDescriptorSet.js
new file mode 100644
index 0000000..d9c4fbd
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classApplyDescriptorSet.js
@@ -0,0 +1,7 @@
+function _classApplyDescriptorSet(e, t, l) {
+ if (t.set) t.set.call(e, l);else {
+ if (!t.writable) throw new TypeError("attempted to set read only private field");
+ t.value = l;
+ }
+}
+export { _classApplyDescriptorSet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classCallCheck.js b/backend/node_modules/@babel/runtime/helpers/esm/classCallCheck.js
new file mode 100644
index 0000000..bf97219
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classCallCheck.js
@@ -0,0 +1,4 @@
+function _classCallCheck(a, n) {
+ if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function");
+}
+export { _classCallCheck as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classCheckPrivateStaticAccess.js b/backend/node_modules/@babel/runtime/helpers/esm/classCheckPrivateStaticAccess.js
new file mode 100644
index 0000000..366ed05
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classCheckPrivateStaticAccess.js
@@ -0,0 +1,5 @@
+import assertClassBrand from "./assertClassBrand.js";
+function _classCheckPrivateStaticAccess(s, a, r) {
+ return assertClassBrand(a, s, r);
+}
+export { _classCheckPrivateStaticAccess as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classCheckPrivateStaticFieldDescriptor.js b/backend/node_modules/@babel/runtime/helpers/esm/classCheckPrivateStaticFieldDescriptor.js
new file mode 100644
index 0000000..844be91
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classCheckPrivateStaticFieldDescriptor.js
@@ -0,0 +1,4 @@
+function _classCheckPrivateStaticFieldDescriptor(t, e) {
+ if (void 0 === t) throw new TypeError("attempted to " + e + " private static field before its declaration");
+}
+export { _classCheckPrivateStaticFieldDescriptor as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classExtractFieldDescriptor.js b/backend/node_modules/@babel/runtime/helpers/esm/classExtractFieldDescriptor.js
new file mode 100644
index 0000000..652689d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classExtractFieldDescriptor.js
@@ -0,0 +1,5 @@
+import classPrivateFieldGet2 from "./classPrivateFieldGet2.js";
+function _classExtractFieldDescriptor(e, t) {
+ return classPrivateFieldGet2(t, e);
+}
+export { _classExtractFieldDescriptor as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classNameTDZError.js b/backend/node_modules/@babel/runtime/helpers/esm/classNameTDZError.js
new file mode 100644
index 0000000..68e76ff
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classNameTDZError.js
@@ -0,0 +1,4 @@
+function _classNameTDZError(e) {
+ throw new ReferenceError('Class "' + e + '" cannot be referenced in computed property keys.');
+}
+export { _classNameTDZError as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldDestructureSet.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldDestructureSet.js
new file mode 100644
index 0000000..9303366
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldDestructureSet.js
@@ -0,0 +1,7 @@
+import classApplyDescriptorDestructureSet from "./classApplyDescriptorDestructureSet.js";
+import classPrivateFieldGet2 from "./classPrivateFieldGet2.js";
+function _classPrivateFieldDestructureSet(e, t) {
+ var r = classPrivateFieldGet2(t, e);
+ return classApplyDescriptorDestructureSet(e, r);
+}
+export { _classPrivateFieldDestructureSet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldGet.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldGet.js
new file mode 100644
index 0000000..ce7ebcb
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldGet.js
@@ -0,0 +1,7 @@
+import classApplyDescriptorGet from "./classApplyDescriptorGet.js";
+import classPrivateFieldGet2 from "./classPrivateFieldGet2.js";
+function _classPrivateFieldGet(e, t) {
+ var r = classPrivateFieldGet2(t, e);
+ return classApplyDescriptorGet(e, r);
+}
+export { _classPrivateFieldGet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldGet2.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldGet2.js
new file mode 100644
index 0000000..4aa3da6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldGet2.js
@@ -0,0 +1,5 @@
+import assertClassBrand from "./assertClassBrand.js";
+function _classPrivateFieldGet2(s, a) {
+ return s.get(assertClassBrand(s, a));
+}
+export { _classPrivateFieldGet2 as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldInitSpec.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldInitSpec.js
new file mode 100644
index 0000000..5dcdbe0
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldInitSpec.js
@@ -0,0 +1,5 @@
+import checkPrivateRedeclaration from "./checkPrivateRedeclaration.js";
+function _classPrivateFieldInitSpec(e, t, a) {
+ checkPrivateRedeclaration(e, t), t.set(e, a);
+}
+export { _classPrivateFieldInitSpec as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldLooseBase.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldLooseBase.js
new file mode 100644
index 0000000..4bd662c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldLooseBase.js
@@ -0,0 +1,5 @@
+function _classPrivateFieldBase(e, t) {
+ if (!{}.hasOwnProperty.call(e, t)) throw new TypeError("attempted to use private field on non-instance");
+ return e;
+}
+export { _classPrivateFieldBase as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldLooseKey.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldLooseKey.js
new file mode 100644
index 0000000..90d2193
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldLooseKey.js
@@ -0,0 +1,5 @@
+var id = 0;
+function _classPrivateFieldKey(e) {
+ return "__private_" + id++ + "_" + e;
+}
+export { _classPrivateFieldKey as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldSet.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldSet.js
new file mode 100644
index 0000000..b5161bd
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldSet.js
@@ -0,0 +1,7 @@
+import classApplyDescriptorSet from "./classApplyDescriptorSet.js";
+import classPrivateFieldGet2 from "./classPrivateFieldGet2.js";
+function _classPrivateFieldSet(e, t, r) {
+ var s = classPrivateFieldGet2(t, e);
+ return classApplyDescriptorSet(e, s, r), r;
+}
+export { _classPrivateFieldSet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldSet2.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldSet2.js
new file mode 100644
index 0000000..337b01a
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateFieldSet2.js
@@ -0,0 +1,5 @@
+import assertClassBrand from "./assertClassBrand.js";
+function _classPrivateFieldSet2(s, a, r) {
+ return s.set(assertClassBrand(s, a), r), r;
+}
+export { _classPrivateFieldSet2 as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateGetter.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateGetter.js
new file mode 100644
index 0000000..ff3e985
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateGetter.js
@@ -0,0 +1,5 @@
+import assertClassBrand from "./assertClassBrand.js";
+function _classPrivateGetter(s, r, a) {
+ return a(assertClassBrand(s, r));
+}
+export { _classPrivateGetter as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateMethodGet.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateMethodGet.js
new file mode 100644
index 0000000..4832fc6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateMethodGet.js
@@ -0,0 +1,5 @@
+import assertClassBrand from "./assertClassBrand.js";
+function _classPrivateMethodGet(s, a, r) {
+ return assertClassBrand(a, s), r;
+}
+export { _classPrivateMethodGet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateMethodInitSpec.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateMethodInitSpec.js
new file mode 100644
index 0000000..61e23e2
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateMethodInitSpec.js
@@ -0,0 +1,5 @@
+import checkPrivateRedeclaration from "./checkPrivateRedeclaration.js";
+function _classPrivateMethodInitSpec(e, a) {
+ checkPrivateRedeclaration(e, a), a.add(e);
+}
+export { _classPrivateMethodInitSpec as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateMethodSet.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateMethodSet.js
new file mode 100644
index 0000000..d181b51
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateMethodSet.js
@@ -0,0 +1,4 @@
+function _classPrivateMethodSet() {
+ throw new TypeError("attempted to reassign private method");
+}
+export { _classPrivateMethodSet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classPrivateSetter.js b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateSetter.js
new file mode 100644
index 0000000..9a80d59
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classPrivateSetter.js
@@ -0,0 +1,5 @@
+import assertClassBrand from "./assertClassBrand.js";
+function _classPrivateSetter(s, r, a, t) {
+ return r(assertClassBrand(s, a), t), t;
+}
+export { _classPrivateSetter as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateFieldDestructureSet.js b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateFieldDestructureSet.js
new file mode 100644
index 0000000..747e639
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateFieldDestructureSet.js
@@ -0,0 +1,7 @@
+import classApplyDescriptorDestructureSet from "./classApplyDescriptorDestructureSet.js";
+import assertClassBrand from "./assertClassBrand.js";
+import classCheckPrivateStaticFieldDescriptor from "./classCheckPrivateStaticFieldDescriptor.js";
+function _classStaticPrivateFieldDestructureSet(t, r, s) {
+ return assertClassBrand(r, t), classCheckPrivateStaticFieldDescriptor(s, "set"), classApplyDescriptorDestructureSet(t, s);
+}
+export { _classStaticPrivateFieldDestructureSet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateFieldSpecGet.js b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateFieldSpecGet.js
new file mode 100644
index 0000000..23684b7
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateFieldSpecGet.js
@@ -0,0 +1,7 @@
+import classApplyDescriptorGet from "./classApplyDescriptorGet.js";
+import assertClassBrand from "./assertClassBrand.js";
+import classCheckPrivateStaticFieldDescriptor from "./classCheckPrivateStaticFieldDescriptor.js";
+function _classStaticPrivateFieldSpecGet(t, s, r) {
+ return assertClassBrand(s, t), classCheckPrivateStaticFieldDescriptor(r, "get"), classApplyDescriptorGet(t, r);
+}
+export { _classStaticPrivateFieldSpecGet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateFieldSpecSet.js b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateFieldSpecSet.js
new file mode 100644
index 0000000..3a31468
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateFieldSpecSet.js
@@ -0,0 +1,7 @@
+import classApplyDescriptorSet from "./classApplyDescriptorSet.js";
+import assertClassBrand from "./assertClassBrand.js";
+import classCheckPrivateStaticFieldDescriptor from "./classCheckPrivateStaticFieldDescriptor.js";
+function _classStaticPrivateFieldSpecSet(s, t, r, e) {
+ return assertClassBrand(t, s), classCheckPrivateStaticFieldDescriptor(r, "set"), classApplyDescriptorSet(s, r, e), e;
+}
+export { _classStaticPrivateFieldSpecSet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateMethodGet.js b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateMethodGet.js
new file mode 100644
index 0000000..047b177
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateMethodGet.js
@@ -0,0 +1,5 @@
+import assertClassBrand from "./assertClassBrand.js";
+function _classStaticPrivateMethodGet(s, a, t) {
+ return assertClassBrand(a, s), t;
+}
+export { _classStaticPrivateMethodGet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateMethodSet.js b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateMethodSet.js
new file mode 100644
index 0000000..a61ae63
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/classStaticPrivateMethodSet.js
@@ -0,0 +1,4 @@
+function _classStaticPrivateMethodSet() {
+ throw new TypeError("attempted to set read only static private field");
+}
+export { _classStaticPrivateMethodSet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/construct.js b/backend/node_modules/@babel/runtime/helpers/esm/construct.js
new file mode 100644
index 0000000..91609ff
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/construct.js
@@ -0,0 +1,10 @@
+import isNativeReflectConstruct from "./isNativeReflectConstruct.js";
+import setPrototypeOf from "./setPrototypeOf.js";
+function _construct(t, e, r) {
+ if (isNativeReflectConstruct()) return Reflect.construct.apply(null, arguments);
+ var o = [null];
+ o.push.apply(o, e);
+ var p = new (t.bind.apply(t, o))();
+ return r && setPrototypeOf(p, r.prototype), p;
+}
+export { _construct as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/createClass.js b/backend/node_modules/@babel/runtime/helpers/esm/createClass.js
new file mode 100644
index 0000000..9b17851
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/createClass.js
@@ -0,0 +1,13 @@
+import toPropertyKey from "./toPropertyKey.js";
+function _defineProperties(e, r) {
+ for (var t = 0; t < r.length; t++) {
+ var o = r[t];
+ o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, toPropertyKey(o.key), o);
+ }
+}
+function _createClass(e, r, t) {
+ return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", {
+ writable: !1
+ }), e;
+}
+export { _createClass as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/createForOfIteratorHelper.js b/backend/node_modules/@babel/runtime/helpers/esm/createForOfIteratorHelper.js
new file mode 100644
index 0000000..93b97f9
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/createForOfIteratorHelper.js
@@ -0,0 +1,50 @@
+import unsupportedIterableToArray from "./unsupportedIterableToArray.js";
+function _createForOfIteratorHelper(r, e) {
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
+ if (!t) {
+ if (Array.isArray(r) || (t = unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
+ t && (r = t);
+ var _n = 0,
+ F = function F() {};
+ return {
+ s: F,
+ n: function n() {
+ return _n >= r.length ? {
+ done: !0
+ } : {
+ done: !1,
+ value: r[_n++]
+ };
+ },
+ e: function e(r) {
+ throw r;
+ },
+ f: F
+ };
+ }
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+ }
+ var o,
+ a = !0,
+ u = !1;
+ return {
+ s: function s() {
+ t = t.call(r);
+ },
+ n: function n() {
+ var r = t.next();
+ return a = r.done, r;
+ },
+ e: function e(r) {
+ u = !0, o = r;
+ },
+ f: function f() {
+ try {
+ a || null == t["return"] || t["return"]();
+ } finally {
+ if (u) throw o;
+ }
+ }
+ };
+}
+export { _createForOfIteratorHelper as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/createForOfIteratorHelperLoose.js b/backend/node_modules/@babel/runtime/helpers/esm/createForOfIteratorHelperLoose.js
new file mode 100644
index 0000000..3deaae4
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/createForOfIteratorHelperLoose.js
@@ -0,0 +1,19 @@
+import unsupportedIterableToArray from "./unsupportedIterableToArray.js";
+function _createForOfIteratorHelperLoose(r, e) {
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
+ if (t) return (t = t.call(r)).next.bind(t);
+ if (Array.isArray(r) || (t = unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
+ t && (r = t);
+ var o = 0;
+ return function () {
+ return o >= r.length ? {
+ done: !0
+ } : {
+ done: !1,
+ value: r[o++]
+ };
+ };
+ }
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+}
+export { _createForOfIteratorHelperLoose as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/createSuper.js b/backend/node_modules/@babel/runtime/helpers/esm/createSuper.js
new file mode 100644
index 0000000..dfabf71
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/createSuper.js
@@ -0,0 +1,16 @@
+import getPrototypeOf from "./getPrototypeOf.js";
+import isNativeReflectConstruct from "./isNativeReflectConstruct.js";
+import possibleConstructorReturn from "./possibleConstructorReturn.js";
+function _createSuper(t) {
+ var r = isNativeReflectConstruct();
+ return function () {
+ var e,
+ o = getPrototypeOf(t);
+ if (r) {
+ var s = getPrototypeOf(this).constructor;
+ e = Reflect.construct(o, arguments, s);
+ } else e = o.apply(this, arguments);
+ return possibleConstructorReturn(this, e);
+ };
+}
+export { _createSuper as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/decorate.js b/backend/node_modules/@babel/runtime/helpers/esm/decorate.js
new file mode 100644
index 0000000..f76b6a6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/decorate.js
@@ -0,0 +1,250 @@
+import toArray from "./toArray.js";
+import toPropertyKey from "./toPropertyKey.js";
+function _decorate(e, r, t, i) {
+ var o = _getDecoratorsApi();
+ if (i) for (var n = 0; n < i.length; n++) o = i[n](o);
+ var s = r(function (e) {
+ o.initializeInstanceElements(e, a.elements);
+ }, t),
+ a = o.decorateClass(_coalesceClassElements(s.d.map(_createElementDescriptor)), e);
+ return o.initializeClassElements(s.F, a.elements), o.runClassFinishers(s.F, a.finishers);
+}
+function _getDecoratorsApi() {
+ _getDecoratorsApi = function _getDecoratorsApi() {
+ return e;
+ };
+ var e = {
+ elementsDefinitionOrder: [["method"], ["field"]],
+ initializeInstanceElements: function initializeInstanceElements(e, r) {
+ ["method", "field"].forEach(function (t) {
+ r.forEach(function (r) {
+ r.kind === t && "own" === r.placement && this.defineClassElement(e, r);
+ }, this);
+ }, this);
+ },
+ initializeClassElements: function initializeClassElements(e, r) {
+ var t = e.prototype;
+ ["method", "field"].forEach(function (i) {
+ r.forEach(function (r) {
+ var o = r.placement;
+ if (r.kind === i && ("static" === o || "prototype" === o)) {
+ var n = "static" === o ? e : t;
+ this.defineClassElement(n, r);
+ }
+ }, this);
+ }, this);
+ },
+ defineClassElement: function defineClassElement(e, r) {
+ var t = r.descriptor;
+ if ("field" === r.kind) {
+ var i = r.initializer;
+ t = {
+ enumerable: t.enumerable,
+ writable: t.writable,
+ configurable: t.configurable,
+ value: void 0 === i ? void 0 : i.call(e)
+ };
+ }
+ Object.defineProperty(e, r.key, t);
+ },
+ decorateClass: function decorateClass(e, r) {
+ var t = [],
+ i = [],
+ o = {
+ "static": [],
+ prototype: [],
+ own: []
+ };
+ if (e.forEach(function (e) {
+ this.addElementPlacement(e, o);
+ }, this), e.forEach(function (e) {
+ if (!_hasDecorators(e)) return t.push(e);
+ var r = this.decorateElement(e, o);
+ t.push(r.element), t.push.apply(t, r.extras), i.push.apply(i, r.finishers);
+ }, this), !r) return {
+ elements: t,
+ finishers: i
+ };
+ var n = this.decorateConstructor(t, r);
+ return i.push.apply(i, n.finishers), n.finishers = i, n;
+ },
+ addElementPlacement: function addElementPlacement(e, r, t) {
+ var i = r[e.placement];
+ if (!t && -1 !== i.indexOf(e.key)) throw new TypeError("Duplicated element (" + e.key + ")");
+ i.push(e.key);
+ },
+ decorateElement: function decorateElement(e, r) {
+ for (var t = [], i = [], o = e.decorators, n = o.length - 1; n >= 0; n--) {
+ var s = r[e.placement];
+ s.splice(s.indexOf(e.key), 1);
+ var a = this.fromElementDescriptor(e),
+ l = this.toElementFinisherExtras((0, o[n])(a) || a);
+ e = l.element, this.addElementPlacement(e, r), l.finisher && i.push(l.finisher);
+ var c = l.extras;
+ if (c) {
+ for (var p = 0; p < c.length; p++) this.addElementPlacement(c[p], r);
+ t.push.apply(t, c);
+ }
+ }
+ return {
+ element: e,
+ finishers: i,
+ extras: t
+ };
+ },
+ decorateConstructor: function decorateConstructor(e, r) {
+ for (var t = [], i = r.length - 1; i >= 0; i--) {
+ var o = this.fromClassDescriptor(e),
+ n = this.toClassDescriptor((0, r[i])(o) || o);
+ if (void 0 !== n.finisher && t.push(n.finisher), void 0 !== n.elements) {
+ e = n.elements;
+ for (var s = 0; s < e.length - 1; s++) for (var a = s + 1; a < e.length; a++) if (e[s].key === e[a].key && e[s].placement === e[a].placement) throw new TypeError("Duplicated element (" + e[s].key + ")");
+ }
+ }
+ return {
+ elements: e,
+ finishers: t
+ };
+ },
+ fromElementDescriptor: function fromElementDescriptor(e) {
+ var r = {
+ kind: e.kind,
+ key: e.key,
+ placement: e.placement,
+ descriptor: e.descriptor
+ };
+ return Object.defineProperty(r, Symbol.toStringTag, {
+ value: "Descriptor",
+ configurable: !0
+ }), "field" === e.kind && (r.initializer = e.initializer), r;
+ },
+ toElementDescriptors: function toElementDescriptors(e) {
+ if (void 0 !== e) return toArray(e).map(function (e) {
+ var r = this.toElementDescriptor(e);
+ return this.disallowProperty(e, "finisher", "An element descriptor"), this.disallowProperty(e, "extras", "An element descriptor"), r;
+ }, this);
+ },
+ toElementDescriptor: function toElementDescriptor(e) {
+ var r = e.kind + "";
+ if ("method" !== r && "field" !== r) throw new TypeError('An element descriptor\'s .kind property must be either "method" or "field", but a decorator created an element descriptor with .kind "' + r + '"');
+ var t = toPropertyKey(e.key),
+ i = e.placement + "";
+ if ("static" !== i && "prototype" !== i && "own" !== i) throw new TypeError('An element descriptor\'s .placement property must be one of "static", "prototype" or "own", but a decorator created an element descriptor with .placement "' + i + '"');
+ var o = e.descriptor;
+ this.disallowProperty(e, "elements", "An element descriptor");
+ var n = {
+ kind: r,
+ key: t,
+ placement: i,
+ descriptor: Object.assign({}, o)
+ };
+ return "field" !== r ? this.disallowProperty(e, "initializer", "A method descriptor") : (this.disallowProperty(o, "get", "The property descriptor of a field descriptor"), this.disallowProperty(o, "set", "The property descriptor of a field descriptor"), this.disallowProperty(o, "value", "The property descriptor of a field descriptor"), n.initializer = e.initializer), n;
+ },
+ toElementFinisherExtras: function toElementFinisherExtras(e) {
+ return {
+ element: this.toElementDescriptor(e),
+ finisher: _optionalCallableProperty(e, "finisher"),
+ extras: this.toElementDescriptors(e.extras)
+ };
+ },
+ fromClassDescriptor: function fromClassDescriptor(e) {
+ var r = {
+ kind: "class",
+ elements: e.map(this.fromElementDescriptor, this)
+ };
+ return Object.defineProperty(r, Symbol.toStringTag, {
+ value: "Descriptor",
+ configurable: !0
+ }), r;
+ },
+ toClassDescriptor: function toClassDescriptor(e) {
+ var r = e.kind + "";
+ if ("class" !== r) throw new TypeError('A class descriptor\'s .kind property must be "class", but a decorator created a class descriptor with .kind "' + r + '"');
+ this.disallowProperty(e, "key", "A class descriptor"), this.disallowProperty(e, "placement", "A class descriptor"), this.disallowProperty(e, "descriptor", "A class descriptor"), this.disallowProperty(e, "initializer", "A class descriptor"), this.disallowProperty(e, "extras", "A class descriptor");
+ var t = _optionalCallableProperty(e, "finisher");
+ return {
+ elements: this.toElementDescriptors(e.elements),
+ finisher: t
+ };
+ },
+ runClassFinishers: function runClassFinishers(e, r) {
+ for (var t = 0; t < r.length; t++) {
+ var i = (0, r[t])(e);
+ if (void 0 !== i) {
+ if ("function" != typeof i) throw new TypeError("Finishers must return a constructor.");
+ e = i;
+ }
+ }
+ return e;
+ },
+ disallowProperty: function disallowProperty(e, r, t) {
+ if (void 0 !== e[r]) throw new TypeError(t + " can't have a ." + r + " property.");
+ }
+ };
+ return e;
+}
+function _createElementDescriptor(e) {
+ var r,
+ t = toPropertyKey(e.key);
+ "method" === e.kind ? r = {
+ value: e.value,
+ writable: !0,
+ configurable: !0,
+ enumerable: !1
+ } : "get" === e.kind ? r = {
+ get: e.value,
+ configurable: !0,
+ enumerable: !1
+ } : "set" === e.kind ? r = {
+ set: e.value,
+ configurable: !0,
+ enumerable: !1
+ } : "field" === e.kind && (r = {
+ configurable: !0,
+ writable: !0,
+ enumerable: !0
+ });
+ var i = {
+ kind: "field" === e.kind ? "field" : "method",
+ key: t,
+ placement: e["static"] ? "static" : "field" === e.kind ? "own" : "prototype",
+ descriptor: r
+ };
+ return e.decorators && (i.decorators = e.decorators), "field" === e.kind && (i.initializer = e.value), i;
+}
+function _coalesceGetterSetter(e, r) {
+ void 0 !== e.descriptor.get ? r.descriptor.get = e.descriptor.get : r.descriptor.set = e.descriptor.set;
+}
+function _coalesceClassElements(e) {
+ for (var r = [], isSameElement = function isSameElement(e) {
+ return "method" === e.kind && e.key === o.key && e.placement === o.placement;
+ }, t = 0; t < e.length; t++) {
+ var i,
+ o = e[t];
+ if ("method" === o.kind && (i = r.find(isSameElement))) {
+ if (_isDataDescriptor(o.descriptor) || _isDataDescriptor(i.descriptor)) {
+ if (_hasDecorators(o) || _hasDecorators(i)) throw new ReferenceError("Duplicated methods (" + o.key + ") can't be decorated.");
+ i.descriptor = o.descriptor;
+ } else {
+ if (_hasDecorators(o)) {
+ if (_hasDecorators(i)) throw new ReferenceError("Decorators can't be placed on different accessors with for the same property (" + o.key + ").");
+ i.decorators = o.decorators;
+ }
+ _coalesceGetterSetter(o, i);
+ }
+ } else r.push(o);
+ }
+ return r;
+}
+function _hasDecorators(e) {
+ return e.decorators && e.decorators.length;
+}
+function _isDataDescriptor(e) {
+ return void 0 !== e && !(void 0 === e.value && void 0 === e.writable);
+}
+function _optionalCallableProperty(e, r) {
+ var t = e[r];
+ if (void 0 !== t && "function" != typeof t) throw new TypeError("Expected '" + r + "' to be a function");
+ return t;
+}
+export { _decorate as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/defaults.js b/backend/node_modules/@babel/runtime/helpers/esm/defaults.js
new file mode 100644
index 0000000..d3041a3
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/defaults.js
@@ -0,0 +1,9 @@
+function _defaults(e, r) {
+ for (var t = Object.getOwnPropertyNames(r), o = 0; o < t.length; o++) {
+ var n = t[o],
+ a = Object.getOwnPropertyDescriptor(r, n);
+ a && a.configurable && void 0 === e[n] && Object.defineProperty(e, n, a);
+ }
+ return e;
+}
+export { _defaults as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/defineAccessor.js b/backend/node_modules/@babel/runtime/helpers/esm/defineAccessor.js
new file mode 100644
index 0000000..a8292de
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/defineAccessor.js
@@ -0,0 +1,8 @@
+function _defineAccessor(e, r, n, t) {
+ var c = {
+ configurable: !0,
+ enumerable: !0
+ };
+ return c[e] = t, Object.defineProperty(r, n, c);
+}
+export { _defineAccessor as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/defineEnumerableProperties.js b/backend/node_modules/@babel/runtime/helpers/esm/defineEnumerableProperties.js
new file mode 100644
index 0000000..3d31d98
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/defineEnumerableProperties.js
@@ -0,0 +1,12 @@
+function _defineEnumerableProperties(e, r) {
+ for (var t in r) {
+ var n = r[t];
+ n.configurable = n.enumerable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, t, n);
+ }
+ if (Object.getOwnPropertySymbols) for (var a = Object.getOwnPropertySymbols(r), b = 0; b < a.length; b++) {
+ var i = a[b];
+ (n = r[i]).configurable = n.enumerable = !0, "value" in n && (n.writable = !0), Object.defineProperty(e, i, n);
+ }
+ return e;
+}
+export { _defineEnumerableProperties as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/defineProperty.js b/backend/node_modules/@babel/runtime/helpers/esm/defineProperty.js
new file mode 100644
index 0000000..05ec32b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/defineProperty.js
@@ -0,0 +1,10 @@
+import toPropertyKey from "./toPropertyKey.js";
+function _defineProperty(e, r, t) {
+ return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
+ value: t,
+ enumerable: !0,
+ configurable: !0,
+ writable: !0
+ }) : e[r] = t, e;
+}
+export { _defineProperty as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/dispose.js b/backend/node_modules/@babel/runtime/helpers/esm/dispose.js
new file mode 100644
index 0000000..a87ab20
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/dispose.js
@@ -0,0 +1,28 @@
+function dispose_SuppressedError(r, e) {
+ return "undefined" != typeof SuppressedError ? dispose_SuppressedError = SuppressedError : (dispose_SuppressedError = function dispose_SuppressedError(r, e) {
+ this.suppressed = e, this.error = r, this.stack = Error().stack;
+ }, dispose_SuppressedError.prototype = Object.create(Error.prototype, {
+ constructor: {
+ value: dispose_SuppressedError,
+ writable: !0,
+ configurable: !0
+ }
+ })), new dispose_SuppressedError(r, e);
+}
+function _dispose(r, e, s) {
+ function next() {
+ for (; r.length > 0;) try {
+ var o = r.pop(),
+ p = o.d.call(o.v);
+ if (o.a) return Promise.resolve(p).then(next, err);
+ } catch (r) {
+ return err(r);
+ }
+ if (s) throw e;
+ }
+ function err(r) {
+ return e = s ? new dispose_SuppressedError(e, r) : r, s = !0, next();
+ }
+ return next();
+}
+export { _dispose as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/extends.js b/backend/node_modules/@babel/runtime/helpers/esm/extends.js
new file mode 100644
index 0000000..53f118c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/extends.js
@@ -0,0 +1,10 @@
+function _extends() {
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
+ for (var e = 1; e < arguments.length; e++) {
+ var t = arguments[e];
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
+ }
+ return n;
+ }, _extends.apply(null, arguments);
+}
+export { _extends as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/get.js b/backend/node_modules/@babel/runtime/helpers/esm/get.js
new file mode 100644
index 0000000..8124bc0
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/get.js
@@ -0,0 +1,11 @@
+import superPropBase from "./superPropBase.js";
+function _get() {
+ return _get = "undefined" != typeof Reflect && Reflect.get ? Reflect.get.bind() : function (e, t, r) {
+ var p = superPropBase(e, t);
+ if (p) {
+ var n = Object.getOwnPropertyDescriptor(p, t);
+ return n.get ? n.get.call(arguments.length < 3 ? e : r) : n.value;
+ }
+ }, _get.apply(null, arguments);
+}
+export { _get as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/getPrototypeOf.js b/backend/node_modules/@babel/runtime/helpers/esm/getPrototypeOf.js
new file mode 100644
index 0000000..9073c45
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/getPrototypeOf.js
@@ -0,0 +1,6 @@
+function _getPrototypeOf(t) {
+ return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
+ return t.__proto__ || Object.getPrototypeOf(t);
+ }, _getPrototypeOf(t);
+}
+export { _getPrototypeOf as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/identity.js b/backend/node_modules/@babel/runtime/helpers/esm/identity.js
new file mode 100644
index 0000000..6b564ac
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/identity.js
@@ -0,0 +1,4 @@
+function _identity(t) {
+ return t;
+}
+export { _identity as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/importDeferProxy.js b/backend/node_modules/@babel/runtime/helpers/esm/importDeferProxy.js
new file mode 100644
index 0000000..6d35b52
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/importDeferProxy.js
@@ -0,0 +1,27 @@
+function _importDeferProxy(e) {
+ var t = null,
+ constValue = function constValue(e) {
+ return function () {
+ return e;
+ };
+ },
+ proxy = function proxy(r) {
+ return function (n, o, f) {
+ return null === t && (t = e()), r(t, o, f);
+ };
+ };
+ return new Proxy({}, {
+ defineProperty: constValue(!1),
+ deleteProperty: constValue(!1),
+ get: proxy(Reflect.get),
+ getOwnPropertyDescriptor: proxy(Reflect.getOwnPropertyDescriptor),
+ getPrototypeOf: constValue(null),
+ isExtensible: constValue(!1),
+ has: proxy(Reflect.has),
+ ownKeys: proxy(Reflect.ownKeys),
+ preventExtensions: constValue(!0),
+ set: constValue(!1),
+ setPrototypeOf: constValue(!1)
+ });
+}
+export { _importDeferProxy as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/inherits.js b/backend/node_modules/@babel/runtime/helpers/esm/inherits.js
new file mode 100644
index 0000000..78f6e4e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/inherits.js
@@ -0,0 +1,14 @@
+import setPrototypeOf from "./setPrototypeOf.js";
+function _inherits(t, e) {
+ if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
+ t.prototype = Object.create(e && e.prototype, {
+ constructor: {
+ value: t,
+ writable: !0,
+ configurable: !0
+ }
+ }), Object.defineProperty(t, "prototype", {
+ writable: !1
+ }), e && setPrototypeOf(t, e);
+}
+export { _inherits as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/inheritsLoose.js b/backend/node_modules/@babel/runtime/helpers/esm/inheritsLoose.js
new file mode 100644
index 0000000..0bd1330
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/inheritsLoose.js
@@ -0,0 +1,5 @@
+import setPrototypeOf from "./setPrototypeOf.js";
+function _inheritsLoose(t, o) {
+ t.prototype = Object.create(o.prototype), t.prototype.constructor = t, setPrototypeOf(t, o);
+}
+export { _inheritsLoose as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/initializerDefineProperty.js b/backend/node_modules/@babel/runtime/helpers/esm/initializerDefineProperty.js
new file mode 100644
index 0000000..68bcc2c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/initializerDefineProperty.js
@@ -0,0 +1,9 @@
+function _initializerDefineProperty(e, i, r, l) {
+ r && Object.defineProperty(e, i, {
+ enumerable: r.enumerable,
+ configurable: r.configurable,
+ writable: r.writable,
+ value: r.initializer ? r.initializer.call(l) : void 0
+ });
+}
+export { _initializerDefineProperty as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/initializerWarningHelper.js b/backend/node_modules/@babel/runtime/helpers/esm/initializerWarningHelper.js
new file mode 100644
index 0000000..0a658e3
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/initializerWarningHelper.js
@@ -0,0 +1,4 @@
+function _initializerWarningHelper(r, e) {
+ throw Error("Decorating class property failed. Please ensure that transform-class-properties is enabled and runs after the decorators transform.");
+}
+export { _initializerWarningHelper as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/instanceof.js b/backend/node_modules/@babel/runtime/helpers/esm/instanceof.js
new file mode 100644
index 0000000..316539e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/instanceof.js
@@ -0,0 +1,4 @@
+function _instanceof(n, e) {
+ return null != e && "undefined" != typeof Symbol && e[Symbol.hasInstance] ? !!e[Symbol.hasInstance](n) : n instanceof e;
+}
+export { _instanceof as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/interopRequireDefault.js b/backend/node_modules/@babel/runtime/helpers/esm/interopRequireDefault.js
new file mode 100644
index 0000000..365d248
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/interopRequireDefault.js
@@ -0,0 +1,6 @@
+function _interopRequireDefault(e) {
+ return e && e.__esModule ? e : {
+ "default": e
+ };
+}
+export { _interopRequireDefault as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/interopRequireWildcard.js b/backend/node_modules/@babel/runtime/helpers/esm/interopRequireWildcard.js
new file mode 100644
index 0000000..ed9ca31
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/interopRequireWildcard.js
@@ -0,0 +1,22 @@
+import _typeof from "./typeof.js";
+function _interopRequireWildcard(e, t) {
+ if ("function" == typeof WeakMap) var r = new WeakMap(),
+ n = new WeakMap();
+ return (_interopRequireWildcard = function _interopRequireWildcard(e, t) {
+ if (!t && e && e.__esModule) return e;
+ var o,
+ i,
+ f = {
+ __proto__: null,
+ "default": e
+ };
+ if (null === e || "object" != _typeof(e) && "function" != typeof e) return f;
+ if (o = t ? n : r) {
+ if (o.has(e)) return o.get(e);
+ o.set(e, f);
+ }
+ for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]);
+ return f;
+ })(e, t);
+}
+export { _interopRequireWildcard as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/isNativeFunction.js b/backend/node_modules/@babel/runtime/helpers/esm/isNativeFunction.js
new file mode 100644
index 0000000..0cfe276
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/isNativeFunction.js
@@ -0,0 +1,8 @@
+function _isNativeFunction(t) {
+ try {
+ return -1 !== Function.toString.call(t).indexOf("[native code]");
+ } catch (n) {
+ return "function" == typeof t;
+ }
+}
+export { _isNativeFunction as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/isNativeReflectConstruct.js b/backend/node_modules/@babel/runtime/helpers/esm/isNativeReflectConstruct.js
new file mode 100644
index 0000000..0eb5e39
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/isNativeReflectConstruct.js
@@ -0,0 +1,9 @@
+function _isNativeReflectConstruct() {
+ try {
+ var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
+ } catch (t) {}
+ return (_isNativeReflectConstruct = function _isNativeReflectConstruct() {
+ return !!t;
+ })();
+}
+export { _isNativeReflectConstruct as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/iterableToArray.js b/backend/node_modules/@babel/runtime/helpers/esm/iterableToArray.js
new file mode 100644
index 0000000..b7de339
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/iterableToArray.js
@@ -0,0 +1,4 @@
+function _iterableToArray(r) {
+ if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
+}
+export { _iterableToArray as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/iterableToArrayLimit.js b/backend/node_modules/@babel/runtime/helpers/esm/iterableToArrayLimit.js
new file mode 100644
index 0000000..473f067
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/iterableToArrayLimit.js
@@ -0,0 +1,28 @@
+function _iterableToArrayLimit(r, l) {
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
+ if (null != t) {
+ var e,
+ n,
+ i,
+ u,
+ a = [],
+ f = !0,
+ o = !1;
+ try {
+ if (i = (t = t.call(r)).next, 0 === l) {
+ if (Object(t) !== t) return;
+ f = !1;
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
+ } catch (r) {
+ o = !0, n = r;
+ } finally {
+ try {
+ if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return;
+ } finally {
+ if (o) throw n;
+ }
+ }
+ return a;
+ }
+}
+export { _iterableToArrayLimit as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/jsx.js b/backend/node_modules/@babel/runtime/helpers/esm/jsx.js
new file mode 100644
index 0000000..a120e5b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/jsx.js
@@ -0,0 +1,22 @@
+var REACT_ELEMENT_TYPE;
+function _createRawReactElement(e, r, E, l) {
+ REACT_ELEMENT_TYPE || (REACT_ELEMENT_TYPE = "function" == typeof Symbol && Symbol["for"] && Symbol["for"]("react.element") || 60103);
+ var o = e && e.defaultProps,
+ n = arguments.length - 3;
+ if (r || 0 === n || (r = {
+ children: void 0
+ }), 1 === n) r.children = l;else if (n > 1) {
+ for (var t = Array(n), f = 0; f < n; f++) t[f] = arguments[f + 3];
+ r.children = t;
+ }
+ if (r && o) for (var i in o) void 0 === r[i] && (r[i] = o[i]);else r || (r = o || {});
+ return {
+ $$typeof: REACT_ELEMENT_TYPE,
+ type: e,
+ key: void 0 === E ? null : "" + E,
+ ref: null,
+ props: r,
+ _owner: null
+ };
+}
+export { _createRawReactElement as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/maybeArrayLike.js b/backend/node_modules/@babel/runtime/helpers/esm/maybeArrayLike.js
new file mode 100644
index 0000000..527c682
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/maybeArrayLike.js
@@ -0,0 +1,9 @@
+import arrayLikeToArray from "./arrayLikeToArray.js";
+function _maybeArrayLike(r, a, e) {
+ if (a && !Array.isArray(a) && "number" == typeof a.length) {
+ var y = a.length;
+ return arrayLikeToArray(a, void 0 !== e && e < y ? e : y);
+ }
+ return r(a, e);
+}
+export { _maybeArrayLike as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/newArrowCheck.js b/backend/node_modules/@babel/runtime/helpers/esm/newArrowCheck.js
new file mode 100644
index 0000000..5f70e0d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/newArrowCheck.js
@@ -0,0 +1,4 @@
+function _newArrowCheck(n, r) {
+ if (n !== r) throw new TypeError("Cannot instantiate an arrow function");
+}
+export { _newArrowCheck as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/nonIterableRest.js b/backend/node_modules/@babel/runtime/helpers/esm/nonIterableRest.js
new file mode 100644
index 0000000..9050250
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/nonIterableRest.js
@@ -0,0 +1,4 @@
+function _nonIterableRest() {
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+}
+export { _nonIterableRest as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js b/backend/node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js
new file mode 100644
index 0000000..fb03235
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/nonIterableSpread.js
@@ -0,0 +1,4 @@
+function _nonIterableSpread() {
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+}
+export { _nonIterableSpread as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/nullishReceiverError.js b/backend/node_modules/@babel/runtime/helpers/esm/nullishReceiverError.js
new file mode 100644
index 0000000..d8c3060
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/nullishReceiverError.js
@@ -0,0 +1,4 @@
+function _nullishReceiverError(r) {
+ throw new TypeError("Cannot set property of null or undefined.");
+}
+export { _nullishReceiverError as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/objectDestructuringEmpty.js b/backend/node_modules/@babel/runtime/helpers/esm/objectDestructuringEmpty.js
new file mode 100644
index 0000000..a92eac8
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/objectDestructuringEmpty.js
@@ -0,0 +1,4 @@
+function _objectDestructuringEmpty(t) {
+ if (null == t) throw new TypeError("Cannot destructure " + t);
+}
+export { _objectDestructuringEmpty as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/objectSpread.js b/backend/node_modules/@babel/runtime/helpers/esm/objectSpread.js
new file mode 100644
index 0000000..0f82f06
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/objectSpread.js
@@ -0,0 +1,14 @@
+import defineProperty from "./defineProperty.js";
+function _objectSpread(e) {
+ for (var r = 1; r < arguments.length; r++) {
+ var t = null != arguments[r] ? Object(arguments[r]) : {},
+ o = Object.keys(t);
+ "function" == typeof Object.getOwnPropertySymbols && o.push.apply(o, Object.getOwnPropertySymbols(t).filter(function (e) {
+ return Object.getOwnPropertyDescriptor(t, e).enumerable;
+ })), o.forEach(function (r) {
+ defineProperty(e, r, t[r]);
+ });
+ }
+ return e;
+}
+export { _objectSpread as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/objectSpread2.js b/backend/node_modules/@babel/runtime/helpers/esm/objectSpread2.js
new file mode 100644
index 0000000..0035bc7
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/objectSpread2.js
@@ -0,0 +1,23 @@
+import defineProperty from "./defineProperty.js";
+function ownKeys(e, r) {
+ var t = Object.keys(e);
+ if (Object.getOwnPropertySymbols) {
+ var o = Object.getOwnPropertySymbols(e);
+ r && (o = o.filter(function (r) {
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
+ })), t.push.apply(t, o);
+ }
+ return t;
+}
+function _objectSpread2(e) {
+ for (var r = 1; r < arguments.length; r++) {
+ var t = null != arguments[r] ? arguments[r] : {};
+ r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
+ defineProperty(e, r, t[r]);
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
+ });
+ }
+ return e;
+}
+export { _objectSpread2 as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/objectWithoutProperties.js b/backend/node_modules/@babel/runtime/helpers/esm/objectWithoutProperties.js
new file mode 100644
index 0000000..598fb9a
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/objectWithoutProperties.js
@@ -0,0 +1,13 @@
+import objectWithoutPropertiesLoose from "./objectWithoutPropertiesLoose.js";
+function _objectWithoutProperties(e, t) {
+ if (null == e) return {};
+ var o,
+ r,
+ i = objectWithoutPropertiesLoose(e, t);
+ if (Object.getOwnPropertySymbols) {
+ var n = Object.getOwnPropertySymbols(e);
+ for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
+ }
+ return i;
+}
+export { _objectWithoutProperties as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js b/backend/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js
new file mode 100644
index 0000000..90f68f3
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js
@@ -0,0 +1,10 @@
+function _objectWithoutPropertiesLoose(r, e) {
+ if (null == r) return {};
+ var t = {};
+ for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
+ if (-1 !== e.indexOf(n)) continue;
+ t[n] = r[n];
+ }
+ return t;
+}
+export { _objectWithoutPropertiesLoose as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/package.json b/backend/node_modules/@babel/runtime/helpers/esm/package.json
new file mode 100644
index 0000000..aead43d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/package.json
@@ -0,0 +1,3 @@
+{
+ "type": "module"
+}
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/possibleConstructorReturn.js b/backend/node_modules/@babel/runtime/helpers/esm/possibleConstructorReturn.js
new file mode 100644
index 0000000..d84e1e6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/possibleConstructorReturn.js
@@ -0,0 +1,8 @@
+import _typeof from "./typeof.js";
+import assertThisInitialized from "./assertThisInitialized.js";
+function _possibleConstructorReturn(t, e) {
+ if (e && ("object" == _typeof(e) || "function" == typeof e)) return e;
+ if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
+ return assertThisInitialized(t);
+}
+export { _possibleConstructorReturn as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/readOnlyError.js b/backend/node_modules/@babel/runtime/helpers/esm/readOnlyError.js
new file mode 100644
index 0000000..fcc3e33
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/readOnlyError.js
@@ -0,0 +1,4 @@
+function _readOnlyError(r) {
+ throw new TypeError('"' + r + '" is read-only');
+}
+export { _readOnlyError as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/regeneratorRuntime.js b/backend/node_modules/@babel/runtime/helpers/esm/regeneratorRuntime.js
new file mode 100644
index 0000000..af1677c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/regeneratorRuntime.js
@@ -0,0 +1,272 @@
+import _typeof from "./typeof.js";
+function _regeneratorRuntime() {
+ "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
+ _regeneratorRuntime = function _regeneratorRuntime() {
+ return r;
+ };
+ var t,
+ r = {},
+ e = Object.prototype,
+ n = e.hasOwnProperty,
+ o = "function" == typeof Symbol ? Symbol : {},
+ i = o.iterator || "@@iterator",
+ a = o.asyncIterator || "@@asyncIterator",
+ u = o.toStringTag || "@@toStringTag";
+ function c(t, r, e, n) {
+ return Object.defineProperty(t, r, {
+ value: e,
+ enumerable: !n,
+ configurable: !n,
+ writable: !n
+ });
+ }
+ try {
+ c({}, "");
+ } catch (t) {
+ c = function c(t, r, e) {
+ return t[r] = e;
+ };
+ }
+ function h(r, e, n, o) {
+ var i = e && e.prototype instanceof Generator ? e : Generator,
+ a = Object.create(i.prototype);
+ return c(a, "_invoke", function (r, e, n) {
+ var o = 1;
+ return function (i, a) {
+ if (3 === o) throw Error("Generator is already running");
+ if (4 === o) {
+ if ("throw" === i) throw a;
+ return {
+ value: t,
+ done: !0
+ };
+ }
+ for (n.method = i, n.arg = a;;) {
+ var u = n.delegate;
+ if (u) {
+ var c = d(u, n);
+ if (c) {
+ if (c === f) continue;
+ return c;
+ }
+ }
+ if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) {
+ if (1 === o) throw o = 4, n.arg;
+ n.dispatchException(n.arg);
+ } else "return" === n.method && n.abrupt("return", n.arg);
+ o = 3;
+ var h = s(r, e, n);
+ if ("normal" === h.type) {
+ if (o = n.done ? 4 : 2, h.arg === f) continue;
+ return {
+ value: h.arg,
+ done: n.done
+ };
+ }
+ "throw" === h.type && (o = 4, n.method = "throw", n.arg = h.arg);
+ }
+ };
+ }(r, n, new Context(o || [])), !0), a;
+ }
+ function s(t, r, e) {
+ try {
+ return {
+ type: "normal",
+ arg: t.call(r, e)
+ };
+ } catch (t) {
+ return {
+ type: "throw",
+ arg: t
+ };
+ }
+ }
+ r.wrap = h;
+ var f = {};
+ function Generator() {}
+ function GeneratorFunction() {}
+ function GeneratorFunctionPrototype() {}
+ var l = {};
+ c(l, i, function () {
+ return this;
+ });
+ var p = Object.getPrototypeOf,
+ y = p && p(p(x([])));
+ y && y !== e && n.call(y, i) && (l = y);
+ var v = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(l);
+ function g(t) {
+ ["next", "throw", "return"].forEach(function (r) {
+ c(t, r, function (t) {
+ return this._invoke(r, t);
+ });
+ });
+ }
+ function AsyncIterator(t, r) {
+ function e(o, i, a, u) {
+ var c = s(t[o], t, i);
+ if ("throw" !== c.type) {
+ var h = c.arg,
+ f = h.value;
+ return f && "object" == _typeof(f) && n.call(f, "__await") ? r.resolve(f.__await).then(function (t) {
+ e("next", t, a, u);
+ }, function (t) {
+ e("throw", t, a, u);
+ }) : r.resolve(f).then(function (t) {
+ h.value = t, a(h);
+ }, function (t) {
+ return e("throw", t, a, u);
+ });
+ }
+ u(c.arg);
+ }
+ var o;
+ c(this, "_invoke", function (t, n) {
+ function i() {
+ return new r(function (r, o) {
+ e(t, n, r, o);
+ });
+ }
+ return o = o ? o.then(i, i) : i();
+ }, !0);
+ }
+ function d(r, e) {
+ var n = e.method,
+ o = r.i[n];
+ if (o === t) return e.delegate = null, "throw" === n && r.i["return"] && (e.method = "return", e.arg = t, d(r, e), "throw" === e.method) || "return" !== n && (e.method = "throw", e.arg = new TypeError("The iterator does not provide a '" + n + "' method")), f;
+ var i = s(o, r.i, e.arg);
+ if ("throw" === i.type) return e.method = "throw", e.arg = i.arg, e.delegate = null, f;
+ var a = i.arg;
+ return a ? a.done ? (e[r.r] = a.value, e.next = r.n, "return" !== e.method && (e.method = "next", e.arg = t), e.delegate = null, f) : a : (e.method = "throw", e.arg = new TypeError("iterator result is not an object"), e.delegate = null, f);
+ }
+ function w(t) {
+ this.tryEntries.push(t);
+ }
+ function m(r) {
+ var e = r[4] || {};
+ e.type = "normal", e.arg = t, r[4] = e;
+ }
+ function Context(t) {
+ this.tryEntries = [[-1]], t.forEach(w, this), this.reset(!0);
+ }
+ function x(r) {
+ if (null != r) {
+ var e = r[i];
+ if (e) return e.call(r);
+ if ("function" == typeof r.next) return r;
+ if (!isNaN(r.length)) {
+ var o = -1,
+ a = function e() {
+ for (; ++o < r.length;) if (n.call(r, o)) return e.value = r[o], e.done = !1, e;
+ return e.value = t, e.done = !0, e;
+ };
+ return a.next = a;
+ }
+ }
+ throw new TypeError(_typeof(r) + " is not iterable");
+ }
+ return GeneratorFunction.prototype = GeneratorFunctionPrototype, c(v, "constructor", GeneratorFunctionPrototype), c(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = c(GeneratorFunctionPrototype, u, "GeneratorFunction"), r.isGeneratorFunction = function (t) {
+ var r = "function" == typeof t && t.constructor;
+ return !!r && (r === GeneratorFunction || "GeneratorFunction" === (r.displayName || r.name));
+ }, r.mark = function (t) {
+ return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, c(t, u, "GeneratorFunction")), t.prototype = Object.create(v), t;
+ }, r.awrap = function (t) {
+ return {
+ __await: t
+ };
+ }, g(AsyncIterator.prototype), c(AsyncIterator.prototype, a, function () {
+ return this;
+ }), r.AsyncIterator = AsyncIterator, r.async = function (t, e, n, o, i) {
+ void 0 === i && (i = Promise);
+ var a = new AsyncIterator(h(t, e, n, o), i);
+ return r.isGeneratorFunction(e) ? a : a.next().then(function (t) {
+ return t.done ? t.value : a.next();
+ });
+ }, g(v), c(v, u, "Generator"), c(v, i, function () {
+ return this;
+ }), c(v, "toString", function () {
+ return "[object Generator]";
+ }), r.keys = function (t) {
+ var r = Object(t),
+ e = [];
+ for (var n in r) e.unshift(n);
+ return function t() {
+ for (; e.length;) if ((n = e.pop()) in r) return t.value = n, t.done = !1, t;
+ return t.done = !0, t;
+ };
+ }, r.values = x, Context.prototype = {
+ constructor: Context,
+ reset: function reset(r) {
+ if (this.prev = this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(m), !r) for (var e in this) "t" === e.charAt(0) && n.call(this, e) && !isNaN(+e.slice(1)) && (this[e] = t);
+ },
+ stop: function stop() {
+ this.done = !0;
+ var t = this.tryEntries[0][4];
+ if ("throw" === t.type) throw t.arg;
+ return this.rval;
+ },
+ dispatchException: function dispatchException(r) {
+ if (this.done) throw r;
+ var e = this;
+ function n(t) {
+ a.type = "throw", a.arg = r, e.next = t;
+ }
+ for (var o = e.tryEntries.length - 1; o >= 0; --o) {
+ var i = this.tryEntries[o],
+ a = i[4],
+ u = this.prev,
+ c = i[1],
+ h = i[2];
+ if (-1 === i[0]) return n("end"), !1;
+ if (!c && !h) throw Error("try statement without catch or finally");
+ if (null != i[0] && i[0] <= u) {
+ if (u < c) return this.method = "next", this.arg = t, n(c), !0;
+ if (u < h) return n(h), !1;
+ }
+ }
+ },
+ abrupt: function abrupt(t, r) {
+ for (var e = this.tryEntries.length - 1; e >= 0; --e) {
+ var n = this.tryEntries[e];
+ if (n[0] > -1 && n[0] <= this.prev && this.prev < n[2]) {
+ var o = n;
+ break;
+ }
+ }
+ o && ("break" === t || "continue" === t) && o[0] <= r && r <= o[2] && (o = null);
+ var i = o ? o[4] : {};
+ return i.type = t, i.arg = r, o ? (this.method = "next", this.next = o[2], f) : this.complete(i);
+ },
+ complete: function complete(t, r) {
+ if ("throw" === t.type) throw t.arg;
+ return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && r && (this.next = r), f;
+ },
+ finish: function finish(t) {
+ for (var r = this.tryEntries.length - 1; r >= 0; --r) {
+ var e = this.tryEntries[r];
+ if (e[2] === t) return this.complete(e[4], e[3]), m(e), f;
+ }
+ },
+ "catch": function _catch(t) {
+ for (var r = this.tryEntries.length - 1; r >= 0; --r) {
+ var e = this.tryEntries[r];
+ if (e[0] === t) {
+ var n = e[4];
+ if ("throw" === n.type) {
+ var o = n.arg;
+ m(e);
+ }
+ return o;
+ }
+ }
+ throw Error("illegal catch attempt");
+ },
+ delegateYield: function delegateYield(r, e, n) {
+ return this.delegate = {
+ i: x(r),
+ r: e,
+ n: n
+ }, "next" === this.method && (this.arg = t), f;
+ }
+ }, r;
+}
+export { _regeneratorRuntime as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/set.js b/backend/node_modules/@babel/runtime/helpers/esm/set.js
new file mode 100644
index 0000000..ed0a803
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/set.js
@@ -0,0 +1,22 @@
+import superPropBase from "./superPropBase.js";
+import defineProperty from "./defineProperty.js";
+function set(e, r, t, o) {
+ return set = "undefined" != typeof Reflect && Reflect.set ? Reflect.set : function (e, r, t, o) {
+ var f,
+ i = superPropBase(e, r);
+ if (i) {
+ if ((f = Object.getOwnPropertyDescriptor(i, r)).set) return f.set.call(o, t), !0;
+ if (!f.writable) return !1;
+ }
+ if (f = Object.getOwnPropertyDescriptor(o, r)) {
+ if (!f.writable) return !1;
+ f.value = t, Object.defineProperty(o, r, f);
+ } else defineProperty(o, r, t);
+ return !0;
+ }, set(e, r, t, o);
+}
+function _set(e, r, t, o, f) {
+ if (!set(e, r, t, o || e) && f) throw new TypeError("failed to set property");
+ return t;
+}
+export { _set as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/setFunctionName.js b/backend/node_modules/@babel/runtime/helpers/esm/setFunctionName.js
new file mode 100644
index 0000000..82213ce
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/setFunctionName.js
@@ -0,0 +1,12 @@
+import _typeof from "./typeof.js";
+function setFunctionName(e, t, n) {
+ "symbol" == _typeof(t) && (t = (t = t.description) ? "[" + t + "]" : "");
+ try {
+ Object.defineProperty(e, "name", {
+ configurable: !0,
+ value: n ? n + " " + t : t
+ });
+ } catch (e) {}
+ return e;
+}
+export { setFunctionName as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js b/backend/node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js
new file mode 100644
index 0000000..c30983c
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js
@@ -0,0 +1,6 @@
+function _setPrototypeOf(t, e) {
+ return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
+ return t.__proto__ = e, t;
+ }, _setPrototypeOf(t, e);
+}
+export { _setPrototypeOf as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/skipFirstGeneratorNext.js b/backend/node_modules/@babel/runtime/helpers/esm/skipFirstGeneratorNext.js
new file mode 100644
index 0000000..41d5738
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/skipFirstGeneratorNext.js
@@ -0,0 +1,7 @@
+function _skipFirstGeneratorNext(t) {
+ return function () {
+ var r = t.apply(this, arguments);
+ return r.next(), r;
+ };
+}
+export { _skipFirstGeneratorNext as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/slicedToArray.js b/backend/node_modules/@babel/runtime/helpers/esm/slicedToArray.js
new file mode 100644
index 0000000..c044c2a
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/slicedToArray.js
@@ -0,0 +1,8 @@
+import arrayWithHoles from "./arrayWithHoles.js";
+import iterableToArrayLimit from "./iterableToArrayLimit.js";
+import unsupportedIterableToArray from "./unsupportedIterableToArray.js";
+import nonIterableRest from "./nonIterableRest.js";
+function _slicedToArray(r, e) {
+ return arrayWithHoles(r) || iterableToArrayLimit(r, e) || unsupportedIterableToArray(r, e) || nonIterableRest();
+}
+export { _slicedToArray as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/superPropBase.js b/backend/node_modules/@babel/runtime/helpers/esm/superPropBase.js
new file mode 100644
index 0000000..a5fa386
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/superPropBase.js
@@ -0,0 +1,6 @@
+import getPrototypeOf from "./getPrototypeOf.js";
+function _superPropBase(t, o) {
+ for (; !{}.hasOwnProperty.call(t, o) && null !== (t = getPrototypeOf(t)););
+ return t;
+}
+export { _superPropBase as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/superPropGet.js b/backend/node_modules/@babel/runtime/helpers/esm/superPropGet.js
new file mode 100644
index 0000000..b2b60a8
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/superPropGet.js
@@ -0,0 +1,9 @@
+import get from "./get.js";
+import getPrototypeOf from "./getPrototypeOf.js";
+function _superPropGet(t, o, e, r) {
+ var p = get(getPrototypeOf(1 & r ? t.prototype : t), o, e);
+ return 2 & r && "function" == typeof p ? function (t) {
+ return p.apply(e, t);
+ } : p;
+}
+export { _superPropGet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/superPropSet.js b/backend/node_modules/@babel/runtime/helpers/esm/superPropSet.js
new file mode 100644
index 0000000..e182f38
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/superPropSet.js
@@ -0,0 +1,6 @@
+import set from "./set.js";
+import getPrototypeOf from "./getPrototypeOf.js";
+function _superPropSet(t, e, o, r, p, f) {
+ return set(getPrototypeOf(f ? t.prototype : t), e, o, r, p);
+}
+export { _superPropSet as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/taggedTemplateLiteral.js b/backend/node_modules/@babel/runtime/helpers/esm/taggedTemplateLiteral.js
new file mode 100644
index 0000000..3d842cd
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/taggedTemplateLiteral.js
@@ -0,0 +1,8 @@
+function _taggedTemplateLiteral(e, t) {
+ return t || (t = e.slice(0)), Object.freeze(Object.defineProperties(e, {
+ raw: {
+ value: Object.freeze(t)
+ }
+ }));
+}
+export { _taggedTemplateLiteral as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/taggedTemplateLiteralLoose.js b/backend/node_modules/@babel/runtime/helpers/esm/taggedTemplateLiteralLoose.js
new file mode 100644
index 0000000..741aeb8
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/taggedTemplateLiteralLoose.js
@@ -0,0 +1,4 @@
+function _taggedTemplateLiteralLoose(e, t) {
+ return t || (t = e.slice(0)), e.raw = t, e;
+}
+export { _taggedTemplateLiteralLoose as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/tdz.js b/backend/node_modules/@babel/runtime/helpers/esm/tdz.js
new file mode 100644
index 0000000..58df493
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/tdz.js
@@ -0,0 +1,4 @@
+function _tdzError(e) {
+ throw new ReferenceError(e + " is not defined - temporal dead zone");
+}
+export { _tdzError as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/temporalRef.js b/backend/node_modules/@babel/runtime/helpers/esm/temporalRef.js
new file mode 100644
index 0000000..8dbf014
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/temporalRef.js
@@ -0,0 +1,6 @@
+import temporalUndefined from "./temporalUndefined.js";
+import tdz from "./tdz.js";
+function _temporalRef(r, e) {
+ return r === temporalUndefined ? tdz(e) : r;
+}
+export { _temporalRef as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/temporalUndefined.js b/backend/node_modules/@babel/runtime/helpers/esm/temporalUndefined.js
new file mode 100644
index 0000000..2ec0b0d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/temporalUndefined.js
@@ -0,0 +1,2 @@
+function _temporalUndefined() {}
+export { _temporalUndefined as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/toArray.js b/backend/node_modules/@babel/runtime/helpers/esm/toArray.js
new file mode 100644
index 0000000..e5f0f52
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/toArray.js
@@ -0,0 +1,8 @@
+import arrayWithHoles from "./arrayWithHoles.js";
+import iterableToArray from "./iterableToArray.js";
+import unsupportedIterableToArray from "./unsupportedIterableToArray.js";
+import nonIterableRest from "./nonIterableRest.js";
+function _toArray(r) {
+ return arrayWithHoles(r) || iterableToArray(r) || unsupportedIterableToArray(r) || nonIterableRest();
+}
+export { _toArray as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/toConsumableArray.js b/backend/node_modules/@babel/runtime/helpers/esm/toConsumableArray.js
new file mode 100644
index 0000000..f7338e4
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/toConsumableArray.js
@@ -0,0 +1,8 @@
+import arrayWithoutHoles from "./arrayWithoutHoles.js";
+import iterableToArray from "./iterableToArray.js";
+import unsupportedIterableToArray from "./unsupportedIterableToArray.js";
+import nonIterableSpread from "./nonIterableSpread.js";
+function _toConsumableArray(r) {
+ return arrayWithoutHoles(r) || iterableToArray(r) || unsupportedIterableToArray(r) || nonIterableSpread();
+}
+export { _toConsumableArray as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/toPrimitive.js b/backend/node_modules/@babel/runtime/helpers/esm/toPrimitive.js
new file mode 100644
index 0000000..9a3de46
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/toPrimitive.js
@@ -0,0 +1,12 @@
+import _typeof from "./typeof.js";
+function toPrimitive(t, r) {
+ if ("object" != _typeof(t) || !t) return t;
+ var e = t[Symbol.toPrimitive];
+ if (void 0 !== e) {
+ var i = e.call(t, r || "default");
+ if ("object" != _typeof(i)) return i;
+ throw new TypeError("@@toPrimitive must return a primitive value.");
+ }
+ return ("string" === r ? String : Number)(t);
+}
+export { toPrimitive as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/toPropertyKey.js b/backend/node_modules/@babel/runtime/helpers/esm/toPropertyKey.js
new file mode 100644
index 0000000..b3274d8
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/toPropertyKey.js
@@ -0,0 +1,7 @@
+import _typeof from "./typeof.js";
+import toPrimitive from "./toPrimitive.js";
+function toPropertyKey(t) {
+ var i = toPrimitive(t, "string");
+ return "symbol" == _typeof(i) ? i : i + "";
+}
+export { toPropertyKey as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/toSetter.js b/backend/node_modules/@babel/runtime/helpers/esm/toSetter.js
new file mode 100644
index 0000000..b1dbf7a
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/toSetter.js
@@ -0,0 +1,10 @@
+function _toSetter(t, e, n) {
+ e || (e = []);
+ var r = e.length++;
+ return Object.defineProperty({}, "_", {
+ set: function set(o) {
+ e[r] = o, t.apply(n, e);
+ }
+ });
+}
+export { _toSetter as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/tsRewriteRelativeImportExtensions.js b/backend/node_modules/@babel/runtime/helpers/esm/tsRewriteRelativeImportExtensions.js
new file mode 100644
index 0000000..28ffc0b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/tsRewriteRelativeImportExtensions.js
@@ -0,0 +1,6 @@
+function tsRewriteRelativeImportExtensions(t, e) {
+ return "string" == typeof t && /^\.\.?\//.test(t) ? t.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+)?)\.([cm]?)ts$/i, function (t, s, r, n, o) {
+ return s ? e ? ".jsx" : ".js" : !r || n && o ? r + n + "." + o.toLowerCase() + "js" : t;
+ }) : t;
+}
+export { tsRewriteRelativeImportExtensions as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/typeof.js b/backend/node_modules/@babel/runtime/helpers/esm/typeof.js
new file mode 100644
index 0000000..5b0bc9b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/typeof.js
@@ -0,0 +1,10 @@
+function _typeof(o) {
+ "@babel/helpers - typeof";
+
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
+ return typeof o;
+ } : function (o) {
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
+ }, _typeof(o);
+}
+export { _typeof as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js b/backend/node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js
new file mode 100644
index 0000000..33adc49
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/unsupportedIterableToArray.js
@@ -0,0 +1,9 @@
+import arrayLikeToArray from "./arrayLikeToArray.js";
+function _unsupportedIterableToArray(r, a) {
+ if (r) {
+ if ("string" == typeof r) return arrayLikeToArray(r, a);
+ var t = {}.toString.call(r).slice(8, -1);
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? arrayLikeToArray(r, a) : void 0;
+ }
+}
+export { _unsupportedIterableToArray as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/using.js b/backend/node_modules/@babel/runtime/helpers/esm/using.js
new file mode 100644
index 0000000..9bda17b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/using.js
@@ -0,0 +1,12 @@
+function _using(o, n, e) {
+ if (null == n) return n;
+ if (Object(n) !== n) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
+ if (e) var r = n[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
+ if (null == r && (r = n[Symbol.dispose || Symbol["for"]("Symbol.dispose")]), "function" != typeof r) throw new TypeError("Property [Symbol.dispose] is not a function.");
+ return o.push({
+ v: n,
+ d: r,
+ a: e
+ }), n;
+}
+export { _using as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/usingCtx.js b/backend/node_modules/@babel/runtime/helpers/esm/usingCtx.js
new file mode 100644
index 0000000..1464379
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/usingCtx.js
@@ -0,0 +1,59 @@
+function _usingCtx() {
+ var r = "function" == typeof SuppressedError ? SuppressedError : function (r, e) {
+ var n = Error();
+ return n.name = "SuppressedError", n.error = r, n.suppressed = e, n;
+ },
+ e = {},
+ n = [];
+ function using(r, e) {
+ if (null != e) {
+ if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
+ if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
+ if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o;
+ if ("function" != typeof o) throw new TypeError("Object is not disposable.");
+ t && (o = function o() {
+ try {
+ t.call(e);
+ } catch (r) {
+ return Promise.reject(r);
+ }
+ }), n.push({
+ v: e,
+ d: o,
+ a: r
+ });
+ } else r && n.push({
+ d: e,
+ a: r
+ });
+ return e;
+ }
+ return {
+ e: e,
+ u: using.bind(null, !1),
+ a: using.bind(null, !0),
+ d: function d() {
+ var o,
+ t = this.e,
+ s = 0;
+ function next() {
+ for (; o = n.pop();) try {
+ if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);
+ if (o.d) {
+ var r = o.d.call(o.v);
+ if (o.a) return s |= 2, Promise.resolve(r).then(next, err);
+ } else s |= 1;
+ } catch (r) {
+ return err(r);
+ }
+ if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();
+ if (t !== e) throw t;
+ }
+ function err(n) {
+ return t = t !== e ? new r(n, t) : n, next();
+ }
+ return next();
+ }
+ };
+}
+export { _usingCtx as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/wrapAsyncGenerator.js b/backend/node_modules/@babel/runtime/helpers/esm/wrapAsyncGenerator.js
new file mode 100644
index 0000000..ffeea5d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/wrapAsyncGenerator.js
@@ -0,0 +1,69 @@
+import OverloadYield from "./OverloadYield.js";
+function _wrapAsyncGenerator(e) {
+ return function () {
+ return new AsyncGenerator(e.apply(this, arguments));
+ };
+}
+function AsyncGenerator(e) {
+ var r, t;
+ function resume(r, t) {
+ try {
+ var n = e[r](t),
+ o = n.value,
+ u = o instanceof OverloadYield;
+ Promise.resolve(u ? o.v : o).then(function (t) {
+ if (u) {
+ var i = "return" === r ? "return" : "next";
+ if (!o.k || t.done) return resume(i, t);
+ t = e[i](t).value;
+ }
+ settle(n.done ? "return" : "normal", t);
+ }, function (e) {
+ resume("throw", e);
+ });
+ } catch (e) {
+ settle("throw", e);
+ }
+ }
+ function settle(e, n) {
+ switch (e) {
+ case "return":
+ r.resolve({
+ value: n,
+ done: !0
+ });
+ break;
+ case "throw":
+ r.reject(n);
+ break;
+ default:
+ r.resolve({
+ value: n,
+ done: !1
+ });
+ }
+ (r = r.next) ? resume(r.key, r.arg) : t = null;
+ }
+ this._invoke = function (e, n) {
+ return new Promise(function (o, u) {
+ var i = {
+ key: e,
+ arg: n,
+ resolve: o,
+ reject: u,
+ next: null
+ };
+ t ? t = t.next = i : (r = t = i, resume(e, n));
+ });
+ }, "function" != typeof e["return"] && (this["return"] = void 0);
+}
+AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function () {
+ return this;
+}, AsyncGenerator.prototype.next = function (e) {
+ return this._invoke("next", e);
+}, AsyncGenerator.prototype["throw"] = function (e) {
+ return this._invoke("throw", e);
+}, AsyncGenerator.prototype["return"] = function (e) {
+ return this._invoke("return", e);
+};
+export { _wrapAsyncGenerator as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/wrapNativeSuper.js b/backend/node_modules/@babel/runtime/helpers/esm/wrapNativeSuper.js
new file mode 100644
index 0000000..15bf78f
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/wrapNativeSuper.js
@@ -0,0 +1,27 @@
+import getPrototypeOf from "./getPrototypeOf.js";
+import setPrototypeOf from "./setPrototypeOf.js";
+import isNativeFunction from "./isNativeFunction.js";
+import construct from "./construct.js";
+function _wrapNativeSuper(t) {
+ var r = "function" == typeof Map ? new Map() : void 0;
+ return _wrapNativeSuper = function _wrapNativeSuper(t) {
+ if (null === t || !isNativeFunction(t)) return t;
+ if ("function" != typeof t) throw new TypeError("Super expression must either be null or a function");
+ if (void 0 !== r) {
+ if (r.has(t)) return r.get(t);
+ r.set(t, Wrapper);
+ }
+ function Wrapper() {
+ return construct(t, arguments, getPrototypeOf(this).constructor);
+ }
+ return Wrapper.prototype = Object.create(t.prototype, {
+ constructor: {
+ value: Wrapper,
+ enumerable: !1,
+ writable: !0,
+ configurable: !0
+ }
+ }), setPrototypeOf(Wrapper, t);
+ }, _wrapNativeSuper(t);
+}
+export { _wrapNativeSuper as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/wrapRegExp.js b/backend/node_modules/@babel/runtime/helpers/esm/wrapRegExp.js
new file mode 100644
index 0000000..c455faa
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/wrapRegExp.js
@@ -0,0 +1,52 @@
+import _typeof from "./typeof.js";
+import setPrototypeOf from "./setPrototypeOf.js";
+import inherits from "./inherits.js";
+function _wrapRegExp() {
+ _wrapRegExp = function _wrapRegExp(e, r) {
+ return new BabelRegExp(e, void 0, r);
+ };
+ var e = RegExp.prototype,
+ r = new WeakMap();
+ function BabelRegExp(e, t, p) {
+ var o = RegExp(e, t);
+ return r.set(o, p || r.get(e)), setPrototypeOf(o, BabelRegExp.prototype);
+ }
+ function buildGroups(e, t) {
+ var p = r.get(t);
+ return Object.keys(p).reduce(function (r, t) {
+ var o = p[t];
+ if ("number" == typeof o) r[t] = e[o];else {
+ for (var i = 0; void 0 === e[o[i]] && i + 1 < o.length;) i++;
+ r[t] = e[o[i]];
+ }
+ return r;
+ }, Object.create(null));
+ }
+ return inherits(BabelRegExp, RegExp), BabelRegExp.prototype.exec = function (r) {
+ var t = e.exec.call(this, r);
+ if (t) {
+ t.groups = buildGroups(t, this);
+ var p = t.indices;
+ p && (p.groups = buildGroups(p, this));
+ }
+ return t;
+ }, BabelRegExp.prototype[Symbol.replace] = function (t, p) {
+ if ("string" == typeof p) {
+ var o = r.get(this);
+ return e[Symbol.replace].call(this, t, p.replace(/\$<([^>]+)(>|$)/g, function (e, r, t) {
+ if ("" === t) return e;
+ var p = o[r];
+ return Array.isArray(p) ? "$" + p.join("$") : "number" == typeof p ? "$" + p : "";
+ }));
+ }
+ if ("function" == typeof p) {
+ var i = this;
+ return e[Symbol.replace].call(this, t, function () {
+ var e = arguments;
+ return "object" != _typeof(e[e.length - 1]) && (e = [].slice.call(e)).push(buildGroups(e, i)), p.apply(this, e);
+ });
+ }
+ return e[Symbol.replace].call(this, t, p);
+ }, _wrapRegExp.apply(this, arguments);
+}
+export { _wrapRegExp as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/esm/writeOnlyError.js b/backend/node_modules/@babel/runtime/helpers/esm/writeOnlyError.js
new file mode 100644
index 0000000..250c286
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/esm/writeOnlyError.js
@@ -0,0 +1,4 @@
+function _writeOnlyError(r) {
+ throw new TypeError('"' + r + '" is write-only');
+}
+export { _writeOnlyError as default };
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/extends.js b/backend/node_modules/@babel/runtime/helpers/extends.js
new file mode 100644
index 0000000..eee4a1f
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/extends.js
@@ -0,0 +1,10 @@
+function _extends() {
+ return module.exports = _extends = Object.assign ? Object.assign.bind() : function (n) {
+ for (var e = 1; e < arguments.length; e++) {
+ var t = arguments[e];
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
+ }
+ return n;
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports, _extends.apply(null, arguments);
+}
+module.exports = _extends, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/get.js b/backend/node_modules/@babel/runtime/helpers/get.js
new file mode 100644
index 0000000..15428de
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/get.js
@@ -0,0 +1,11 @@
+var superPropBase = require("./superPropBase.js");
+function _get() {
+ return module.exports = _get = "undefined" != typeof Reflect && Reflect.get ? Reflect.get.bind() : function (e, t, r) {
+ var p = superPropBase(e, t);
+ if (p) {
+ var n = Object.getOwnPropertyDescriptor(p, t);
+ return n.get ? n.get.call(arguments.length < 3 ? e : r) : n.value;
+ }
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports, _get.apply(null, arguments);
+}
+module.exports = _get, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/getPrototypeOf.js b/backend/node_modules/@babel/runtime/helpers/getPrototypeOf.js
new file mode 100644
index 0000000..9070748
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/getPrototypeOf.js
@@ -0,0 +1,6 @@
+function _getPrototypeOf(t) {
+ return module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) {
+ return t.__proto__ || Object.getPrototypeOf(t);
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports, _getPrototypeOf(t);
+}
+module.exports = _getPrototypeOf, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/identity.js b/backend/node_modules/@babel/runtime/helpers/identity.js
new file mode 100644
index 0000000..54de5b5
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/identity.js
@@ -0,0 +1,4 @@
+function _identity(t) {
+ return t;
+}
+module.exports = _identity, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/importDeferProxy.js b/backend/node_modules/@babel/runtime/helpers/importDeferProxy.js
new file mode 100644
index 0000000..cffaae6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/importDeferProxy.js
@@ -0,0 +1,27 @@
+function _importDeferProxy(e) {
+ var t = null,
+ constValue = function constValue(e) {
+ return function () {
+ return e;
+ };
+ },
+ proxy = function proxy(r) {
+ return function (n, o, f) {
+ return null === t && (t = e()), r(t, o, f);
+ };
+ };
+ return new Proxy({}, {
+ defineProperty: constValue(!1),
+ deleteProperty: constValue(!1),
+ get: proxy(Reflect.get),
+ getOwnPropertyDescriptor: proxy(Reflect.getOwnPropertyDescriptor),
+ getPrototypeOf: constValue(null),
+ isExtensible: constValue(!1),
+ has: proxy(Reflect.has),
+ ownKeys: proxy(Reflect.ownKeys),
+ preventExtensions: constValue(!0),
+ set: constValue(!1),
+ setPrototypeOf: constValue(!1)
+ });
+}
+module.exports = _importDeferProxy, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/inherits.js b/backend/node_modules/@babel/runtime/helpers/inherits.js
new file mode 100644
index 0000000..715a78e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/inherits.js
@@ -0,0 +1,14 @@
+var setPrototypeOf = require("./setPrototypeOf.js");
+function _inherits(t, e) {
+ if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function");
+ t.prototype = Object.create(e && e.prototype, {
+ constructor: {
+ value: t,
+ writable: !0,
+ configurable: !0
+ }
+ }), Object.defineProperty(t, "prototype", {
+ writable: !1
+ }), e && setPrototypeOf(t, e);
+}
+module.exports = _inherits, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/inheritsLoose.js b/backend/node_modules/@babel/runtime/helpers/inheritsLoose.js
new file mode 100644
index 0000000..a27baf0
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/inheritsLoose.js
@@ -0,0 +1,5 @@
+var setPrototypeOf = require("./setPrototypeOf.js");
+function _inheritsLoose(t, o) {
+ t.prototype = Object.create(o.prototype), t.prototype.constructor = t, setPrototypeOf(t, o);
+}
+module.exports = _inheritsLoose, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/initializerDefineProperty.js b/backend/node_modules/@babel/runtime/helpers/initializerDefineProperty.js
new file mode 100644
index 0000000..f9fa317
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/initializerDefineProperty.js
@@ -0,0 +1,9 @@
+function _initializerDefineProperty(e, i, r, l) {
+ r && Object.defineProperty(e, i, {
+ enumerable: r.enumerable,
+ configurable: r.configurable,
+ writable: r.writable,
+ value: r.initializer ? r.initializer.call(l) : void 0
+ });
+}
+module.exports = _initializerDefineProperty, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/initializerWarningHelper.js b/backend/node_modules/@babel/runtime/helpers/initializerWarningHelper.js
new file mode 100644
index 0000000..e14ce59
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/initializerWarningHelper.js
@@ -0,0 +1,4 @@
+function _initializerWarningHelper(r, e) {
+ throw Error("Decorating class property failed. Please ensure that transform-class-properties is enabled and runs after the decorators transform.");
+}
+module.exports = _initializerWarningHelper, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/instanceof.js b/backend/node_modules/@babel/runtime/helpers/instanceof.js
new file mode 100644
index 0000000..9952301
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/instanceof.js
@@ -0,0 +1,4 @@
+function _instanceof(n, e) {
+ return null != e && "undefined" != typeof Symbol && e[Symbol.hasInstance] ? !!e[Symbol.hasInstance](n) : n instanceof e;
+}
+module.exports = _instanceof, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/interopRequireDefault.js b/backend/node_modules/@babel/runtime/helpers/interopRequireDefault.js
new file mode 100644
index 0000000..6944715
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/interopRequireDefault.js
@@ -0,0 +1,6 @@
+function _interopRequireDefault(e) {
+ return e && e.__esModule ? e : {
+ "default": e
+ };
+}
+module.exports = _interopRequireDefault, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/interopRequireWildcard.js b/backend/node_modules/@babel/runtime/helpers/interopRequireWildcard.js
new file mode 100644
index 0000000..d5f1054
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/interopRequireWildcard.js
@@ -0,0 +1,22 @@
+var _typeof = require("./typeof.js")["default"];
+function _interopRequireWildcard(e, t) {
+ if ("function" == typeof WeakMap) var r = new WeakMap(),
+ n = new WeakMap();
+ return (module.exports = _interopRequireWildcard = function _interopRequireWildcard(e, t) {
+ if (!t && e && e.__esModule) return e;
+ var o,
+ i,
+ f = {
+ __proto__: null,
+ "default": e
+ };
+ if (null === e || "object" != _typeof(e) && "function" != typeof e) return f;
+ if (o = t ? n : r) {
+ if (o.has(e)) return o.get(e);
+ o.set(e, f);
+ }
+ for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]);
+ return f;
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports)(e, t);
+}
+module.exports = _interopRequireWildcard, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/isNativeFunction.js b/backend/node_modules/@babel/runtime/helpers/isNativeFunction.js
new file mode 100644
index 0000000..f0eb49e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/isNativeFunction.js
@@ -0,0 +1,8 @@
+function _isNativeFunction(t) {
+ try {
+ return -1 !== Function.toString.call(t).indexOf("[native code]");
+ } catch (n) {
+ return "function" == typeof t;
+ }
+}
+module.exports = _isNativeFunction, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/isNativeReflectConstruct.js b/backend/node_modules/@babel/runtime/helpers/isNativeReflectConstruct.js
new file mode 100644
index 0000000..b677e10
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/isNativeReflectConstruct.js
@@ -0,0 +1,9 @@
+function _isNativeReflectConstruct() {
+ try {
+ var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
+ } catch (t) {}
+ return (module.exports = _isNativeReflectConstruct = function _isNativeReflectConstruct() {
+ return !!t;
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports)();
+}
+module.exports = _isNativeReflectConstruct, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/iterableToArray.js b/backend/node_modules/@babel/runtime/helpers/iterableToArray.js
new file mode 100644
index 0000000..c839a32
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/iterableToArray.js
@@ -0,0 +1,4 @@
+function _iterableToArray(r) {
+ if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r);
+}
+module.exports = _iterableToArray, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/iterableToArrayLimit.js b/backend/node_modules/@babel/runtime/helpers/iterableToArrayLimit.js
new file mode 100644
index 0000000..2671778
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/iterableToArrayLimit.js
@@ -0,0 +1,28 @@
+function _iterableToArrayLimit(r, l) {
+ var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
+ if (null != t) {
+ var e,
+ n,
+ i,
+ u,
+ a = [],
+ f = !0,
+ o = !1;
+ try {
+ if (i = (t = t.call(r)).next, 0 === l) {
+ if (Object(t) !== t) return;
+ f = !1;
+ } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);
+ } catch (r) {
+ o = !0, n = r;
+ } finally {
+ try {
+ if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return;
+ } finally {
+ if (o) throw n;
+ }
+ }
+ return a;
+ }
+}
+module.exports = _iterableToArrayLimit, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/jsx.js b/backend/node_modules/@babel/runtime/helpers/jsx.js
new file mode 100644
index 0000000..3415eea
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/jsx.js
@@ -0,0 +1,22 @@
+var REACT_ELEMENT_TYPE;
+function _createRawReactElement(e, r, E, l) {
+ REACT_ELEMENT_TYPE || (REACT_ELEMENT_TYPE = "function" == typeof Symbol && Symbol["for"] && Symbol["for"]("react.element") || 60103);
+ var o = e && e.defaultProps,
+ n = arguments.length - 3;
+ if (r || 0 === n || (r = {
+ children: void 0
+ }), 1 === n) r.children = l;else if (n > 1) {
+ for (var t = Array(n), f = 0; f < n; f++) t[f] = arguments[f + 3];
+ r.children = t;
+ }
+ if (r && o) for (var i in o) void 0 === r[i] && (r[i] = o[i]);else r || (r = o || {});
+ return {
+ $$typeof: REACT_ELEMENT_TYPE,
+ type: e,
+ key: void 0 === E ? null : "" + E,
+ ref: null,
+ props: r,
+ _owner: null
+ };
+}
+module.exports = _createRawReactElement, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/maybeArrayLike.js b/backend/node_modules/@babel/runtime/helpers/maybeArrayLike.js
new file mode 100644
index 0000000..9873cc7
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/maybeArrayLike.js
@@ -0,0 +1,9 @@
+var arrayLikeToArray = require("./arrayLikeToArray.js");
+function _maybeArrayLike(r, a, e) {
+ if (a && !Array.isArray(a) && "number" == typeof a.length) {
+ var y = a.length;
+ return arrayLikeToArray(a, void 0 !== e && e < y ? e : y);
+ }
+ return r(a, e);
+}
+module.exports = _maybeArrayLike, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/newArrowCheck.js b/backend/node_modules/@babel/runtime/helpers/newArrowCheck.js
new file mode 100644
index 0000000..8e74d99
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/newArrowCheck.js
@@ -0,0 +1,4 @@
+function _newArrowCheck(n, r) {
+ if (n !== r) throw new TypeError("Cannot instantiate an arrow function");
+}
+module.exports = _newArrowCheck, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/nonIterableRest.js b/backend/node_modules/@babel/runtime/helpers/nonIterableRest.js
new file mode 100644
index 0000000..95265ba
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/nonIterableRest.js
@@ -0,0 +1,4 @@
+function _nonIterableRest() {
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+}
+module.exports = _nonIterableRest, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/nonIterableSpread.js b/backend/node_modules/@babel/runtime/helpers/nonIterableSpread.js
new file mode 100644
index 0000000..3fcf23f
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/nonIterableSpread.js
@@ -0,0 +1,4 @@
+function _nonIterableSpread() {
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
+}
+module.exports = _nonIterableSpread, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/nullishReceiverError.js b/backend/node_modules/@babel/runtime/helpers/nullishReceiverError.js
new file mode 100644
index 0000000..970e023
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/nullishReceiverError.js
@@ -0,0 +1,4 @@
+function _nullishReceiverError(r) {
+ throw new TypeError("Cannot set property of null or undefined.");
+}
+module.exports = _nullishReceiverError, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/objectDestructuringEmpty.js b/backend/node_modules/@babel/runtime/helpers/objectDestructuringEmpty.js
new file mode 100644
index 0000000..9f62a1b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/objectDestructuringEmpty.js
@@ -0,0 +1,4 @@
+function _objectDestructuringEmpty(t) {
+ if (null == t) throw new TypeError("Cannot destructure " + t);
+}
+module.exports = _objectDestructuringEmpty, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/objectSpread.js b/backend/node_modules/@babel/runtime/helpers/objectSpread.js
new file mode 100644
index 0000000..a367643
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/objectSpread.js
@@ -0,0 +1,14 @@
+var defineProperty = require("./defineProperty.js");
+function _objectSpread(e) {
+ for (var r = 1; r < arguments.length; r++) {
+ var t = null != arguments[r] ? Object(arguments[r]) : {},
+ o = Object.keys(t);
+ "function" == typeof Object.getOwnPropertySymbols && o.push.apply(o, Object.getOwnPropertySymbols(t).filter(function (e) {
+ return Object.getOwnPropertyDescriptor(t, e).enumerable;
+ })), o.forEach(function (r) {
+ defineProperty(e, r, t[r]);
+ });
+ }
+ return e;
+}
+module.exports = _objectSpread, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/objectSpread2.js b/backend/node_modules/@babel/runtime/helpers/objectSpread2.js
new file mode 100644
index 0000000..4f3b9fa
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/objectSpread2.js
@@ -0,0 +1,23 @@
+var defineProperty = require("./defineProperty.js");
+function ownKeys(e, r) {
+ var t = Object.keys(e);
+ if (Object.getOwnPropertySymbols) {
+ var o = Object.getOwnPropertySymbols(e);
+ r && (o = o.filter(function (r) {
+ return Object.getOwnPropertyDescriptor(e, r).enumerable;
+ })), t.push.apply(t, o);
+ }
+ return t;
+}
+function _objectSpread2(e) {
+ for (var r = 1; r < arguments.length; r++) {
+ var t = null != arguments[r] ? arguments[r] : {};
+ r % 2 ? ownKeys(Object(t), !0).forEach(function (r) {
+ defineProperty(e, r, t[r]);
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {
+ Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
+ });
+ }
+ return e;
+}
+module.exports = _objectSpread2, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/objectWithoutProperties.js b/backend/node_modules/@babel/runtime/helpers/objectWithoutProperties.js
new file mode 100644
index 0000000..3a40f9e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/objectWithoutProperties.js
@@ -0,0 +1,13 @@
+var objectWithoutPropertiesLoose = require("./objectWithoutPropertiesLoose.js");
+function _objectWithoutProperties(e, t) {
+ if (null == e) return {};
+ var o,
+ r,
+ i = objectWithoutPropertiesLoose(e, t);
+ if (Object.getOwnPropertySymbols) {
+ var n = Object.getOwnPropertySymbols(e);
+ for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);
+ }
+ return i;
+}
+module.exports = _objectWithoutProperties, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js b/backend/node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js
new file mode 100644
index 0000000..c243acd
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js
@@ -0,0 +1,10 @@
+function _objectWithoutPropertiesLoose(r, e) {
+ if (null == r) return {};
+ var t = {};
+ for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
+ if (-1 !== e.indexOf(n)) continue;
+ t[n] = r[n];
+ }
+ return t;
+}
+module.exports = _objectWithoutPropertiesLoose, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/possibleConstructorReturn.js b/backend/node_modules/@babel/runtime/helpers/possibleConstructorReturn.js
new file mode 100644
index 0000000..06e6e6d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/possibleConstructorReturn.js
@@ -0,0 +1,8 @@
+var _typeof = require("./typeof.js")["default"];
+var assertThisInitialized = require("./assertThisInitialized.js");
+function _possibleConstructorReturn(t, e) {
+ if (e && ("object" == _typeof(e) || "function" == typeof e)) return e;
+ if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined");
+ return assertThisInitialized(t);
+}
+module.exports = _possibleConstructorReturn, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/readOnlyError.js b/backend/node_modules/@babel/runtime/helpers/readOnlyError.js
new file mode 100644
index 0000000..1bf3e09
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/readOnlyError.js
@@ -0,0 +1,4 @@
+function _readOnlyError(r) {
+ throw new TypeError('"' + r + '" is read-only');
+}
+module.exports = _readOnlyError, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/regeneratorRuntime.js b/backend/node_modules/@babel/runtime/helpers/regeneratorRuntime.js
new file mode 100644
index 0000000..e13d604
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/regeneratorRuntime.js
@@ -0,0 +1,272 @@
+var _typeof = require("./typeof.js")["default"];
+function _regeneratorRuntime() {
+ "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
+ module.exports = _regeneratorRuntime = function _regeneratorRuntime() {
+ return r;
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports;
+ var t,
+ r = {},
+ e = Object.prototype,
+ n = e.hasOwnProperty,
+ o = "function" == typeof Symbol ? Symbol : {},
+ i = o.iterator || "@@iterator",
+ a = o.asyncIterator || "@@asyncIterator",
+ u = o.toStringTag || "@@toStringTag";
+ function c(t, r, e, n) {
+ return Object.defineProperty(t, r, {
+ value: e,
+ enumerable: !n,
+ configurable: !n,
+ writable: !n
+ });
+ }
+ try {
+ c({}, "");
+ } catch (t) {
+ c = function c(t, r, e) {
+ return t[r] = e;
+ };
+ }
+ function h(r, e, n, o) {
+ var i = e && e.prototype instanceof Generator ? e : Generator,
+ a = Object.create(i.prototype);
+ return c(a, "_invoke", function (r, e, n) {
+ var o = 1;
+ return function (i, a) {
+ if (3 === o) throw Error("Generator is already running");
+ if (4 === o) {
+ if ("throw" === i) throw a;
+ return {
+ value: t,
+ done: !0
+ };
+ }
+ for (n.method = i, n.arg = a;;) {
+ var u = n.delegate;
+ if (u) {
+ var c = d(u, n);
+ if (c) {
+ if (c === f) continue;
+ return c;
+ }
+ }
+ if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) {
+ if (1 === o) throw o = 4, n.arg;
+ n.dispatchException(n.arg);
+ } else "return" === n.method && n.abrupt("return", n.arg);
+ o = 3;
+ var h = s(r, e, n);
+ if ("normal" === h.type) {
+ if (o = n.done ? 4 : 2, h.arg === f) continue;
+ return {
+ value: h.arg,
+ done: n.done
+ };
+ }
+ "throw" === h.type && (o = 4, n.method = "throw", n.arg = h.arg);
+ }
+ };
+ }(r, n, new Context(o || [])), !0), a;
+ }
+ function s(t, r, e) {
+ try {
+ return {
+ type: "normal",
+ arg: t.call(r, e)
+ };
+ } catch (t) {
+ return {
+ type: "throw",
+ arg: t
+ };
+ }
+ }
+ r.wrap = h;
+ var f = {};
+ function Generator() {}
+ function GeneratorFunction() {}
+ function GeneratorFunctionPrototype() {}
+ var l = {};
+ c(l, i, function () {
+ return this;
+ });
+ var p = Object.getPrototypeOf,
+ y = p && p(p(x([])));
+ y && y !== e && n.call(y, i) && (l = y);
+ var v = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(l);
+ function g(t) {
+ ["next", "throw", "return"].forEach(function (r) {
+ c(t, r, function (t) {
+ return this._invoke(r, t);
+ });
+ });
+ }
+ function AsyncIterator(t, r) {
+ function e(o, i, a, u) {
+ var c = s(t[o], t, i);
+ if ("throw" !== c.type) {
+ var h = c.arg,
+ f = h.value;
+ return f && "object" == _typeof(f) && n.call(f, "__await") ? r.resolve(f.__await).then(function (t) {
+ e("next", t, a, u);
+ }, function (t) {
+ e("throw", t, a, u);
+ }) : r.resolve(f).then(function (t) {
+ h.value = t, a(h);
+ }, function (t) {
+ return e("throw", t, a, u);
+ });
+ }
+ u(c.arg);
+ }
+ var o;
+ c(this, "_invoke", function (t, n) {
+ function i() {
+ return new r(function (r, o) {
+ e(t, n, r, o);
+ });
+ }
+ return o = o ? o.then(i, i) : i();
+ }, !0);
+ }
+ function d(r, e) {
+ var n = e.method,
+ o = r.i[n];
+ if (o === t) return e.delegate = null, "throw" === n && r.i["return"] && (e.method = "return", e.arg = t, d(r, e), "throw" === e.method) || "return" !== n && (e.method = "throw", e.arg = new TypeError("The iterator does not provide a '" + n + "' method")), f;
+ var i = s(o, r.i, e.arg);
+ if ("throw" === i.type) return e.method = "throw", e.arg = i.arg, e.delegate = null, f;
+ var a = i.arg;
+ return a ? a.done ? (e[r.r] = a.value, e.next = r.n, "return" !== e.method && (e.method = "next", e.arg = t), e.delegate = null, f) : a : (e.method = "throw", e.arg = new TypeError("iterator result is not an object"), e.delegate = null, f);
+ }
+ function w(t) {
+ this.tryEntries.push(t);
+ }
+ function m(r) {
+ var e = r[4] || {};
+ e.type = "normal", e.arg = t, r[4] = e;
+ }
+ function Context(t) {
+ this.tryEntries = [[-1]], t.forEach(w, this), this.reset(!0);
+ }
+ function x(r) {
+ if (null != r) {
+ var e = r[i];
+ if (e) return e.call(r);
+ if ("function" == typeof r.next) return r;
+ if (!isNaN(r.length)) {
+ var o = -1,
+ a = function e() {
+ for (; ++o < r.length;) if (n.call(r, o)) return e.value = r[o], e.done = !1, e;
+ return e.value = t, e.done = !0, e;
+ };
+ return a.next = a;
+ }
+ }
+ throw new TypeError(_typeof(r) + " is not iterable");
+ }
+ return GeneratorFunction.prototype = GeneratorFunctionPrototype, c(v, "constructor", GeneratorFunctionPrototype), c(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = c(GeneratorFunctionPrototype, u, "GeneratorFunction"), r.isGeneratorFunction = function (t) {
+ var r = "function" == typeof t && t.constructor;
+ return !!r && (r === GeneratorFunction || "GeneratorFunction" === (r.displayName || r.name));
+ }, r.mark = function (t) {
+ return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, c(t, u, "GeneratorFunction")), t.prototype = Object.create(v), t;
+ }, r.awrap = function (t) {
+ return {
+ __await: t
+ };
+ }, g(AsyncIterator.prototype), c(AsyncIterator.prototype, a, function () {
+ return this;
+ }), r.AsyncIterator = AsyncIterator, r.async = function (t, e, n, o, i) {
+ void 0 === i && (i = Promise);
+ var a = new AsyncIterator(h(t, e, n, o), i);
+ return r.isGeneratorFunction(e) ? a : a.next().then(function (t) {
+ return t.done ? t.value : a.next();
+ });
+ }, g(v), c(v, u, "Generator"), c(v, i, function () {
+ return this;
+ }), c(v, "toString", function () {
+ return "[object Generator]";
+ }), r.keys = function (t) {
+ var r = Object(t),
+ e = [];
+ for (var n in r) e.unshift(n);
+ return function t() {
+ for (; e.length;) if ((n = e.pop()) in r) return t.value = n, t.done = !1, t;
+ return t.done = !0, t;
+ };
+ }, r.values = x, Context.prototype = {
+ constructor: Context,
+ reset: function reset(r) {
+ if (this.prev = this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(m), !r) for (var e in this) "t" === e.charAt(0) && n.call(this, e) && !isNaN(+e.slice(1)) && (this[e] = t);
+ },
+ stop: function stop() {
+ this.done = !0;
+ var t = this.tryEntries[0][4];
+ if ("throw" === t.type) throw t.arg;
+ return this.rval;
+ },
+ dispatchException: function dispatchException(r) {
+ if (this.done) throw r;
+ var e = this;
+ function n(t) {
+ a.type = "throw", a.arg = r, e.next = t;
+ }
+ for (var o = e.tryEntries.length - 1; o >= 0; --o) {
+ var i = this.tryEntries[o],
+ a = i[4],
+ u = this.prev,
+ c = i[1],
+ h = i[2];
+ if (-1 === i[0]) return n("end"), !1;
+ if (!c && !h) throw Error("try statement without catch or finally");
+ if (null != i[0] && i[0] <= u) {
+ if (u < c) return this.method = "next", this.arg = t, n(c), !0;
+ if (u < h) return n(h), !1;
+ }
+ }
+ },
+ abrupt: function abrupt(t, r) {
+ for (var e = this.tryEntries.length - 1; e >= 0; --e) {
+ var n = this.tryEntries[e];
+ if (n[0] > -1 && n[0] <= this.prev && this.prev < n[2]) {
+ var o = n;
+ break;
+ }
+ }
+ o && ("break" === t || "continue" === t) && o[0] <= r && r <= o[2] && (o = null);
+ var i = o ? o[4] : {};
+ return i.type = t, i.arg = r, o ? (this.method = "next", this.next = o[2], f) : this.complete(i);
+ },
+ complete: function complete(t, r) {
+ if ("throw" === t.type) throw t.arg;
+ return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && r && (this.next = r), f;
+ },
+ finish: function finish(t) {
+ for (var r = this.tryEntries.length - 1; r >= 0; --r) {
+ var e = this.tryEntries[r];
+ if (e[2] === t) return this.complete(e[4], e[3]), m(e), f;
+ }
+ },
+ "catch": function _catch(t) {
+ for (var r = this.tryEntries.length - 1; r >= 0; --r) {
+ var e = this.tryEntries[r];
+ if (e[0] === t) {
+ var n = e[4];
+ if ("throw" === n.type) {
+ var o = n.arg;
+ m(e);
+ }
+ return o;
+ }
+ }
+ throw Error("illegal catch attempt");
+ },
+ delegateYield: function delegateYield(r, e, n) {
+ return this.delegate = {
+ i: x(r),
+ r: e,
+ n: n
+ }, "next" === this.method && (this.arg = t), f;
+ }
+ }, r;
+}
+module.exports = _regeneratorRuntime, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/set.js b/backend/node_modules/@babel/runtime/helpers/set.js
new file mode 100644
index 0000000..6421470
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/set.js
@@ -0,0 +1,22 @@
+var superPropBase = require("./superPropBase.js");
+var defineProperty = require("./defineProperty.js");
+function set(e, r, t, o) {
+ return set = "undefined" != typeof Reflect && Reflect.set ? Reflect.set : function (e, r, t, o) {
+ var f,
+ i = superPropBase(e, r);
+ if (i) {
+ if ((f = Object.getOwnPropertyDescriptor(i, r)).set) return f.set.call(o, t), !0;
+ if (!f.writable) return !1;
+ }
+ if (f = Object.getOwnPropertyDescriptor(o, r)) {
+ if (!f.writable) return !1;
+ f.value = t, Object.defineProperty(o, r, f);
+ } else defineProperty(o, r, t);
+ return !0;
+ }, set(e, r, t, o);
+}
+function _set(e, r, t, o, f) {
+ if (!set(e, r, t, o || e) && f) throw new TypeError("failed to set property");
+ return t;
+}
+module.exports = _set, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/setFunctionName.js b/backend/node_modules/@babel/runtime/helpers/setFunctionName.js
new file mode 100644
index 0000000..9664076
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/setFunctionName.js
@@ -0,0 +1,12 @@
+var _typeof = require("./typeof.js")["default"];
+function setFunctionName(e, t, n) {
+ "symbol" == _typeof(t) && (t = (t = t.description) ? "[" + t + "]" : "");
+ try {
+ Object.defineProperty(e, "name", {
+ configurable: !0,
+ value: n ? n + " " + t : t
+ });
+ } catch (e) {}
+ return e;
+}
+module.exports = setFunctionName, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/setPrototypeOf.js b/backend/node_modules/@babel/runtime/helpers/setPrototypeOf.js
new file mode 100644
index 0000000..7d991ff
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/setPrototypeOf.js
@@ -0,0 +1,6 @@
+function _setPrototypeOf(t, e) {
+ return module.exports = _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) {
+ return t.__proto__ = e, t;
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports, _setPrototypeOf(t, e);
+}
+module.exports = _setPrototypeOf, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/skipFirstGeneratorNext.js b/backend/node_modules/@babel/runtime/helpers/skipFirstGeneratorNext.js
new file mode 100644
index 0000000..2aed548
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/skipFirstGeneratorNext.js
@@ -0,0 +1,7 @@
+function _skipFirstGeneratorNext(t) {
+ return function () {
+ var r = t.apply(this, arguments);
+ return r.next(), r;
+ };
+}
+module.exports = _skipFirstGeneratorNext, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/slicedToArray.js b/backend/node_modules/@babel/runtime/helpers/slicedToArray.js
new file mode 100644
index 0000000..3d752c4
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/slicedToArray.js
@@ -0,0 +1,8 @@
+var arrayWithHoles = require("./arrayWithHoles.js");
+var iterableToArrayLimit = require("./iterableToArrayLimit.js");
+var unsupportedIterableToArray = require("./unsupportedIterableToArray.js");
+var nonIterableRest = require("./nonIterableRest.js");
+function _slicedToArray(r, e) {
+ return arrayWithHoles(r) || iterableToArrayLimit(r, e) || unsupportedIterableToArray(r, e) || nonIterableRest();
+}
+module.exports = _slicedToArray, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/superPropBase.js b/backend/node_modules/@babel/runtime/helpers/superPropBase.js
new file mode 100644
index 0000000..5cad459
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/superPropBase.js
@@ -0,0 +1,6 @@
+var getPrototypeOf = require("./getPrototypeOf.js");
+function _superPropBase(t, o) {
+ for (; !{}.hasOwnProperty.call(t, o) && null !== (t = getPrototypeOf(t)););
+ return t;
+}
+module.exports = _superPropBase, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/superPropGet.js b/backend/node_modules/@babel/runtime/helpers/superPropGet.js
new file mode 100644
index 0000000..baf8b10
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/superPropGet.js
@@ -0,0 +1,9 @@
+var get = require("./get.js");
+var getPrototypeOf = require("./getPrototypeOf.js");
+function _superPropGet(t, o, e, r) {
+ var p = get(getPrototypeOf(1 & r ? t.prototype : t), o, e);
+ return 2 & r && "function" == typeof p ? function (t) {
+ return p.apply(e, t);
+ } : p;
+}
+module.exports = _superPropGet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/superPropSet.js b/backend/node_modules/@babel/runtime/helpers/superPropSet.js
new file mode 100644
index 0000000..e0578c0
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/superPropSet.js
@@ -0,0 +1,6 @@
+var set = require("./set.js");
+var getPrototypeOf = require("./getPrototypeOf.js");
+function _superPropSet(t, e, o, r, p, f) {
+ return set(getPrototypeOf(f ? t.prototype : t), e, o, r, p);
+}
+module.exports = _superPropSet, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/taggedTemplateLiteral.js b/backend/node_modules/@babel/runtime/helpers/taggedTemplateLiteral.js
new file mode 100644
index 0000000..38d6065
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/taggedTemplateLiteral.js
@@ -0,0 +1,8 @@
+function _taggedTemplateLiteral(e, t) {
+ return t || (t = e.slice(0)), Object.freeze(Object.defineProperties(e, {
+ raw: {
+ value: Object.freeze(t)
+ }
+ }));
+}
+module.exports = _taggedTemplateLiteral, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/taggedTemplateLiteralLoose.js b/backend/node_modules/@babel/runtime/helpers/taggedTemplateLiteralLoose.js
new file mode 100644
index 0000000..2f8c146
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/taggedTemplateLiteralLoose.js
@@ -0,0 +1,4 @@
+function _taggedTemplateLiteralLoose(e, t) {
+ return t || (t = e.slice(0)), e.raw = t, e;
+}
+module.exports = _taggedTemplateLiteralLoose, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/tdz.js b/backend/node_modules/@babel/runtime/helpers/tdz.js
new file mode 100644
index 0000000..c66f476
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/tdz.js
@@ -0,0 +1,4 @@
+function _tdzError(e) {
+ throw new ReferenceError(e + " is not defined - temporal dead zone");
+}
+module.exports = _tdzError, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/temporalRef.js b/backend/node_modules/@babel/runtime/helpers/temporalRef.js
new file mode 100644
index 0000000..54c9190
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/temporalRef.js
@@ -0,0 +1,6 @@
+var temporalUndefined = require("./temporalUndefined.js");
+var tdz = require("./tdz.js");
+function _temporalRef(r, e) {
+ return r === temporalUndefined ? tdz(e) : r;
+}
+module.exports = _temporalRef, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/temporalUndefined.js b/backend/node_modules/@babel/runtime/helpers/temporalUndefined.js
new file mode 100644
index 0000000..f8def80
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/temporalUndefined.js
@@ -0,0 +1,2 @@
+function _temporalUndefined() {}
+module.exports = _temporalUndefined, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/toArray.js b/backend/node_modules/@babel/runtime/helpers/toArray.js
new file mode 100644
index 0000000..2be1d2b
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/toArray.js
@@ -0,0 +1,8 @@
+var arrayWithHoles = require("./arrayWithHoles.js");
+var iterableToArray = require("./iterableToArray.js");
+var unsupportedIterableToArray = require("./unsupportedIterableToArray.js");
+var nonIterableRest = require("./nonIterableRest.js");
+function _toArray(r) {
+ return arrayWithHoles(r) || iterableToArray(r) || unsupportedIterableToArray(r) || nonIterableRest();
+}
+module.exports = _toArray, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/toConsumableArray.js b/backend/node_modules/@babel/runtime/helpers/toConsumableArray.js
new file mode 100644
index 0000000..698f9c6
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/toConsumableArray.js
@@ -0,0 +1,8 @@
+var arrayWithoutHoles = require("./arrayWithoutHoles.js");
+var iterableToArray = require("./iterableToArray.js");
+var unsupportedIterableToArray = require("./unsupportedIterableToArray.js");
+var nonIterableSpread = require("./nonIterableSpread.js");
+function _toConsumableArray(r) {
+ return arrayWithoutHoles(r) || iterableToArray(r) || unsupportedIterableToArray(r) || nonIterableSpread();
+}
+module.exports = _toConsumableArray, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/toPrimitive.js b/backend/node_modules/@babel/runtime/helpers/toPrimitive.js
new file mode 100644
index 0000000..ef9d249
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/toPrimitive.js
@@ -0,0 +1,12 @@
+var _typeof = require("./typeof.js")["default"];
+function toPrimitive(t, r) {
+ if ("object" != _typeof(t) || !t) return t;
+ var e = t[Symbol.toPrimitive];
+ if (void 0 !== e) {
+ var i = e.call(t, r || "default");
+ if ("object" != _typeof(i)) return i;
+ throw new TypeError("@@toPrimitive must return a primitive value.");
+ }
+ return ("string" === r ? String : Number)(t);
+}
+module.exports = toPrimitive, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/toPropertyKey.js b/backend/node_modules/@babel/runtime/helpers/toPropertyKey.js
new file mode 100644
index 0000000..3ca3d4f
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/toPropertyKey.js
@@ -0,0 +1,7 @@
+var _typeof = require("./typeof.js")["default"];
+var toPrimitive = require("./toPrimitive.js");
+function toPropertyKey(t) {
+ var i = toPrimitive(t, "string");
+ return "symbol" == _typeof(i) ? i : i + "";
+}
+module.exports = toPropertyKey, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/toSetter.js b/backend/node_modules/@babel/runtime/helpers/toSetter.js
new file mode 100644
index 0000000..e0012a8
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/toSetter.js
@@ -0,0 +1,10 @@
+function _toSetter(t, e, n) {
+ e || (e = []);
+ var r = e.length++;
+ return Object.defineProperty({}, "_", {
+ set: function set(o) {
+ e[r] = o, t.apply(n, e);
+ }
+ });
+}
+module.exports = _toSetter, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/tsRewriteRelativeImportExtensions.js b/backend/node_modules/@babel/runtime/helpers/tsRewriteRelativeImportExtensions.js
new file mode 100644
index 0000000..4de0e4d
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/tsRewriteRelativeImportExtensions.js
@@ -0,0 +1,6 @@
+function tsRewriteRelativeImportExtensions(t, e) {
+ return "string" == typeof t && /^\.\.?\//.test(t) ? t.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+)?)\.([cm]?)ts$/i, function (t, s, r, n, o) {
+ return s ? e ? ".jsx" : ".js" : !r || n && o ? r + n + "." + o.toLowerCase() + "js" : t;
+ }) : t;
+}
+module.exports = tsRewriteRelativeImportExtensions, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/typeof.js b/backend/node_modules/@babel/runtime/helpers/typeof.js
new file mode 100644
index 0000000..b6fbfaf
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/typeof.js
@@ -0,0 +1,10 @@
+function _typeof(o) {
+ "@babel/helpers - typeof";
+
+ return module.exports = _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
+ return typeof o;
+ } : function (o) {
+ return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports, _typeof(o);
+}
+module.exports = _typeof, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js b/backend/node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js
new file mode 100644
index 0000000..8fb1a71
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/unsupportedIterableToArray.js
@@ -0,0 +1,9 @@
+var arrayLikeToArray = require("./arrayLikeToArray.js");
+function _unsupportedIterableToArray(r, a) {
+ if (r) {
+ if ("string" == typeof r) return arrayLikeToArray(r, a);
+ var t = {}.toString.call(r).slice(8, -1);
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? arrayLikeToArray(r, a) : void 0;
+ }
+}
+module.exports = _unsupportedIterableToArray, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/using.js b/backend/node_modules/@babel/runtime/helpers/using.js
new file mode 100644
index 0000000..37c79e2
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/using.js
@@ -0,0 +1,12 @@
+function _using(o, n, e) {
+ if (null == n) return n;
+ if (Object(n) !== n) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
+ if (e) var r = n[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
+ if (null == r && (r = n[Symbol.dispose || Symbol["for"]("Symbol.dispose")]), "function" != typeof r) throw new TypeError("Property [Symbol.dispose] is not a function.");
+ return o.push({
+ v: n,
+ d: r,
+ a: e
+ }), n;
+}
+module.exports = _using, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/usingCtx.js b/backend/node_modules/@babel/runtime/helpers/usingCtx.js
new file mode 100644
index 0000000..652ab15
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/usingCtx.js
@@ -0,0 +1,59 @@
+function _usingCtx() {
+ var r = "function" == typeof SuppressedError ? SuppressedError : function (r, e) {
+ var n = Error();
+ return n.name = "SuppressedError", n.error = r, n.suppressed = e, n;
+ },
+ e = {},
+ n = [];
+ function using(r, e) {
+ if (null != e) {
+ if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
+ if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
+ if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o;
+ if ("function" != typeof o) throw new TypeError("Object is not disposable.");
+ t && (o = function o() {
+ try {
+ t.call(e);
+ } catch (r) {
+ return Promise.reject(r);
+ }
+ }), n.push({
+ v: e,
+ d: o,
+ a: r
+ });
+ } else r && n.push({
+ d: e,
+ a: r
+ });
+ return e;
+ }
+ return {
+ e: e,
+ u: using.bind(null, !1),
+ a: using.bind(null, !0),
+ d: function d() {
+ var o,
+ t = this.e,
+ s = 0;
+ function next() {
+ for (; o = n.pop();) try {
+ if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);
+ if (o.d) {
+ var r = o.d.call(o.v);
+ if (o.a) return s |= 2, Promise.resolve(r).then(next, err);
+ } else s |= 1;
+ } catch (r) {
+ return err(r);
+ }
+ if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();
+ if (t !== e) throw t;
+ }
+ function err(n) {
+ return t = t !== e ? new r(n, t) : n, next();
+ }
+ return next();
+ }
+ };
+}
+module.exports = _usingCtx, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/wrapAsyncGenerator.js b/backend/node_modules/@babel/runtime/helpers/wrapAsyncGenerator.js
new file mode 100644
index 0000000..b818e2e
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/wrapAsyncGenerator.js
@@ -0,0 +1,69 @@
+var OverloadYield = require("./OverloadYield.js");
+function _wrapAsyncGenerator(e) {
+ return function () {
+ return new AsyncGenerator(e.apply(this, arguments));
+ };
+}
+function AsyncGenerator(e) {
+ var r, t;
+ function resume(r, t) {
+ try {
+ var n = e[r](t),
+ o = n.value,
+ u = o instanceof OverloadYield;
+ Promise.resolve(u ? o.v : o).then(function (t) {
+ if (u) {
+ var i = "return" === r ? "return" : "next";
+ if (!o.k || t.done) return resume(i, t);
+ t = e[i](t).value;
+ }
+ settle(n.done ? "return" : "normal", t);
+ }, function (e) {
+ resume("throw", e);
+ });
+ } catch (e) {
+ settle("throw", e);
+ }
+ }
+ function settle(e, n) {
+ switch (e) {
+ case "return":
+ r.resolve({
+ value: n,
+ done: !0
+ });
+ break;
+ case "throw":
+ r.reject(n);
+ break;
+ default:
+ r.resolve({
+ value: n,
+ done: !1
+ });
+ }
+ (r = r.next) ? resume(r.key, r.arg) : t = null;
+ }
+ this._invoke = function (e, n) {
+ return new Promise(function (o, u) {
+ var i = {
+ key: e,
+ arg: n,
+ resolve: o,
+ reject: u,
+ next: null
+ };
+ t ? t = t.next = i : (r = t = i, resume(e, n));
+ });
+ }, "function" != typeof e["return"] && (this["return"] = void 0);
+}
+AsyncGenerator.prototype["function" == typeof Symbol && Symbol.asyncIterator || "@@asyncIterator"] = function () {
+ return this;
+}, AsyncGenerator.prototype.next = function (e) {
+ return this._invoke("next", e);
+}, AsyncGenerator.prototype["throw"] = function (e) {
+ return this._invoke("throw", e);
+}, AsyncGenerator.prototype["return"] = function (e) {
+ return this._invoke("return", e);
+};
+module.exports = _wrapAsyncGenerator, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/wrapNativeSuper.js b/backend/node_modules/@babel/runtime/helpers/wrapNativeSuper.js
new file mode 100644
index 0000000..acd87ab
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/wrapNativeSuper.js
@@ -0,0 +1,27 @@
+var getPrototypeOf = require("./getPrototypeOf.js");
+var setPrototypeOf = require("./setPrototypeOf.js");
+var isNativeFunction = require("./isNativeFunction.js");
+var construct = require("./construct.js");
+function _wrapNativeSuper(t) {
+ var r = "function" == typeof Map ? new Map() : void 0;
+ return module.exports = _wrapNativeSuper = function _wrapNativeSuper(t) {
+ if (null === t || !isNativeFunction(t)) return t;
+ if ("function" != typeof t) throw new TypeError("Super expression must either be null or a function");
+ if (void 0 !== r) {
+ if (r.has(t)) return r.get(t);
+ r.set(t, Wrapper);
+ }
+ function Wrapper() {
+ return construct(t, arguments, getPrototypeOf(this).constructor);
+ }
+ return Wrapper.prototype = Object.create(t.prototype, {
+ constructor: {
+ value: Wrapper,
+ enumerable: !1,
+ writable: !0,
+ configurable: !0
+ }
+ }), setPrototypeOf(Wrapper, t);
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports, _wrapNativeSuper(t);
+}
+module.exports = _wrapNativeSuper, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/wrapRegExp.js b/backend/node_modules/@babel/runtime/helpers/wrapRegExp.js
new file mode 100644
index 0000000..3d6e6ce
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/wrapRegExp.js
@@ -0,0 +1,52 @@
+var _typeof = require("./typeof.js")["default"];
+var setPrototypeOf = require("./setPrototypeOf.js");
+var inherits = require("./inherits.js");
+function _wrapRegExp() {
+ module.exports = _wrapRegExp = function _wrapRegExp(e, r) {
+ return new BabelRegExp(e, void 0, r);
+ }, module.exports.__esModule = true, module.exports["default"] = module.exports;
+ var e = RegExp.prototype,
+ r = new WeakMap();
+ function BabelRegExp(e, t, p) {
+ var o = RegExp(e, t);
+ return r.set(o, p || r.get(e)), setPrototypeOf(o, BabelRegExp.prototype);
+ }
+ function buildGroups(e, t) {
+ var p = r.get(t);
+ return Object.keys(p).reduce(function (r, t) {
+ var o = p[t];
+ if ("number" == typeof o) r[t] = e[o];else {
+ for (var i = 0; void 0 === e[o[i]] && i + 1 < o.length;) i++;
+ r[t] = e[o[i]];
+ }
+ return r;
+ }, Object.create(null));
+ }
+ return inherits(BabelRegExp, RegExp), BabelRegExp.prototype.exec = function (r) {
+ var t = e.exec.call(this, r);
+ if (t) {
+ t.groups = buildGroups(t, this);
+ var p = t.indices;
+ p && (p.groups = buildGroups(p, this));
+ }
+ return t;
+ }, BabelRegExp.prototype[Symbol.replace] = function (t, p) {
+ if ("string" == typeof p) {
+ var o = r.get(this);
+ return e[Symbol.replace].call(this, t, p.replace(/\$<([^>]+)(>|$)/g, function (e, r, t) {
+ if ("" === t) return e;
+ var p = o[r];
+ return Array.isArray(p) ? "$" + p.join("$") : "number" == typeof p ? "$" + p : "";
+ }));
+ }
+ if ("function" == typeof p) {
+ var i = this;
+ return e[Symbol.replace].call(this, t, function () {
+ var e = arguments;
+ return "object" != _typeof(e[e.length - 1]) && (e = [].slice.call(e)).push(buildGroups(e, i)), p.apply(this, e);
+ });
+ }
+ return e[Symbol.replace].call(this, t, p);
+ }, _wrapRegExp.apply(this, arguments);
+}
+module.exports = _wrapRegExp, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/helpers/writeOnlyError.js b/backend/node_modules/@babel/runtime/helpers/writeOnlyError.js
new file mode 100644
index 0000000..c98ee82
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/helpers/writeOnlyError.js
@@ -0,0 +1,4 @@
+function _writeOnlyError(r) {
+ throw new TypeError('"' + r + '" is write-only');
+}
+module.exports = _writeOnlyError, module.exports.__esModule = true, module.exports["default"] = module.exports;
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/package.json b/backend/node_modules/@babel/runtime/package.json
new file mode 100644
index 0000000..3bba6e1
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/package.json
@@ -0,0 +1,1062 @@
+{
+ "name": "@babel/runtime",
+ "version": "7.27.1",
+ "description": "babel's modular runtime helpers",
+ "license": "MIT",
+ "publishConfig": {
+ "access": "public"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/babel/babel.git",
+ "directory": "packages/babel-runtime"
+ },
+ "homepage": "https://babel.dev/docs/en/next/babel-runtime",
+ "author": "The Babel Team (https://babel.dev/team)",
+ "exports": {
+ "./helpers/OverloadYield": [
+ {
+ "node": "./helpers/OverloadYield.js",
+ "import": "./helpers/esm/OverloadYield.js",
+ "default": "./helpers/OverloadYield.js"
+ },
+ "./helpers/OverloadYield.js"
+ ],
+ "./helpers/esm/OverloadYield": "./helpers/esm/OverloadYield.js",
+ "./helpers/applyDecoratedDescriptor": [
+ {
+ "node": "./helpers/applyDecoratedDescriptor.js",
+ "import": "./helpers/esm/applyDecoratedDescriptor.js",
+ "default": "./helpers/applyDecoratedDescriptor.js"
+ },
+ "./helpers/applyDecoratedDescriptor.js"
+ ],
+ "./helpers/esm/applyDecoratedDescriptor": "./helpers/esm/applyDecoratedDescriptor.js",
+ "./helpers/applyDecs2311": [
+ {
+ "node": "./helpers/applyDecs2311.js",
+ "import": "./helpers/esm/applyDecs2311.js",
+ "default": "./helpers/applyDecs2311.js"
+ },
+ "./helpers/applyDecs2311.js"
+ ],
+ "./helpers/esm/applyDecs2311": "./helpers/esm/applyDecs2311.js",
+ "./helpers/arrayLikeToArray": [
+ {
+ "node": "./helpers/arrayLikeToArray.js",
+ "import": "./helpers/esm/arrayLikeToArray.js",
+ "default": "./helpers/arrayLikeToArray.js"
+ },
+ "./helpers/arrayLikeToArray.js"
+ ],
+ "./helpers/esm/arrayLikeToArray": "./helpers/esm/arrayLikeToArray.js",
+ "./helpers/arrayWithHoles": [
+ {
+ "node": "./helpers/arrayWithHoles.js",
+ "import": "./helpers/esm/arrayWithHoles.js",
+ "default": "./helpers/arrayWithHoles.js"
+ },
+ "./helpers/arrayWithHoles.js"
+ ],
+ "./helpers/esm/arrayWithHoles": "./helpers/esm/arrayWithHoles.js",
+ "./helpers/arrayWithoutHoles": [
+ {
+ "node": "./helpers/arrayWithoutHoles.js",
+ "import": "./helpers/esm/arrayWithoutHoles.js",
+ "default": "./helpers/arrayWithoutHoles.js"
+ },
+ "./helpers/arrayWithoutHoles.js"
+ ],
+ "./helpers/esm/arrayWithoutHoles": "./helpers/esm/arrayWithoutHoles.js",
+ "./helpers/assertClassBrand": [
+ {
+ "node": "./helpers/assertClassBrand.js",
+ "import": "./helpers/esm/assertClassBrand.js",
+ "default": "./helpers/assertClassBrand.js"
+ },
+ "./helpers/assertClassBrand.js"
+ ],
+ "./helpers/esm/assertClassBrand": "./helpers/esm/assertClassBrand.js",
+ "./helpers/assertThisInitialized": [
+ {
+ "node": "./helpers/assertThisInitialized.js",
+ "import": "./helpers/esm/assertThisInitialized.js",
+ "default": "./helpers/assertThisInitialized.js"
+ },
+ "./helpers/assertThisInitialized.js"
+ ],
+ "./helpers/esm/assertThisInitialized": "./helpers/esm/assertThisInitialized.js",
+ "./helpers/asyncGeneratorDelegate": [
+ {
+ "node": "./helpers/asyncGeneratorDelegate.js",
+ "import": "./helpers/esm/asyncGeneratorDelegate.js",
+ "default": "./helpers/asyncGeneratorDelegate.js"
+ },
+ "./helpers/asyncGeneratorDelegate.js"
+ ],
+ "./helpers/esm/asyncGeneratorDelegate": "./helpers/esm/asyncGeneratorDelegate.js",
+ "./helpers/asyncIterator": [
+ {
+ "node": "./helpers/asyncIterator.js",
+ "import": "./helpers/esm/asyncIterator.js",
+ "default": "./helpers/asyncIterator.js"
+ },
+ "./helpers/asyncIterator.js"
+ ],
+ "./helpers/esm/asyncIterator": "./helpers/esm/asyncIterator.js",
+ "./helpers/asyncToGenerator": [
+ {
+ "node": "./helpers/asyncToGenerator.js",
+ "import": "./helpers/esm/asyncToGenerator.js",
+ "default": "./helpers/asyncToGenerator.js"
+ },
+ "./helpers/asyncToGenerator.js"
+ ],
+ "./helpers/esm/asyncToGenerator": "./helpers/esm/asyncToGenerator.js",
+ "./helpers/awaitAsyncGenerator": [
+ {
+ "node": "./helpers/awaitAsyncGenerator.js",
+ "import": "./helpers/esm/awaitAsyncGenerator.js",
+ "default": "./helpers/awaitAsyncGenerator.js"
+ },
+ "./helpers/awaitAsyncGenerator.js"
+ ],
+ "./helpers/esm/awaitAsyncGenerator": "./helpers/esm/awaitAsyncGenerator.js",
+ "./helpers/callSuper": [
+ {
+ "node": "./helpers/callSuper.js",
+ "import": "./helpers/esm/callSuper.js",
+ "default": "./helpers/callSuper.js"
+ },
+ "./helpers/callSuper.js"
+ ],
+ "./helpers/esm/callSuper": "./helpers/esm/callSuper.js",
+ "./helpers/checkInRHS": [
+ {
+ "node": "./helpers/checkInRHS.js",
+ "import": "./helpers/esm/checkInRHS.js",
+ "default": "./helpers/checkInRHS.js"
+ },
+ "./helpers/checkInRHS.js"
+ ],
+ "./helpers/esm/checkInRHS": "./helpers/esm/checkInRHS.js",
+ "./helpers/checkPrivateRedeclaration": [
+ {
+ "node": "./helpers/checkPrivateRedeclaration.js",
+ "import": "./helpers/esm/checkPrivateRedeclaration.js",
+ "default": "./helpers/checkPrivateRedeclaration.js"
+ },
+ "./helpers/checkPrivateRedeclaration.js"
+ ],
+ "./helpers/esm/checkPrivateRedeclaration": "./helpers/esm/checkPrivateRedeclaration.js",
+ "./helpers/classCallCheck": [
+ {
+ "node": "./helpers/classCallCheck.js",
+ "import": "./helpers/esm/classCallCheck.js",
+ "default": "./helpers/classCallCheck.js"
+ },
+ "./helpers/classCallCheck.js"
+ ],
+ "./helpers/esm/classCallCheck": "./helpers/esm/classCallCheck.js",
+ "./helpers/classNameTDZError": [
+ {
+ "node": "./helpers/classNameTDZError.js",
+ "import": "./helpers/esm/classNameTDZError.js",
+ "default": "./helpers/classNameTDZError.js"
+ },
+ "./helpers/classNameTDZError.js"
+ ],
+ "./helpers/esm/classNameTDZError": "./helpers/esm/classNameTDZError.js",
+ "./helpers/classPrivateFieldGet2": [
+ {
+ "node": "./helpers/classPrivateFieldGet2.js",
+ "import": "./helpers/esm/classPrivateFieldGet2.js",
+ "default": "./helpers/classPrivateFieldGet2.js"
+ },
+ "./helpers/classPrivateFieldGet2.js"
+ ],
+ "./helpers/esm/classPrivateFieldGet2": "./helpers/esm/classPrivateFieldGet2.js",
+ "./helpers/classPrivateFieldInitSpec": [
+ {
+ "node": "./helpers/classPrivateFieldInitSpec.js",
+ "import": "./helpers/esm/classPrivateFieldInitSpec.js",
+ "default": "./helpers/classPrivateFieldInitSpec.js"
+ },
+ "./helpers/classPrivateFieldInitSpec.js"
+ ],
+ "./helpers/esm/classPrivateFieldInitSpec": "./helpers/esm/classPrivateFieldInitSpec.js",
+ "./helpers/classPrivateFieldLooseBase": [
+ {
+ "node": "./helpers/classPrivateFieldLooseBase.js",
+ "import": "./helpers/esm/classPrivateFieldLooseBase.js",
+ "default": "./helpers/classPrivateFieldLooseBase.js"
+ },
+ "./helpers/classPrivateFieldLooseBase.js"
+ ],
+ "./helpers/esm/classPrivateFieldLooseBase": "./helpers/esm/classPrivateFieldLooseBase.js",
+ "./helpers/classPrivateFieldLooseKey": [
+ {
+ "node": "./helpers/classPrivateFieldLooseKey.js",
+ "import": "./helpers/esm/classPrivateFieldLooseKey.js",
+ "default": "./helpers/classPrivateFieldLooseKey.js"
+ },
+ "./helpers/classPrivateFieldLooseKey.js"
+ ],
+ "./helpers/esm/classPrivateFieldLooseKey": "./helpers/esm/classPrivateFieldLooseKey.js",
+ "./helpers/classPrivateFieldSet2": [
+ {
+ "node": "./helpers/classPrivateFieldSet2.js",
+ "import": "./helpers/esm/classPrivateFieldSet2.js",
+ "default": "./helpers/classPrivateFieldSet2.js"
+ },
+ "./helpers/classPrivateFieldSet2.js"
+ ],
+ "./helpers/esm/classPrivateFieldSet2": "./helpers/esm/classPrivateFieldSet2.js",
+ "./helpers/classPrivateGetter": [
+ {
+ "node": "./helpers/classPrivateGetter.js",
+ "import": "./helpers/esm/classPrivateGetter.js",
+ "default": "./helpers/classPrivateGetter.js"
+ },
+ "./helpers/classPrivateGetter.js"
+ ],
+ "./helpers/esm/classPrivateGetter": "./helpers/esm/classPrivateGetter.js",
+ "./helpers/classPrivateMethodInitSpec": [
+ {
+ "node": "./helpers/classPrivateMethodInitSpec.js",
+ "import": "./helpers/esm/classPrivateMethodInitSpec.js",
+ "default": "./helpers/classPrivateMethodInitSpec.js"
+ },
+ "./helpers/classPrivateMethodInitSpec.js"
+ ],
+ "./helpers/esm/classPrivateMethodInitSpec": "./helpers/esm/classPrivateMethodInitSpec.js",
+ "./helpers/classPrivateSetter": [
+ {
+ "node": "./helpers/classPrivateSetter.js",
+ "import": "./helpers/esm/classPrivateSetter.js",
+ "default": "./helpers/classPrivateSetter.js"
+ },
+ "./helpers/classPrivateSetter.js"
+ ],
+ "./helpers/esm/classPrivateSetter": "./helpers/esm/classPrivateSetter.js",
+ "./helpers/classStaticPrivateMethodGet": [
+ {
+ "node": "./helpers/classStaticPrivateMethodGet.js",
+ "import": "./helpers/esm/classStaticPrivateMethodGet.js",
+ "default": "./helpers/classStaticPrivateMethodGet.js"
+ },
+ "./helpers/classStaticPrivateMethodGet.js"
+ ],
+ "./helpers/esm/classStaticPrivateMethodGet": "./helpers/esm/classStaticPrivateMethodGet.js",
+ "./helpers/construct": [
+ {
+ "node": "./helpers/construct.js",
+ "import": "./helpers/esm/construct.js",
+ "default": "./helpers/construct.js"
+ },
+ "./helpers/construct.js"
+ ],
+ "./helpers/esm/construct": "./helpers/esm/construct.js",
+ "./helpers/createClass": [
+ {
+ "node": "./helpers/createClass.js",
+ "import": "./helpers/esm/createClass.js",
+ "default": "./helpers/createClass.js"
+ },
+ "./helpers/createClass.js"
+ ],
+ "./helpers/esm/createClass": "./helpers/esm/createClass.js",
+ "./helpers/createForOfIteratorHelper": [
+ {
+ "node": "./helpers/createForOfIteratorHelper.js",
+ "import": "./helpers/esm/createForOfIteratorHelper.js",
+ "default": "./helpers/createForOfIteratorHelper.js"
+ },
+ "./helpers/createForOfIteratorHelper.js"
+ ],
+ "./helpers/esm/createForOfIteratorHelper": "./helpers/esm/createForOfIteratorHelper.js",
+ "./helpers/createForOfIteratorHelperLoose": [
+ {
+ "node": "./helpers/createForOfIteratorHelperLoose.js",
+ "import": "./helpers/esm/createForOfIteratorHelperLoose.js",
+ "default": "./helpers/createForOfIteratorHelperLoose.js"
+ },
+ "./helpers/createForOfIteratorHelperLoose.js"
+ ],
+ "./helpers/esm/createForOfIteratorHelperLoose": "./helpers/esm/createForOfIteratorHelperLoose.js",
+ "./helpers/createSuper": [
+ {
+ "node": "./helpers/createSuper.js",
+ "import": "./helpers/esm/createSuper.js",
+ "default": "./helpers/createSuper.js"
+ },
+ "./helpers/createSuper.js"
+ ],
+ "./helpers/esm/createSuper": "./helpers/esm/createSuper.js",
+ "./helpers/decorate": [
+ {
+ "node": "./helpers/decorate.js",
+ "import": "./helpers/esm/decorate.js",
+ "default": "./helpers/decorate.js"
+ },
+ "./helpers/decorate.js"
+ ],
+ "./helpers/esm/decorate": "./helpers/esm/decorate.js",
+ "./helpers/defaults": [
+ {
+ "node": "./helpers/defaults.js",
+ "import": "./helpers/esm/defaults.js",
+ "default": "./helpers/defaults.js"
+ },
+ "./helpers/defaults.js"
+ ],
+ "./helpers/esm/defaults": "./helpers/esm/defaults.js",
+ "./helpers/defineAccessor": [
+ {
+ "node": "./helpers/defineAccessor.js",
+ "import": "./helpers/esm/defineAccessor.js",
+ "default": "./helpers/defineAccessor.js"
+ },
+ "./helpers/defineAccessor.js"
+ ],
+ "./helpers/esm/defineAccessor": "./helpers/esm/defineAccessor.js",
+ "./helpers/defineProperty": [
+ {
+ "node": "./helpers/defineProperty.js",
+ "import": "./helpers/esm/defineProperty.js",
+ "default": "./helpers/defineProperty.js"
+ },
+ "./helpers/defineProperty.js"
+ ],
+ "./helpers/esm/defineProperty": "./helpers/esm/defineProperty.js",
+ "./helpers/extends": [
+ {
+ "node": "./helpers/extends.js",
+ "import": "./helpers/esm/extends.js",
+ "default": "./helpers/extends.js"
+ },
+ "./helpers/extends.js"
+ ],
+ "./helpers/esm/extends": "./helpers/esm/extends.js",
+ "./helpers/get": [
+ {
+ "node": "./helpers/get.js",
+ "import": "./helpers/esm/get.js",
+ "default": "./helpers/get.js"
+ },
+ "./helpers/get.js"
+ ],
+ "./helpers/esm/get": "./helpers/esm/get.js",
+ "./helpers/getPrototypeOf": [
+ {
+ "node": "./helpers/getPrototypeOf.js",
+ "import": "./helpers/esm/getPrototypeOf.js",
+ "default": "./helpers/getPrototypeOf.js"
+ },
+ "./helpers/getPrototypeOf.js"
+ ],
+ "./helpers/esm/getPrototypeOf": "./helpers/esm/getPrototypeOf.js",
+ "./helpers/identity": [
+ {
+ "node": "./helpers/identity.js",
+ "import": "./helpers/esm/identity.js",
+ "default": "./helpers/identity.js"
+ },
+ "./helpers/identity.js"
+ ],
+ "./helpers/esm/identity": "./helpers/esm/identity.js",
+ "./helpers/importDeferProxy": [
+ {
+ "node": "./helpers/importDeferProxy.js",
+ "import": "./helpers/esm/importDeferProxy.js",
+ "default": "./helpers/importDeferProxy.js"
+ },
+ "./helpers/importDeferProxy.js"
+ ],
+ "./helpers/esm/importDeferProxy": "./helpers/esm/importDeferProxy.js",
+ "./helpers/inherits": [
+ {
+ "node": "./helpers/inherits.js",
+ "import": "./helpers/esm/inherits.js",
+ "default": "./helpers/inherits.js"
+ },
+ "./helpers/inherits.js"
+ ],
+ "./helpers/esm/inherits": "./helpers/esm/inherits.js",
+ "./helpers/inheritsLoose": [
+ {
+ "node": "./helpers/inheritsLoose.js",
+ "import": "./helpers/esm/inheritsLoose.js",
+ "default": "./helpers/inheritsLoose.js"
+ },
+ "./helpers/inheritsLoose.js"
+ ],
+ "./helpers/esm/inheritsLoose": "./helpers/esm/inheritsLoose.js",
+ "./helpers/initializerDefineProperty": [
+ {
+ "node": "./helpers/initializerDefineProperty.js",
+ "import": "./helpers/esm/initializerDefineProperty.js",
+ "default": "./helpers/initializerDefineProperty.js"
+ },
+ "./helpers/initializerDefineProperty.js"
+ ],
+ "./helpers/esm/initializerDefineProperty": "./helpers/esm/initializerDefineProperty.js",
+ "./helpers/initializerWarningHelper": [
+ {
+ "node": "./helpers/initializerWarningHelper.js",
+ "import": "./helpers/esm/initializerWarningHelper.js",
+ "default": "./helpers/initializerWarningHelper.js"
+ },
+ "./helpers/initializerWarningHelper.js"
+ ],
+ "./helpers/esm/initializerWarningHelper": "./helpers/esm/initializerWarningHelper.js",
+ "./helpers/instanceof": [
+ {
+ "node": "./helpers/instanceof.js",
+ "import": "./helpers/esm/instanceof.js",
+ "default": "./helpers/instanceof.js"
+ },
+ "./helpers/instanceof.js"
+ ],
+ "./helpers/esm/instanceof": "./helpers/esm/instanceof.js",
+ "./helpers/interopRequireDefault": [
+ {
+ "node": "./helpers/interopRequireDefault.js",
+ "import": "./helpers/esm/interopRequireDefault.js",
+ "default": "./helpers/interopRequireDefault.js"
+ },
+ "./helpers/interopRequireDefault.js"
+ ],
+ "./helpers/esm/interopRequireDefault": "./helpers/esm/interopRequireDefault.js",
+ "./helpers/interopRequireWildcard": [
+ {
+ "node": "./helpers/interopRequireWildcard.js",
+ "import": "./helpers/esm/interopRequireWildcard.js",
+ "default": "./helpers/interopRequireWildcard.js"
+ },
+ "./helpers/interopRequireWildcard.js"
+ ],
+ "./helpers/esm/interopRequireWildcard": "./helpers/esm/interopRequireWildcard.js",
+ "./helpers/isNativeFunction": [
+ {
+ "node": "./helpers/isNativeFunction.js",
+ "import": "./helpers/esm/isNativeFunction.js",
+ "default": "./helpers/isNativeFunction.js"
+ },
+ "./helpers/isNativeFunction.js"
+ ],
+ "./helpers/esm/isNativeFunction": "./helpers/esm/isNativeFunction.js",
+ "./helpers/isNativeReflectConstruct": [
+ {
+ "node": "./helpers/isNativeReflectConstruct.js",
+ "import": "./helpers/esm/isNativeReflectConstruct.js",
+ "default": "./helpers/isNativeReflectConstruct.js"
+ },
+ "./helpers/isNativeReflectConstruct.js"
+ ],
+ "./helpers/esm/isNativeReflectConstruct": "./helpers/esm/isNativeReflectConstruct.js",
+ "./helpers/iterableToArray": [
+ {
+ "node": "./helpers/iterableToArray.js",
+ "import": "./helpers/esm/iterableToArray.js",
+ "default": "./helpers/iterableToArray.js"
+ },
+ "./helpers/iterableToArray.js"
+ ],
+ "./helpers/esm/iterableToArray": "./helpers/esm/iterableToArray.js",
+ "./helpers/iterableToArrayLimit": [
+ {
+ "node": "./helpers/iterableToArrayLimit.js",
+ "import": "./helpers/esm/iterableToArrayLimit.js",
+ "default": "./helpers/iterableToArrayLimit.js"
+ },
+ "./helpers/iterableToArrayLimit.js"
+ ],
+ "./helpers/esm/iterableToArrayLimit": "./helpers/esm/iterableToArrayLimit.js",
+ "./helpers/jsx": [
+ {
+ "node": "./helpers/jsx.js",
+ "import": "./helpers/esm/jsx.js",
+ "default": "./helpers/jsx.js"
+ },
+ "./helpers/jsx.js"
+ ],
+ "./helpers/esm/jsx": "./helpers/esm/jsx.js",
+ "./helpers/maybeArrayLike": [
+ {
+ "node": "./helpers/maybeArrayLike.js",
+ "import": "./helpers/esm/maybeArrayLike.js",
+ "default": "./helpers/maybeArrayLike.js"
+ },
+ "./helpers/maybeArrayLike.js"
+ ],
+ "./helpers/esm/maybeArrayLike": "./helpers/esm/maybeArrayLike.js",
+ "./helpers/newArrowCheck": [
+ {
+ "node": "./helpers/newArrowCheck.js",
+ "import": "./helpers/esm/newArrowCheck.js",
+ "default": "./helpers/newArrowCheck.js"
+ },
+ "./helpers/newArrowCheck.js"
+ ],
+ "./helpers/esm/newArrowCheck": "./helpers/esm/newArrowCheck.js",
+ "./helpers/nonIterableRest": [
+ {
+ "node": "./helpers/nonIterableRest.js",
+ "import": "./helpers/esm/nonIterableRest.js",
+ "default": "./helpers/nonIterableRest.js"
+ },
+ "./helpers/nonIterableRest.js"
+ ],
+ "./helpers/esm/nonIterableRest": "./helpers/esm/nonIterableRest.js",
+ "./helpers/nonIterableSpread": [
+ {
+ "node": "./helpers/nonIterableSpread.js",
+ "import": "./helpers/esm/nonIterableSpread.js",
+ "default": "./helpers/nonIterableSpread.js"
+ },
+ "./helpers/nonIterableSpread.js"
+ ],
+ "./helpers/esm/nonIterableSpread": "./helpers/esm/nonIterableSpread.js",
+ "./helpers/nullishReceiverError": [
+ {
+ "node": "./helpers/nullishReceiverError.js",
+ "import": "./helpers/esm/nullishReceiverError.js",
+ "default": "./helpers/nullishReceiverError.js"
+ },
+ "./helpers/nullishReceiverError.js"
+ ],
+ "./helpers/esm/nullishReceiverError": "./helpers/esm/nullishReceiverError.js",
+ "./helpers/objectDestructuringEmpty": [
+ {
+ "node": "./helpers/objectDestructuringEmpty.js",
+ "import": "./helpers/esm/objectDestructuringEmpty.js",
+ "default": "./helpers/objectDestructuringEmpty.js"
+ },
+ "./helpers/objectDestructuringEmpty.js"
+ ],
+ "./helpers/esm/objectDestructuringEmpty": "./helpers/esm/objectDestructuringEmpty.js",
+ "./helpers/objectSpread2": [
+ {
+ "node": "./helpers/objectSpread2.js",
+ "import": "./helpers/esm/objectSpread2.js",
+ "default": "./helpers/objectSpread2.js"
+ },
+ "./helpers/objectSpread2.js"
+ ],
+ "./helpers/esm/objectSpread2": "./helpers/esm/objectSpread2.js",
+ "./helpers/objectWithoutProperties": [
+ {
+ "node": "./helpers/objectWithoutProperties.js",
+ "import": "./helpers/esm/objectWithoutProperties.js",
+ "default": "./helpers/objectWithoutProperties.js"
+ },
+ "./helpers/objectWithoutProperties.js"
+ ],
+ "./helpers/esm/objectWithoutProperties": "./helpers/esm/objectWithoutProperties.js",
+ "./helpers/objectWithoutPropertiesLoose": [
+ {
+ "node": "./helpers/objectWithoutPropertiesLoose.js",
+ "import": "./helpers/esm/objectWithoutPropertiesLoose.js",
+ "default": "./helpers/objectWithoutPropertiesLoose.js"
+ },
+ "./helpers/objectWithoutPropertiesLoose.js"
+ ],
+ "./helpers/esm/objectWithoutPropertiesLoose": "./helpers/esm/objectWithoutPropertiesLoose.js",
+ "./helpers/possibleConstructorReturn": [
+ {
+ "node": "./helpers/possibleConstructorReturn.js",
+ "import": "./helpers/esm/possibleConstructorReturn.js",
+ "default": "./helpers/possibleConstructorReturn.js"
+ },
+ "./helpers/possibleConstructorReturn.js"
+ ],
+ "./helpers/esm/possibleConstructorReturn": "./helpers/esm/possibleConstructorReturn.js",
+ "./helpers/readOnlyError": [
+ {
+ "node": "./helpers/readOnlyError.js",
+ "import": "./helpers/esm/readOnlyError.js",
+ "default": "./helpers/readOnlyError.js"
+ },
+ "./helpers/readOnlyError.js"
+ ],
+ "./helpers/esm/readOnlyError": "./helpers/esm/readOnlyError.js",
+ "./helpers/regeneratorRuntime": [
+ {
+ "node": "./helpers/regeneratorRuntime.js",
+ "import": "./helpers/esm/regeneratorRuntime.js",
+ "default": "./helpers/regeneratorRuntime.js"
+ },
+ "./helpers/regeneratorRuntime.js"
+ ],
+ "./helpers/esm/regeneratorRuntime": "./helpers/esm/regeneratorRuntime.js",
+ "./helpers/set": [
+ {
+ "node": "./helpers/set.js",
+ "import": "./helpers/esm/set.js",
+ "default": "./helpers/set.js"
+ },
+ "./helpers/set.js"
+ ],
+ "./helpers/esm/set": "./helpers/esm/set.js",
+ "./helpers/setFunctionName": [
+ {
+ "node": "./helpers/setFunctionName.js",
+ "import": "./helpers/esm/setFunctionName.js",
+ "default": "./helpers/setFunctionName.js"
+ },
+ "./helpers/setFunctionName.js"
+ ],
+ "./helpers/esm/setFunctionName": "./helpers/esm/setFunctionName.js",
+ "./helpers/setPrototypeOf": [
+ {
+ "node": "./helpers/setPrototypeOf.js",
+ "import": "./helpers/esm/setPrototypeOf.js",
+ "default": "./helpers/setPrototypeOf.js"
+ },
+ "./helpers/setPrototypeOf.js"
+ ],
+ "./helpers/esm/setPrototypeOf": "./helpers/esm/setPrototypeOf.js",
+ "./helpers/skipFirstGeneratorNext": [
+ {
+ "node": "./helpers/skipFirstGeneratorNext.js",
+ "import": "./helpers/esm/skipFirstGeneratorNext.js",
+ "default": "./helpers/skipFirstGeneratorNext.js"
+ },
+ "./helpers/skipFirstGeneratorNext.js"
+ ],
+ "./helpers/esm/skipFirstGeneratorNext": "./helpers/esm/skipFirstGeneratorNext.js",
+ "./helpers/slicedToArray": [
+ {
+ "node": "./helpers/slicedToArray.js",
+ "import": "./helpers/esm/slicedToArray.js",
+ "default": "./helpers/slicedToArray.js"
+ },
+ "./helpers/slicedToArray.js"
+ ],
+ "./helpers/esm/slicedToArray": "./helpers/esm/slicedToArray.js",
+ "./helpers/superPropBase": [
+ {
+ "node": "./helpers/superPropBase.js",
+ "import": "./helpers/esm/superPropBase.js",
+ "default": "./helpers/superPropBase.js"
+ },
+ "./helpers/superPropBase.js"
+ ],
+ "./helpers/esm/superPropBase": "./helpers/esm/superPropBase.js",
+ "./helpers/superPropGet": [
+ {
+ "node": "./helpers/superPropGet.js",
+ "import": "./helpers/esm/superPropGet.js",
+ "default": "./helpers/superPropGet.js"
+ },
+ "./helpers/superPropGet.js"
+ ],
+ "./helpers/esm/superPropGet": "./helpers/esm/superPropGet.js",
+ "./helpers/superPropSet": [
+ {
+ "node": "./helpers/superPropSet.js",
+ "import": "./helpers/esm/superPropSet.js",
+ "default": "./helpers/superPropSet.js"
+ },
+ "./helpers/superPropSet.js"
+ ],
+ "./helpers/esm/superPropSet": "./helpers/esm/superPropSet.js",
+ "./helpers/taggedTemplateLiteral": [
+ {
+ "node": "./helpers/taggedTemplateLiteral.js",
+ "import": "./helpers/esm/taggedTemplateLiteral.js",
+ "default": "./helpers/taggedTemplateLiteral.js"
+ },
+ "./helpers/taggedTemplateLiteral.js"
+ ],
+ "./helpers/esm/taggedTemplateLiteral": "./helpers/esm/taggedTemplateLiteral.js",
+ "./helpers/taggedTemplateLiteralLoose": [
+ {
+ "node": "./helpers/taggedTemplateLiteralLoose.js",
+ "import": "./helpers/esm/taggedTemplateLiteralLoose.js",
+ "default": "./helpers/taggedTemplateLiteralLoose.js"
+ },
+ "./helpers/taggedTemplateLiteralLoose.js"
+ ],
+ "./helpers/esm/taggedTemplateLiteralLoose": "./helpers/esm/taggedTemplateLiteralLoose.js",
+ "./helpers/tdz": [
+ {
+ "node": "./helpers/tdz.js",
+ "import": "./helpers/esm/tdz.js",
+ "default": "./helpers/tdz.js"
+ },
+ "./helpers/tdz.js"
+ ],
+ "./helpers/esm/tdz": "./helpers/esm/tdz.js",
+ "./helpers/temporalRef": [
+ {
+ "node": "./helpers/temporalRef.js",
+ "import": "./helpers/esm/temporalRef.js",
+ "default": "./helpers/temporalRef.js"
+ },
+ "./helpers/temporalRef.js"
+ ],
+ "./helpers/esm/temporalRef": "./helpers/esm/temporalRef.js",
+ "./helpers/temporalUndefined": [
+ {
+ "node": "./helpers/temporalUndefined.js",
+ "import": "./helpers/esm/temporalUndefined.js",
+ "default": "./helpers/temporalUndefined.js"
+ },
+ "./helpers/temporalUndefined.js"
+ ],
+ "./helpers/esm/temporalUndefined": "./helpers/esm/temporalUndefined.js",
+ "./helpers/toArray": [
+ {
+ "node": "./helpers/toArray.js",
+ "import": "./helpers/esm/toArray.js",
+ "default": "./helpers/toArray.js"
+ },
+ "./helpers/toArray.js"
+ ],
+ "./helpers/esm/toArray": "./helpers/esm/toArray.js",
+ "./helpers/toConsumableArray": [
+ {
+ "node": "./helpers/toConsumableArray.js",
+ "import": "./helpers/esm/toConsumableArray.js",
+ "default": "./helpers/toConsumableArray.js"
+ },
+ "./helpers/toConsumableArray.js"
+ ],
+ "./helpers/esm/toConsumableArray": "./helpers/esm/toConsumableArray.js",
+ "./helpers/toPrimitive": [
+ {
+ "node": "./helpers/toPrimitive.js",
+ "import": "./helpers/esm/toPrimitive.js",
+ "default": "./helpers/toPrimitive.js"
+ },
+ "./helpers/toPrimitive.js"
+ ],
+ "./helpers/esm/toPrimitive": "./helpers/esm/toPrimitive.js",
+ "./helpers/toPropertyKey": [
+ {
+ "node": "./helpers/toPropertyKey.js",
+ "import": "./helpers/esm/toPropertyKey.js",
+ "default": "./helpers/toPropertyKey.js"
+ },
+ "./helpers/toPropertyKey.js"
+ ],
+ "./helpers/esm/toPropertyKey": "./helpers/esm/toPropertyKey.js",
+ "./helpers/toSetter": [
+ {
+ "node": "./helpers/toSetter.js",
+ "import": "./helpers/esm/toSetter.js",
+ "default": "./helpers/toSetter.js"
+ },
+ "./helpers/toSetter.js"
+ ],
+ "./helpers/esm/toSetter": "./helpers/esm/toSetter.js",
+ "./helpers/tsRewriteRelativeImportExtensions": [
+ {
+ "node": "./helpers/tsRewriteRelativeImportExtensions.js",
+ "import": "./helpers/esm/tsRewriteRelativeImportExtensions.js",
+ "default": "./helpers/tsRewriteRelativeImportExtensions.js"
+ },
+ "./helpers/tsRewriteRelativeImportExtensions.js"
+ ],
+ "./helpers/esm/tsRewriteRelativeImportExtensions": "./helpers/esm/tsRewriteRelativeImportExtensions.js",
+ "./helpers/typeof": [
+ {
+ "node": "./helpers/typeof.js",
+ "import": "./helpers/esm/typeof.js",
+ "default": "./helpers/typeof.js"
+ },
+ "./helpers/typeof.js"
+ ],
+ "./helpers/esm/typeof": "./helpers/esm/typeof.js",
+ "./helpers/unsupportedIterableToArray": [
+ {
+ "node": "./helpers/unsupportedIterableToArray.js",
+ "import": "./helpers/esm/unsupportedIterableToArray.js",
+ "default": "./helpers/unsupportedIterableToArray.js"
+ },
+ "./helpers/unsupportedIterableToArray.js"
+ ],
+ "./helpers/esm/unsupportedIterableToArray": "./helpers/esm/unsupportedIterableToArray.js",
+ "./helpers/usingCtx": [
+ {
+ "node": "./helpers/usingCtx.js",
+ "import": "./helpers/esm/usingCtx.js",
+ "default": "./helpers/usingCtx.js"
+ },
+ "./helpers/usingCtx.js"
+ ],
+ "./helpers/esm/usingCtx": "./helpers/esm/usingCtx.js",
+ "./helpers/wrapAsyncGenerator": [
+ {
+ "node": "./helpers/wrapAsyncGenerator.js",
+ "import": "./helpers/esm/wrapAsyncGenerator.js",
+ "default": "./helpers/wrapAsyncGenerator.js"
+ },
+ "./helpers/wrapAsyncGenerator.js"
+ ],
+ "./helpers/esm/wrapAsyncGenerator": "./helpers/esm/wrapAsyncGenerator.js",
+ "./helpers/wrapNativeSuper": [
+ {
+ "node": "./helpers/wrapNativeSuper.js",
+ "import": "./helpers/esm/wrapNativeSuper.js",
+ "default": "./helpers/wrapNativeSuper.js"
+ },
+ "./helpers/wrapNativeSuper.js"
+ ],
+ "./helpers/esm/wrapNativeSuper": "./helpers/esm/wrapNativeSuper.js",
+ "./helpers/wrapRegExp": [
+ {
+ "node": "./helpers/wrapRegExp.js",
+ "import": "./helpers/esm/wrapRegExp.js",
+ "default": "./helpers/wrapRegExp.js"
+ },
+ "./helpers/wrapRegExp.js"
+ ],
+ "./helpers/esm/wrapRegExp": "./helpers/esm/wrapRegExp.js",
+ "./helpers/writeOnlyError": [
+ {
+ "node": "./helpers/writeOnlyError.js",
+ "import": "./helpers/esm/writeOnlyError.js",
+ "default": "./helpers/writeOnlyError.js"
+ },
+ "./helpers/writeOnlyError.js"
+ ],
+ "./helpers/esm/writeOnlyError": "./helpers/esm/writeOnlyError.js",
+ "./helpers/AwaitValue": [
+ {
+ "node": "./helpers/AwaitValue.js",
+ "import": "./helpers/esm/AwaitValue.js",
+ "default": "./helpers/AwaitValue.js"
+ },
+ "./helpers/AwaitValue.js"
+ ],
+ "./helpers/esm/AwaitValue": "./helpers/esm/AwaitValue.js",
+ "./helpers/applyDecs": [
+ {
+ "node": "./helpers/applyDecs.js",
+ "import": "./helpers/esm/applyDecs.js",
+ "default": "./helpers/applyDecs.js"
+ },
+ "./helpers/applyDecs.js"
+ ],
+ "./helpers/esm/applyDecs": "./helpers/esm/applyDecs.js",
+ "./helpers/applyDecs2203": [
+ {
+ "node": "./helpers/applyDecs2203.js",
+ "import": "./helpers/esm/applyDecs2203.js",
+ "default": "./helpers/applyDecs2203.js"
+ },
+ "./helpers/applyDecs2203.js"
+ ],
+ "./helpers/esm/applyDecs2203": "./helpers/esm/applyDecs2203.js",
+ "./helpers/applyDecs2203R": [
+ {
+ "node": "./helpers/applyDecs2203R.js",
+ "import": "./helpers/esm/applyDecs2203R.js",
+ "default": "./helpers/applyDecs2203R.js"
+ },
+ "./helpers/applyDecs2203R.js"
+ ],
+ "./helpers/esm/applyDecs2203R": "./helpers/esm/applyDecs2203R.js",
+ "./helpers/applyDecs2301": [
+ {
+ "node": "./helpers/applyDecs2301.js",
+ "import": "./helpers/esm/applyDecs2301.js",
+ "default": "./helpers/applyDecs2301.js"
+ },
+ "./helpers/applyDecs2301.js"
+ ],
+ "./helpers/esm/applyDecs2301": "./helpers/esm/applyDecs2301.js",
+ "./helpers/applyDecs2305": [
+ {
+ "node": "./helpers/applyDecs2305.js",
+ "import": "./helpers/esm/applyDecs2305.js",
+ "default": "./helpers/applyDecs2305.js"
+ },
+ "./helpers/applyDecs2305.js"
+ ],
+ "./helpers/esm/applyDecs2305": "./helpers/esm/applyDecs2305.js",
+ "./helpers/classApplyDescriptorDestructureSet": [
+ {
+ "node": "./helpers/classApplyDescriptorDestructureSet.js",
+ "import": "./helpers/esm/classApplyDescriptorDestructureSet.js",
+ "default": "./helpers/classApplyDescriptorDestructureSet.js"
+ },
+ "./helpers/classApplyDescriptorDestructureSet.js"
+ ],
+ "./helpers/esm/classApplyDescriptorDestructureSet": "./helpers/esm/classApplyDescriptorDestructureSet.js",
+ "./helpers/classApplyDescriptorGet": [
+ {
+ "node": "./helpers/classApplyDescriptorGet.js",
+ "import": "./helpers/esm/classApplyDescriptorGet.js",
+ "default": "./helpers/classApplyDescriptorGet.js"
+ },
+ "./helpers/classApplyDescriptorGet.js"
+ ],
+ "./helpers/esm/classApplyDescriptorGet": "./helpers/esm/classApplyDescriptorGet.js",
+ "./helpers/classApplyDescriptorSet": [
+ {
+ "node": "./helpers/classApplyDescriptorSet.js",
+ "import": "./helpers/esm/classApplyDescriptorSet.js",
+ "default": "./helpers/classApplyDescriptorSet.js"
+ },
+ "./helpers/classApplyDescriptorSet.js"
+ ],
+ "./helpers/esm/classApplyDescriptorSet": "./helpers/esm/classApplyDescriptorSet.js",
+ "./helpers/classCheckPrivateStaticAccess": [
+ {
+ "node": "./helpers/classCheckPrivateStaticAccess.js",
+ "import": "./helpers/esm/classCheckPrivateStaticAccess.js",
+ "default": "./helpers/classCheckPrivateStaticAccess.js"
+ },
+ "./helpers/classCheckPrivateStaticAccess.js"
+ ],
+ "./helpers/esm/classCheckPrivateStaticAccess": "./helpers/esm/classCheckPrivateStaticAccess.js",
+ "./helpers/classCheckPrivateStaticFieldDescriptor": [
+ {
+ "node": "./helpers/classCheckPrivateStaticFieldDescriptor.js",
+ "import": "./helpers/esm/classCheckPrivateStaticFieldDescriptor.js",
+ "default": "./helpers/classCheckPrivateStaticFieldDescriptor.js"
+ },
+ "./helpers/classCheckPrivateStaticFieldDescriptor.js"
+ ],
+ "./helpers/esm/classCheckPrivateStaticFieldDescriptor": "./helpers/esm/classCheckPrivateStaticFieldDescriptor.js",
+ "./helpers/classExtractFieldDescriptor": [
+ {
+ "node": "./helpers/classExtractFieldDescriptor.js",
+ "import": "./helpers/esm/classExtractFieldDescriptor.js",
+ "default": "./helpers/classExtractFieldDescriptor.js"
+ },
+ "./helpers/classExtractFieldDescriptor.js"
+ ],
+ "./helpers/esm/classExtractFieldDescriptor": "./helpers/esm/classExtractFieldDescriptor.js",
+ "./helpers/classPrivateFieldDestructureSet": [
+ {
+ "node": "./helpers/classPrivateFieldDestructureSet.js",
+ "import": "./helpers/esm/classPrivateFieldDestructureSet.js",
+ "default": "./helpers/classPrivateFieldDestructureSet.js"
+ },
+ "./helpers/classPrivateFieldDestructureSet.js"
+ ],
+ "./helpers/esm/classPrivateFieldDestructureSet": "./helpers/esm/classPrivateFieldDestructureSet.js",
+ "./helpers/classPrivateFieldGet": [
+ {
+ "node": "./helpers/classPrivateFieldGet.js",
+ "import": "./helpers/esm/classPrivateFieldGet.js",
+ "default": "./helpers/classPrivateFieldGet.js"
+ },
+ "./helpers/classPrivateFieldGet.js"
+ ],
+ "./helpers/esm/classPrivateFieldGet": "./helpers/esm/classPrivateFieldGet.js",
+ "./helpers/classPrivateFieldSet": [
+ {
+ "node": "./helpers/classPrivateFieldSet.js",
+ "import": "./helpers/esm/classPrivateFieldSet.js",
+ "default": "./helpers/classPrivateFieldSet.js"
+ },
+ "./helpers/classPrivateFieldSet.js"
+ ],
+ "./helpers/esm/classPrivateFieldSet": "./helpers/esm/classPrivateFieldSet.js",
+ "./helpers/classPrivateMethodGet": [
+ {
+ "node": "./helpers/classPrivateMethodGet.js",
+ "import": "./helpers/esm/classPrivateMethodGet.js",
+ "default": "./helpers/classPrivateMethodGet.js"
+ },
+ "./helpers/classPrivateMethodGet.js"
+ ],
+ "./helpers/esm/classPrivateMethodGet": "./helpers/esm/classPrivateMethodGet.js",
+ "./helpers/classPrivateMethodSet": [
+ {
+ "node": "./helpers/classPrivateMethodSet.js",
+ "import": "./helpers/esm/classPrivateMethodSet.js",
+ "default": "./helpers/classPrivateMethodSet.js"
+ },
+ "./helpers/classPrivateMethodSet.js"
+ ],
+ "./helpers/esm/classPrivateMethodSet": "./helpers/esm/classPrivateMethodSet.js",
+ "./helpers/classStaticPrivateFieldDestructureSet": [
+ {
+ "node": "./helpers/classStaticPrivateFieldDestructureSet.js",
+ "import": "./helpers/esm/classStaticPrivateFieldDestructureSet.js",
+ "default": "./helpers/classStaticPrivateFieldDestructureSet.js"
+ },
+ "./helpers/classStaticPrivateFieldDestructureSet.js"
+ ],
+ "./helpers/esm/classStaticPrivateFieldDestructureSet": "./helpers/esm/classStaticPrivateFieldDestructureSet.js",
+ "./helpers/classStaticPrivateFieldSpecGet": [
+ {
+ "node": "./helpers/classStaticPrivateFieldSpecGet.js",
+ "import": "./helpers/esm/classStaticPrivateFieldSpecGet.js",
+ "default": "./helpers/classStaticPrivateFieldSpecGet.js"
+ },
+ "./helpers/classStaticPrivateFieldSpecGet.js"
+ ],
+ "./helpers/esm/classStaticPrivateFieldSpecGet": "./helpers/esm/classStaticPrivateFieldSpecGet.js",
+ "./helpers/classStaticPrivateFieldSpecSet": [
+ {
+ "node": "./helpers/classStaticPrivateFieldSpecSet.js",
+ "import": "./helpers/esm/classStaticPrivateFieldSpecSet.js",
+ "default": "./helpers/classStaticPrivateFieldSpecSet.js"
+ },
+ "./helpers/classStaticPrivateFieldSpecSet.js"
+ ],
+ "./helpers/esm/classStaticPrivateFieldSpecSet": "./helpers/esm/classStaticPrivateFieldSpecSet.js",
+ "./helpers/classStaticPrivateMethodSet": [
+ {
+ "node": "./helpers/classStaticPrivateMethodSet.js",
+ "import": "./helpers/esm/classStaticPrivateMethodSet.js",
+ "default": "./helpers/classStaticPrivateMethodSet.js"
+ },
+ "./helpers/classStaticPrivateMethodSet.js"
+ ],
+ "./helpers/esm/classStaticPrivateMethodSet": "./helpers/esm/classStaticPrivateMethodSet.js",
+ "./helpers/defineEnumerableProperties": [
+ {
+ "node": "./helpers/defineEnumerableProperties.js",
+ "import": "./helpers/esm/defineEnumerableProperties.js",
+ "default": "./helpers/defineEnumerableProperties.js"
+ },
+ "./helpers/defineEnumerableProperties.js"
+ ],
+ "./helpers/esm/defineEnumerableProperties": "./helpers/esm/defineEnumerableProperties.js",
+ "./helpers/dispose": [
+ {
+ "node": "./helpers/dispose.js",
+ "import": "./helpers/esm/dispose.js",
+ "default": "./helpers/dispose.js"
+ },
+ "./helpers/dispose.js"
+ ],
+ "./helpers/esm/dispose": "./helpers/esm/dispose.js",
+ "./helpers/objectSpread": [
+ {
+ "node": "./helpers/objectSpread.js",
+ "import": "./helpers/esm/objectSpread.js",
+ "default": "./helpers/objectSpread.js"
+ },
+ "./helpers/objectSpread.js"
+ ],
+ "./helpers/esm/objectSpread": "./helpers/esm/objectSpread.js",
+ "./helpers/using": [
+ {
+ "node": "./helpers/using.js",
+ "import": "./helpers/esm/using.js",
+ "default": "./helpers/using.js"
+ },
+ "./helpers/using.js"
+ ],
+ "./helpers/esm/using": "./helpers/esm/using.js",
+ "./package": "./package.json",
+ "./package.json": "./package.json",
+ "./regenerator": "./regenerator/index.js",
+ "./regenerator/*.js": "./regenerator/*.js",
+ "./regenerator/": "./regenerator/"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "type": "commonjs"
+}
\ No newline at end of file
diff --git a/backend/node_modules/@babel/runtime/regenerator/index.js b/backend/node_modules/@babel/runtime/regenerator/index.js
new file mode 100644
index 0000000..5881357
--- /dev/null
+++ b/backend/node_modules/@babel/runtime/regenerator/index.js
@@ -0,0 +1,15 @@
+// TODO(Babel 8): Remove this file.
+
+var runtime = require("../helpers/regeneratorRuntime")();
+module.exports = runtime;
+
+// Copied from https://github.com/facebook/regenerator/blob/main/packages/runtime/runtime.js#L736=
+try {
+ regeneratorRuntime = runtime;
+} catch (accidentalStrictMode) {
+ if (typeof globalThis === "object") {
+ globalThis.regeneratorRuntime = runtime;
+ } else {
+ Function("r", "regeneratorRuntime = r")(runtime);
+ }
+}
diff --git a/backend/node_modules/@types/d3-array/LICENSE b/backend/node_modules/@types/d3-array/LICENSE
new file mode 100644
index 0000000..9e841e7
--- /dev/null
+++ b/backend/node_modules/@types/d3-array/LICENSE
@@ -0,0 +1,21 @@
+ MIT License
+
+ Copyright (c) Microsoft Corporation.
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE
diff --git a/backend/node_modules/@types/d3-array/README.md b/backend/node_modules/@types/d3-array/README.md
new file mode 100644
index 0000000..20fb00f
--- /dev/null
+++ b/backend/node_modules/@types/d3-array/README.md
@@ -0,0 +1,15 @@
+# Installation
+> `npm install --save @types/d3-array`
+
+# Summary
+This package contains type definitions for d3-array (https://github.com/d3/d3-array).
+
+# Details
+Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/d3-array.
+
+### Additional Details
+ * Last updated: Tue, 07 Nov 2023 15:11:36 GMT
+ * Dependencies: none
+
+# Credits
+These definitions were written by [Alex Ford](https://github.com/gustavderdrache), [Boris Yankov](https://github.com/borisyankov), [Tom Wanzek](https://github.com/tomwanzek), [denisname](https://github.com/denisname), [Hugues Stefanski](https://github.com/ledragon), [Nathan Bierema](https://github.com/Methuselah96), and [Fil](https://github.com/Fil).
diff --git a/backend/node_modules/@types/d3-array/index.d.ts b/backend/node_modules/@types/d3-array/index.d.ts
new file mode 100644
index 0000000..5021041
--- /dev/null
+++ b/backend/node_modules/@types/d3-array/index.d.ts
@@ -0,0 +1,1087 @@
+// Last module patch version validated against: 3.2.4
+
+// --------------------------------------------------------------------------
+// Shared Types and Interfaces
+// --------------------------------------------------------------------------
+
+/**
+ * Administrivia: JavaScript primitive types and Date
+ */
+export type Primitive = number | string | boolean | Date;
+
+/**
+ * Administrivia: anything with a valueOf(): number method is comparable, so we allow it in numeric operations
+ */
+export interface Numeric {
+ valueOf(): number;
+}
+
+/**
+ * Administrivia: a matrix of numeric values.
+ * If height is not specified, it is inferred from the given width and data.length.
+ */
+export interface Matrix {
+ data: ArrayLike;
+ width: number;
+ height?: number;
+}
+
+/**
+ * Represents a nested/recursive InternMap type
+ *
+ * The first generic "TObject" refers to the type of the data object that is available in the accessor functions.
+ * The second generic "TReduce" refers to the type of the data available at the deepest level (the result data).
+ * The third generic "TKeys" refers to the type of the keys at each level of the nestes InternMap.
+ */
+export type NestedInternMap = TKeys extends [infer TFirst, ...infer TRest]
+ ? InternMap>
+ : TReduce;
+
+/**
+ * Represents a nested/recursive Array type
+ *
+ * The first generic "TObject" refers to the type of the data object that is available in the accessor functions.
+ * The second generic "TReduce" refers to the type of the data available at the deepest level (the result data).
+ * The third generic "TKeys" refers to the type of the keys at each level of the nestes Array.
+ */
+export type NestedArray = TKeys extends [infer TFirst, ...infer TRest]
+ ? Array<[TFirst, NestedArray]>
+ : TReduce;
+
+// --------------------------------------------------------------------------------------
+// Statistics
+// --------------------------------------------------------------------------------------
+
+/**
+ * Return the minimum value in the array using natural order.
+ */
+export function min(iterable: Iterable): string | undefined;
+
+/**
+ * Return the minimum value in the array using natural order.
+ */
+export function min(iterable: Iterable): T | undefined;
+/**
+ * Return the minimum value in the array using natural order.
+ */
+export function min(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => string | undefined | null,
+): string | undefined;
+/**
+ * Return the minimum value in the array using natural order.
+ */
+export function min(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => U | undefined | null,
+): U | undefined;
+
+/**
+ * Return the index of the minimum value in the array using natural order.
+ */
+export function minIndex(iterable: Iterable): number;
+/**
+ * Return the index of the minimum value in the array using natural order and a projection function to map values.
+ */
+export function minIndex(
+ iterable: Iterable,
+ accessor: (datum: TDatum, index: number, array: Iterable) => unknown,
+): number;
+/**
+ * Return the index of the minimum value in the array using natural order.
+ */
+export function minIndex(iterable: Iterable): number;
+
+/**
+ * Return the maximum value in the array of strings using natural order.
+ */
+export function max(iterable: Iterable): string | undefined;
+/**
+ * Return the maximum value in the array of numbers using natural order.
+ */
+export function max(iterable: Iterable): T | undefined;
+/**
+ * Return the maximum value in the array using natural order and a projection function to map values to strings.
+ */
+export function max(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => string | undefined | null,
+): string | undefined;
+/**
+ * Return the maximum value in the array using natural order and a projection function to map values to easily-sorted values.
+ */
+export function max(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => U | undefined | null,
+): U | undefined;
+
+/**
+ * Return the index of the maximum value in the array using natural order.
+ */
+export function maxIndex(iterable: Iterable): number;
+/**
+ * Return the index of the maximum value in the array using natural order and a projection function to map values.
+ */
+export function maxIndex(
+ iterable: Iterable,
+ accessor: (datum: TDatum, index: number, array: Iterable) => unknown,
+): number;
+
+/**
+ * Return the min and max simultaneously.
+ */
+export function extent(iterable: Iterable): [string, string] | [undefined, undefined];
+/**
+ * Return the min and max simultaneously.
+ */
+export function extent(iterable: Iterable): [T, T] | [undefined, undefined];
+/**
+ * Return the min and max simultaneously.
+ */
+export function extent(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => string | undefined | null,
+): [string, string] | [undefined, undefined];
+/**
+ * Return the min and max simultaneously.
+ */
+export function extent(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => U | undefined | null,
+): [U, U] | [undefined, undefined];
+
+/**
+ * Returns the mode of the given iterable, i.e. the value which appears the most often.
+ * In case of equality, returns the first of the relevant values.
+ * If the iterable contains no comparable values, returns undefined.
+ * An optional accessor function may be specified, which is equivalent to calling Array.from before computing the mode.
+ * This method ignores undefined, null and NaN values; this is useful for ignoring missing data.
+ */
+export function mode(iterable: Iterable): number;
+/**
+ * Returns the mode of the given iterable, i.e. the value which appears the most often.
+ * In case of equality, returns the first of the relevant values.
+ * If the iterable contains no comparable values, returns undefined.
+ * An optional accessor function may be specified, which is equivalent to calling Array.from before computing the mode.
+ * This method ignores undefined, null and NaN values; this is useful for ignoring missing data.
+ */
+export function mode(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => number | undefined | null,
+): number;
+
+/**
+ * Compute the sum of an array of numbers.
+ */
+export function sum(iterable: Iterable): number;
+/**
+ * Compute the sum of an array, using the given accessor to convert values to numbers.
+ */
+export function sum(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => number | undefined | null,
+): number;
+
+/**
+ * Return the mean of an array of numbers
+ */
+export function mean(iterable: Iterable): number | undefined;
+/**
+ * Return the mean of an array of numbers
+ */
+export function mean(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => number | undefined | null,
+): number | undefined;
+
+/**
+ * Return the median of an array of numbers
+ */
+export function median(iterable: Iterable): number | undefined;
+/**
+ * Return the median of an array of numbers
+ */
+export function median(
+ iterable: Iterable,
+ accessor: (element: T, i: number, array: Iterable) => number | undefined | null,
+): number | undefined;
+
+/**
+ * Like median, but returns the index of the element to the left of the median.
+ */
+export function medianIndex(iterable: Iterable): number;
+/**
+ * Like median, but returns the index of the element to the left of the median.
+ */
+export function medianIndex(
+ iterable: Iterable,
+ accessor: (element: T, i: number, array: Iterable) => number | undefined | null,
+): number;
+
+/**
+ * Returns the cumulative sum of the given iterable of numbers, as a Float64Array of the same length.
+ * If the iterable contains no numbers, returns zeros.
+ * An optional accessor function may be specified, which is equivalent to calling Array.from before computing the cumulative sum.
+ * This method ignores undefined and NaN values; this is useful for ignoring missing data.
+ */
+export function cumsum(iterable: Iterable): Float64Array;
+/**
+ * Returns the cumulative sum of the given iterable of numbers, as a Float64Array of the same length.
+ * If the iterable contains no numbers, returns zeros.
+ * An optional accessor function may be specified, which is equivalent to calling Array.from before computing the cumulative sum.
+ * This method ignores undefined and NaN values; this is useful for ignoring missing data.
+ */
+export function cumsum(
+ iterable: Iterable,
+ accessor: (element: T, i: number, array: Iterable) => number | undefined | null,
+): Float64Array;
+
+/**
+ * Returns the p-quantile of the given iterable of numbers, where p is a number in the range [0, 1].
+ *
+ * An optional accessor function may be specified, which is equivalent to calling array.map(accessor) before computing the quantile.
+ */
+export function quantile(iterable: Iterable, p: number): number | undefined;
+/**
+ * Returns the p-quantile of the given iterable of numbers, where p is a number in the range [0, 1].
+ *
+ * An optional accessor function may be specified, which is equivalent to calling array.map(accessor) before computing the quantile.
+ */
+export function quantile(
+ iterable: Iterable,
+ p: number,
+ accessor: (element: T, i: number, array: Iterable) => number | undefined | null,
+): number | undefined;
+
+/**
+ * Similar to quantile, but returns the index to the left of p.
+ */
+export function quantileIndex(iterable: Iterable, p: number): number;
+/**
+ * Similar to quantile, but returns the index to the left of p.
+ */
+export function quantileIndex(
+ iterable: Iterable,
+ p: number,
+ accessor: (element: T, i: number, array: Iterable) => number | undefined | null,
+): number;
+
+/**
+ * Similar to quantile, but expects the input to be a sorted array of values.
+ * In contrast with quantile, the accessor is only called on the elements needed to compute the quantile.
+ */
+export function quantileSorted(
+ array: Array,
+ p: number,
+): number | undefined;
+/**
+ * Similar to quantile, but expects the input to be a sorted array of values.
+ * In contrast with quantile, the accessor is only called on the elements needed to compute the quantile.
+ */
+export function quantileSorted(
+ array: T[],
+ p: number,
+ accessor: (element: T, i: number, array: T[]) => number | undefined | null,
+): number | undefined;
+
+/**
+ * Returns an array with the rank of each value in the iterable, i.e. the zero-based index of the value when the iterable is sorted.
+ * Nullish values are sorted to the end and ranked NaN.
+ * An optional comparator or accessor function may be specified; the latter is equivalent to calling array.map(accessor) before computing the ranks.
+ * If comparator is not specified, it defaults to ascending.
+ * Ties (equivalent values) all get the same rank, defined as the first time the value is found.
+ */
+export function rank(iterable: Iterable): Float64Array;
+/**
+ * Returns an array with the rank of each value in the iterable, i.e. the zero-based index of the value when the iterable is sorted.
+ * Nullish values are sorted to the end and ranked NaN.
+ * An optional comparator or accessor function may be specified; the latter is equivalent to calling array.map(accessor) before computing the ranks.
+ * If comparator is not specified, it defaults to ascending.
+ * Ties (equivalent values) all get the same rank, defined as the first time the value is found.
+ */
+export function rank(
+ iterable: Iterable,
+ accessorOrComparator:
+ | ((datum: T, index: number, array: Iterable) => number | undefined | null)
+ | ((a: T, b: T) => number | undefined | null),
+): Float64Array;
+
+/**
+ * Returns an unbiased estimator of the population variance of the given iterable of numbers using Welford’s algorithm.
+ * If the iterable has fewer than two numbers, returns undefined.
+ * An optional accessor function may be specified, which is equivalent to calling Array.from before computing the variance.
+ * This method ignores undefined and NaN values; this is useful for ignoring missing data.
+ */
+export function variance(iterable: Iterable): number | undefined;
+/**
+ * Returns an unbiased estimator of the population variance of the given iterable of numbers using Welford’s algorithm.
+ * If the iterable has fewer than two numbers, returns undefined.
+ * An optional accessor function may be specified, which is equivalent to calling Array.from before computing the variance.
+ * This method ignores undefined and NaN values; this is useful for ignoring missing data.
+ */
+export function variance(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => number | undefined | null,
+): number | undefined;
+
+/**
+ * Compute the standard deviation, defined as the square root of the bias-corrected variance, of the given array of numbers.
+ */
+export function deviation(iterable: Iterable): number | undefined;
+/**
+ * Compute the standard deviation, defined as the square root of the bias-corrected variance, of the given array,
+ * using the given accessor to convert values to numbers.
+ */
+export function deviation(
+ iterable: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => number | undefined | null,
+): number | undefined;
+
+/**
+ * Returns a full precision summation of the given values.
+ * Although slower, d3.fsum can replace d3.sum wherever greater precision is needed. Uses d3.Adder.
+ */
+export function fsum(values: Iterable): number;
+/**
+ * Returns a full precision summation of the given values.
+ * Although slower, d3.fsum can replace d3.sum wherever greater precision is needed. Uses d3.Adder.
+ */
+export function fsum(
+ values: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => number | undefined | null,
+): number;
+
+/**
+ * Returns a full precision cumulative sum of the given values.
+ * Although slower, d3.fcumsum can replace d3.cumsum when greater precision is needed. Uses d3.Adder.
+ */
+export function fcumsum(values: Iterable): Float64Array;
+/**
+ * Returns a full precision cumulative sum of the given values.
+ * Although slower, d3.fcumsum can replace d3.cumsum when greater precision is needed. Uses d3.Adder.
+ */
+export function fcumsum(
+ values: Iterable,
+ accessor: (datum: T, index: number, array: Iterable) => number | undefined | null,
+): Float64Array;
+
+export class Adder {
+ /**
+ * Creates a full precision adder for IEEE 754 floating point numbers, setting its initial value to 0.
+ */
+ constructor();
+
+ /**
+ * Adds the specified number to the adder’s current value and returns the adder.
+ */
+ add(number: number): Adder;
+
+ /**
+ * Returns the IEEE 754 double precision representation of the adder’s current value.
+ * Most useful as the short-hand notation +adder.
+ */
+ valueOf(): number;
+}
+
+// --------------------------------------------------------------------------------------
+// Search
+// --------------------------------------------------------------------------------------
+
+/**
+ * Returns the least element of the specified iterable according to the specified comparator.
+ * If comparator is not specified, it defaults to ascending.
+ */
+export function least(iterable: Iterable, comparator?: (a: T, b: T) => number): T | undefined;
+/**
+ * Returns the least element of the specified iterable according to the specified accessor.
+ */
+export function least(iterable: Iterable, accessor: (a: T) => unknown): T | undefined;
+
+/**
+ * Returns the index of the least element of the specified iterable according to the specified comparator.
+ */
+export function leastIndex(iterable: Iterable): number | undefined;
+/**
+ * Returns the index of the least element of the specified iterable according to the specified comparator.
+ */
+export function leastIndex(iterable: Iterable, comparator: (a: T, b: T) => number): number | undefined;
+/**
+ * Returns the index of the least element of the specified iterable according to the specified accessor.
+ */
+// tslint:disable-next-line:unified-signatures
+export function leastIndex(iterable: Iterable, accessor: (a: T) => unknown): number | undefined;
+
+/**
+ * Returns the greatest element of the specified iterable according to the specified comparator or accessor.
+ * If the given iterable contains no comparable elements (i.e., the comparator returns NaN when comparing each element to itself), returns undefined.
+ * If comparator is not specified, it defaults to ascending.
+ */
+export function greatest(iterable: Iterable, comparator?: (a: T, b: T) => number): T | undefined;
+/**
+ * Returns the greatest element of the specified iterable according to the specified comparator or accessor.
+ * If the given iterable contains no comparable elements (i.e., the comparator returns NaN when comparing each element to itself), returns undefined.
+ * If comparator is not specified, it defaults to ascending.
+ */
+export function greatest(iterable: Iterable, accessor: (a: T) => unknown): T | undefined;
+
+/**
+ * Returns the index of the greatest element of the specified iterable according to the specified comparator or accessor.
+ * If the given iterable contains no comparable elements (i.e., the comparator returns NaN when comparing each element to itself), returns -1.
+ * If comparator is not specified, it defaults to ascending.
+ */
+export function greatestIndex(iterable: Iterable): number | undefined;
+/**
+ * Returns the index of the greatest element of the specified iterable according to the specified comparator or accessor.
+ * If the given iterable contains no comparable elements (i.e., the comparator returns NaN when comparing each element to itself), returns -1.
+ * If comparator is not specified, it defaults to ascending.
+ */
+export function greatestIndex(iterable: Iterable, comparator: (a: T, b: T) => number): number | undefined;
+/**
+ * Returns the index of the greatest element of the specified iterable according to the specified comparator or accessor.
+ * If the given iterable contains no comparable elements (i.e., the comparator returns NaN when comparing each element to itself), returns -1.
+ * If comparator is not specified, it defaults to ascending.
+ */
+// tslint:disable-next-line:unified-signatures
+export function greatestIndex(iterable: Iterable, accessor: (a: T) => unknown): number | undefined;
+
+export function bisectLeft(array: ArrayLike, x: number, lo?: number, hi?: number): number;
+export function bisectLeft(array: ArrayLike, x: string, lo?: number, hi?: number): number;
+export function bisectLeft(array: ArrayLike, x: Date, lo?: number, hi?: number): number;
+
+export function bisectRight(array: ArrayLike, x: number, lo?: number, hi?: number): number;
+export function bisectRight(array: ArrayLike, x: string, lo?: number, hi?: number): number;
+export function bisectRight(array: ArrayLike, x: Date, lo?: number, hi?: number): number;
+
+export function bisectCenter(array: ArrayLike, x: number, lo?: number, hi?: number): number;
+export function bisectCenter(array: ArrayLike, x: string, lo?: number, hi?: number): number;
+export function bisectCenter(array: ArrayLike, x: Date, lo?: number, hi?: number): number;
+
+export const bisect: typeof bisectRight;
+
+export interface Bisector {
+ left(array: ArrayLike, x: U, lo?: number, hi?: number): number;
+ right(array: ArrayLike, x: U, lo?: number, hi?: number): number;
+ center(array: ArrayLike, x: U, lo?: number, hi?: number): number;
+}
+
+export function bisector(comparator: (a: T, b: U) => number): Bisector;
+// tslint:disable-next-line:unified-signatures
+export function bisector(accessor: (x: T) => U): Bisector;
+
+/**
+ * Rearranges items so that all items in the [left, k] are the smallest. The k-th element will have the (k - left + 1)-th smallest value in [left, right].
+ *
+ * @param array The array to partially sort (in place).
+ * @param k The middle index for partial sorting.
+ * @param left The left index of the range to sort.
+ * @param right The right index.
+ * @param compare The compare function.
+ */
+export function quickselect(
+ array: ArrayLike,
+ k: number,
+ left?: number,
+ right?: number,
+ compare?: (a: Primitive | undefined, b: Primitive | undefined) => number,
+): T[];
+
+// NB. this is limited to primitive values due to D3's use of the <, >, and >= operators. Results get weird for object instances.
+/**
+ * Compares two primitive values for sorting (in ascending order).
+ */
+export function ascending(a: Primitive | undefined, b: Primitive | undefined): number;
+
+// NB. this is limited to primitive values due to D3's use of the <, >, and >= operators. Results get weird for object instances.
+/**
+ * Compares two primitive values for sorting (in descending order).
+ */
+export function descending(a: Primitive | undefined, b: Primitive | undefined): number;
+
+// --------------------------------------------------------------------------------------
+// Transformations
+// --------------------------------------------------------------------------------------
+
+/**
+ * Groups the specified iterable of values into an InternMap from key to array of value.
+ *
+ * @param iterable The iterable to group.
+ * @param keys The key functions.
+ */
+export function group(
+ iterable: Iterable,
+ ...keys: {
+ [Index in keyof TKeys]: (value: TObject, index: number, values: TObject[]) => TKeys[Index];
+ }
+): NestedInternMap;
+
+/**
+ * Equivalent to group, but returns nested arrays instead of nested maps.
+ *
+ * @param iterable The iterable to group.
+ * @param keys The key functions.
+ */
+export function groups(
+ iterable: Iterable,
+ ...keys: {
+ [Index in keyof TKeys]: (value: TObject, index: number, values: TObject[]) => TKeys[Index];
+ }
+): NestedArray;
+
+/**
+ * Equivalent to group, but returns a flat array of [key0, key1, …, values] instead of nested maps.
+ *
+ * @param iterable The iterable to group.
+ * @param keys The key functions.
+ */
+export function flatGroup(
+ iterable: Iterable,
+ ...keys: {
+ [Index in keyof TKeys]: (value: TObject, index: number, values: TObject[]) => TKeys[Index];
+ }
+): Array<[...TKeys, TObject[]]>;
+
+/**
+ * Equivalent to group but returns a unique value per compound key instead of an array, throwing if the key is not unique.
+ *
+ * @param iterable The iterable to group.
+ * @param key The key functions.
+ */
+export function index(
+ iterable: Iterable,
+ ...keys: {
+ [Index in keyof TKeys]: (value: TObject, index: number, values: TObject[]) => TKeys[Index];
+ }
+): NestedInternMap;
+
+/**
+ * Equivalent to index, but returns nested arrays instead of nested maps.
+ *
+ * @param iterable The iterable to group.
+ * @param keys The key functions.
+ */
+export function indexes(
+ iterable: Iterable,
+ ...keys: {
+ [Index in keyof TKeys]: (value: TObject, index: number, values: TObject[]) => TKeys[Index];
+ }
+): NestedArray;
+
+/**
+ * Groups and reduces the specified array of values into an InternMap from key to value.
+ *
+ * @param iterable The iterable to group.
+ * @param reduce The reduce function.
+ * @param keys The key functions.
+ */
+export function rollup(
+ iterable: Iterable,
+ reduce: (values: TObject[]) => TReduce,
+ ...keys: {
+ [Index in keyof TKeys]: (value: TObject, index: number, values: TObject[]) => TKeys[Index];
+ }
+): NestedInternMap;
+
+/**
+ * Equivalent to rollup, but returns nested arrays instead of nested maps.
+ *
+ * @param iterable The iterable to group.
+ * @param reduce The reduce function.
+ * @param keys The key functions.
+ */
+export function rollups(
+ iterable: Iterable,
+ reduce: (values: TObject[]) => TReduce,
+ ...keys: {
+ [Index in keyof TKeys]: (value: TObject, index: number, values: TObject[]) => TKeys[Index];
+ }
+): NestedArray;
+
+/**
+ * Equivalent to rollup, but returns a flat array of [key0, key1, …, value] instead of nested maps.
+ *
+ * @param iterable The iterable to group.
+ * @param reduce The reduce function.
+ * @param keys The key functions.
+ */
+export function flatRollup(
+ iterable: Iterable,
+ reduce: (values: TObject[]) => TReduce,
+ ...keys: {
+ [Index in keyof TKeys]: (value: TObject, index: number, values: TObject[]) => TKeys[Index];
+ }
+): Array<[...TKeys, TReduce]>;
+
+/**
+ * Groups the specified iterable of elements according to the specified key function, sorts the groups according to the specified comparator, and then returns an array of keys in sorted order.
+ * The comparator will be asked to compare two groups a and b and should return a negative value if a should be before b, a positive value if a should be after b, or zero for a partial ordering.
+ */
+export function groupSort(
+ iterable: Iterable,
+ comparator: (a: TObject[], b: TObject[]) => number,
+ key: (value: TObject) => TKey,
+): TKey[];
+/**
+ * Groups the specified iterable of elements according to the specified key function, sorts the groups according to the specified accessor, and then returns an array of keys in sorted order.
+ */
+export function groupSort(
+ iterable: Iterable,
+ // tslint:disable-next-line:unified-signatures
+ accessor: (value: TObject[]) => unknown,
+ key: (value: TObject) => TKey,
+): TKey[];
+
+/**
+ * Returns the number of valid number values (i.e., not null, NaN, or undefined) in the specified iterable; accepts an accessor.
+ *
+ * @param iterable Input array.
+ */
+export function count(iterable: Iterable): number;
+/**
+ * Returns the number of valid number values (i.e., not null, NaN, or undefined) in the specified iterable; accepts an accessor.
+ *
+ * @param iterable Input array.
+ * @param accessor Accessor method.
+ */
+export function count(
+ iterable: Iterable,
+ accessor: (a: TObject, b: TObject) => number | null | undefined,
+): number;
+
+/**
+ * Returns the Cartesian product of the two arrays a and b.
+ * For each element i in the specified array a and each element j in the specified array b, in order,
+ * it creates a two-element array for each pair.
+ *
+ * @param a First input array.
+ * @param b Second input array.
+ */
+export function cross(a: Iterable, b: Iterable): Array<[S, T]>;
+
+/**
+ * Returns the Cartesian product of the two arrays a and b.
+ * For each element i in the specified array a and each element j in the specified array b, in order,
+ * invokes the specified reducer function passing the element i and element j.
+ *
+ * @param a First input array.
+ * @param b Second input array.
+ * @param reducer A reducer function taking as input an element from "a" and "b" and returning a reduced value.
+ */
+export function cross(a: Iterable, b: Iterable, reducer: (a: S, b: T) => U): U[];
+
+/**
+ * Merges the specified arrays into a single array.
+ */
+export function merge(iterables: Iterable>): T[];
+
+/**
+ * For each adjacent pair of elements in the specified array, returns a new array of tuples of elements i and i - 1.
+ * Returns the empty array if the input array has fewer than two elements.
+ *
+ * @param iterable Array of input elements
+ */
+export function pairs(iterable: Iterable): Array<[T, T]>;
+/**
+ * For each adjacent pair of elements in the specified array, in order, invokes the specified reducer function passing the element i and element i - 1.
+ * Returns the resulting array of pair-wise reduced elements.
+ * Returns the empty array if the input array has fewer than two elements.
+ *
+ * @param iterable Array of input elements
+ * @param reducer A reducer function taking as input to adjacent elements of the input array and returning a reduced value.
+ */
+export function pairs(iterable: Iterable, reducer: (a: T, b: T) => U): U[];
+
+/**
+ * Returns a permutation of the specified source object (or array) using the specified iterable of keys.
+ * The returned array contains the corresponding property of the source object for each key in keys, in order.
+ * For example, `permute(["a", "b", "c"], [1, 2, 0]) // ["b", "c", "a"]`
+ *
+ * It is acceptable to have more keys than source elements, and for keys to be duplicated or omitted.
+ */
+export function permute(source: { [key: number]: T }, keys: Iterable): T[];
+/**
+ * Extract the values from an object into an array with a stable order. For example:
+ * `var object = {yield: 27, year: 1931, site: "University Farm"};`
+ * `d3.permute(object, ["site", "yield"]); // ["University Farm", 27]`
+ */
+export function permute(source: T, keys: Iterable): Array;
+
+/**
+ * Randomizes the order of the specified array using the Fisher–Yates shuffle.
+ */
+export function shuffle(array: T[], lo?: number, hi?: number): T[];
+export function shuffle(array: Int8Array, lo?: number, hi?: number): Int8Array;
+export function shuffle(array: Uint8Array, lo?: number, hi?: number): Uint8Array;
+export function shuffle(array: Uint8ClampedArray, lo?: number, hi?: number): Uint8ClampedArray;
+export function shuffle(array: Int16Array, lo?: number, hi?: number): Int16Array;
+export function shuffle(array: Uint16Array, lo?: number, hi?: number): Uint16Array;
+export function shuffle(array: Int32Array, lo?: number, hi?: number): Int32Array;
+export function shuffle(array: Uint32Array, lo?: number, hi?: number): Uint32Array;
+export function shuffle(array: Float32Array, lo?: number, hi?: number): Float32Array;
+export function shuffle(array: Float64Array, lo?: number, hi?: number): Float64Array;
+
+/**
+ * Returns a shuffle function given the specified random source.
+ */
+export function shuffler(random: () => number): typeof shuffle;
+
+/**
+ * Generate an array of approximately count + 1 uniformly-spaced, nicely-rounded values between start and stop (inclusive).
+ * Each value is a power of ten multiplied by 1, 2 or 5. See also d3.tickIncrement, d3.tickStep and linear.ticks.
+ *
+ * Ticks are inclusive in the sense that they may include the specified start and stop values if (and only if) they are exact,
+ * nicely-rounded values consistent with the inferred step. More formally, each returned tick t satisfies start ≤ t and t ≤ stop.
+ *
+ * @param start Start value for ticks
+ * @param stop Stop value for ticks
+ * @param count count + 1 is the approximate number of ticks to be returned by d3.ticks.
+ */
+export function ticks(start: number, stop: number, count: number): number[];
+
+/**
+ * Returns the difference between adjacent tick values if the same arguments were passed to d3.ticks:
+ * a nicely-rounded value that is a power of ten multiplied by 1, 2 or 5.
+ *
+ * Like d3.tickStep, except requires that start is always less than or equal to stop, and if the tick step for the given start,
+ * stop and count would be less than one, returns the negative inverse tick step instead.
+ *
+ * This method is always guaranteed to return an integer, and is used by d3.ticks to avoid guarantee that the returned tick values
+ * are represented as precisely as possible in IEEE 754 floating point.
+ *
+ * @param start Start value for ticks
+ * @param stop Stop value for ticks
+ * @param count count + 1 is the approximate number of ticks to be returned by d3.ticks.
+ */
+export function tickIncrement(start: number, stop: number, count: number): number;
+
+/**
+ * Returns the difference between adjacent tick values if the same arguments were passed to d3.ticks:
+ * a nicely-rounded value that is a power of ten multiplied by 1, 2 or 5.
+ *
+ * Note that due to the limited precision of IEEE 754 floating point, the returned value may not be exact decimals;
+ * use d3-format to format numbers for human consumption.
+ *
+ * @param start Start value for ticks
+ * @param stop Stop value for ticks
+ * @param count count + 1 is the approximate number of ticks to be returned by d3.ticks.
+ */
+export function tickStep(start: number, stop: number, count: number): number;
+
+/**
+ * Returns a new interval [niceStart, niceStop] covering the given interval [start, stop] and where niceStart and niceStop are guaranteed to align with the corresponding tick step.
+ * Like d3.tickIncrement, this requires that start is less than or equal to stop.
+ *
+ * @param start Start value for ticks
+ * @param stop Stop value for ticks
+ * @param count count + 1 is the approximate number of ticks to be returned by d3.ticks.
+ */
+export function nice(start: number, stop: number, count: number): [number, number];
+
+/**
+ * Generates a 0-based numeric sequence. The output range does not include 'stop'.
+ */
+export function range(stop: number): number[];
+/**
+ * Generates a numeric sequence starting from the given start and stop values. 'step' defaults to 1. The output range does not include 'stop'.
+ */
+// tslint:disable-next-line:unified-signatures
+export function range(start: number, stop: number, step?: number): number[];
+
+/**
+ * Transpose a matrix provided in Array of Arrays format.
+ */
+export function transpose(matrix: ArrayLike>): T[][];
+
+/**
+ * Returns an array of arrays, where the ith array contains the ith element from each of the argument arrays.
+ * The returned array is truncated in length to the shortest array in arrays. If arrays contains only a single array, the returned array
+ * contains one-element arrays. With no arguments, the returned array is empty.
+ */
+export function zip(...arrays: Array>): T[][];
+
+// --------------------------------------------------------------------------------------
+// Blur
+// --------------------------------------------------------------------------------------
+
+/**
+ * Blurs an array of data in-place by applying three iterations of a moving average transform (box filter)
+ * for a fast approximation of a Gaussian kernel of the given radius, a non-negative number.
+ * Returns the given data.
+ */
+export function blur(data: ArrayLike, radius: number): ArrayLike;
+
+/**
+ * Blurs a matrix of the given width and height in-place by applying a horizontal blur of radius rx
+ * and a vertical blur of radius ry (which defaults to rx).
+ * The matrix values data are stored in a flat (one-dimensional) array.
+ * If height is not specified, it is inferred from the given width and data.length.
+ * Returns the blurred matrix {data, width, height}.
+ */
+export function blur2(data: Matrix, rx: number, ry?: number): Matrix;
+
+/**
+ * Blurs the given ImageData in-place, blurring each of the RGBA layers independently by applying an horizontal blur of radius rx
+ * and a vertical blur of radius ry (which defaults to rx).
+ * Returns the blurred ImageData.
+ */
+export function blurImage(imageData: ImageData, rx: number, ry?: number): ImageData;
+
+// --------------------------------------------------------------------------------------
+// Iterables
+// --------------------------------------------------------------------------------------
+
+/**
+ * Returns true if the given test function returns true for every value in the given iterable.
+ * This method returns as soon as test returns a non-truthy value or all values are iterated over.
+ * Equivalent to array.every.
+ */
+export function every(
+ iterable: Iterable,
+ test: (value: T, index: number, iterable: Iterable) => unknown,
+): boolean;
+
+/**
+ * Returns true if the given test function returns true for any value in the given iterable.
+ * This method returns as soon as test returns a truthy value or all values are iterated over.
+ * Equivalent to array.some.
+ */
+export function some(
+ iterable: Iterable,
+ test: (value: T, index: number, iterable: Iterable) => unknown,
+): boolean;
+
+/**
+ * Returns a new array containing the values from iterable, in order, for which the given test function returns true.
+ * Equivalent to array.filter.
+ */
+export function filter(
+ iterable: Iterable,
+ test: (value: T, index: number, iterable: Iterable) => unknown,
+): T[];
+
+/**
+ * Returns a new array containing the mapped values from iterable, in order, as defined by given mapper function.
+ * Equivalent to array.map and Array.from.
+ */
+export function map(iterable: Iterable, mapper: (value: T, index: number, iterable: Iterable) => U): U[];
+
+/**
+ * Returns the reduced value defined by given reducer function, which is repeatedly invoked for each value in iterable, being passed the current reduced value and the next value.
+ * Equivalent to array.reduce.
+ */
+export function reduce(
+ iterable: Iterable,
+ reducer: (previousValue: T, currentValue: T, currentIndex: number, iterable: Iterable) => T,
+ initialValue?: T,
+): T;
+/**
+ * Returns the reduced value defined by given reducer function, which is repeatedly invoked for each value in iterable, being passed the current reduced value and the next value.
+ * Equivalent to array.reduce.
+ */
+export function reduce(
+ iterable: Iterable,
+ reducer: (previousValue: U, currentValue: T, currentIndex: number, iterable: Iterable) => U,
+ initialValue: U,
+): U;
+
+/**
+ * Returns an array containing the values in the given iterable in reverse order.
+ * Equivalent to array.reverse, except that it does not mutate the given iterable.
+ */
+export function reverse(iterable: Iterable): T[];
+
+/**
+ * Returns an array containing the values in the given iterable in the sorted order defined by the given comparator function.
+ * If comparator is not specified, it defaults to d3.ascending.
+ * Equivalent to array.sort, except that it does not mutate the given iterable, and the comparator defaults to natural order instead of lexicographic order.
+ */
+export function sort(iterable: Iterable, comparator?: (a: T, b: T) => number): T[];
+/**
+ * Returns an array containing the values in the given iterable in the sorted order defined by the given accessor function.
+ * This is equivalent to a comparator using natural order.
+ * The accessor is only invoked once per element, and thus may be nondeterministic.
+ * Multiple accessors may be specified to break ties.
+ */
+export function sort(iterable: Iterable, ...accessors: Array<(a: T) => unknown>): T[];
+
+// --------------------------------------------------------------------------------------
+// Sets
+// --------------------------------------------------------------------------------------
+
+/**
+ * Returns a new InternSet containing every value in iterable that is not in any of the others iterables.
+ */
+export function difference(iterable: Iterable, ...others: Array>): InternSet;
+
+/**
+ * Returns a new InternSet containing every (distinct) value that appears in any of the given iterables.
+ * The order of values in the returned set is based on their first occurrence in the given iterables.
+ */
+export function union(...iterables: Array>): InternSet;
+
+/**
+ * Returns a new InternSet containing every (distinct) value that appears in all of the given iterables.
+ * The order of values in the returned set is based on their first occurrence in the given iterables.
+ */
+export function intersection(...iterables: Array>): InternSet;
+
+/**
+ * Returns true if a is a superset of b: if every value in the given iterable b is also in the given iterable a.
+ */
+export function superset(a: Iterable, b: Iterable): boolean;
+
+/**
+ * Returns true if a is a subset of b: if every value in the given iterable a is also in the given iterable b.
+ */
+export function subset(a: Iterable, b: Iterable): boolean;
+
+/**
+ * Returns true if a and b are disjoint: if a and b contain no shared value.
+ */
+export function disjoint(a: Iterable, b: Iterable): boolean;
+
+// --------------------------------------------------------------------------------------
+// Bins
+// --------------------------------------------------------------------------------------
+
+export interface Bin extends Array {
+ x0: Value | undefined;
+ x1: Value | undefined;
+}
+
+/**
+ * Type definition for threshold generator which returns the count of recommended thresholds
+ */
+export type ThresholdCountGenerator = (
+ values: ArrayLike,
+ min: number,
+ max: number,
+) => number;
+
+/**
+ * Type definition for threshold generator which returns an array of recommended numbers thresholds
+ */
+export type ThresholdNumberArrayGenerator = (
+ values: ArrayLike,
+ min: number,
+ max: number,
+) => Value[];
+
+/**
+ * Type definition for threshold generator which returns an array of recommended dates thresholds
+ */
+export type ThresholdDateArrayGenerator = (
+ values: ArrayLike,
+ min: Date,
+ max: Date,
+) => Value[];
+
+export interface HistogramCommon {
+ (data: ArrayLike): Array>;
+
+ value(): (d: Datum, i: number, data: ArrayLike) => Value;
+ value(valueAccessor: (d: Datum, i: number, data: ArrayLike) => Value): this;
+}
+
+export interface HistogramGeneratorDate extends HistogramCommon {
+ domain(): (values: ArrayLike) => [Date, Date];
+ domain(domain: [Date, Date] | ((values: ArrayLike) => [Date, Date])): this;
+
+ thresholds(): ThresholdDateArrayGenerator;
+ /**
+ * Set the array of values to be used as thresholds in determining the bins.
+ *
+ * Any threshold values outside the domain are ignored. The first bin.x0 is always equal to the minimum domain value,
+ * and the last bin.x1 is always equal to the maximum domain value.
+ *
+ * @param thresholds Either an array of threshold values used for binning. The elements must
+ * be of the same type as the materialized values of the histogram.
+ * Or a function which accepts as arguments the array of materialized values, and
+ * optionally the domain minimum and maximum. The function calculates and returns the array of values to be used as
+ * thresholds in determining the bins.
+ */
+ thresholds(thresholds: ArrayLike | ThresholdDateArrayGenerator): this;
+}
+
+export interface HistogramGeneratorNumber
+ extends HistogramCommon