diff --git a/.gitignore b/.gitignore index ff0067e..23c6007 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,7 @@ pokemon_database.db Utilities/venv/ venv/ DBVisualiser/node_modules/ -__pycache__/ \ No newline at end of file +__pycache__/ +ui_feedback.log +logs/qt_log.log +logs/default.log diff --git a/DBEditor/DBEditor.py b/DBEditor/DBEditor.py index f3ecce2..dbf3fd9 100644 --- a/DBEditor/DBEditor.py +++ b/DBEditor/DBEditor.py @@ -3,294 +3,134 @@ from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QH QLabel, QCheckBox, QPushButton, QFormLayout, QListWidgetItem, QSplitter, QTreeWidget, QTreeWidgetItem, QDialog, QDialogButtonBox, QComboBox, QMessageBox, QSpinBox, QMenu, QTabWidget, QTextEdit) -from PyQt6.QtCore import Qt, QSize +from PyQt6.QtCore import Qt, QSize, qInstallMessageHandler, QThread, pyqtSignal from PyQt6.QtGui import QPixmap, QFontMetrics, QColor, QAction import sqlite3 import json import os +import traceback +import time +import pdb +import debugpy # Add the parent directory to the Python path sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) # Now try to import +from db_controller import DBController from pokemon_db_ui import PokemonUI from DataGatherers.update_location_information import process_pokemon_for_location_data from DataGatherers.cache_manager import CacheManager from event_system import event_system -def parse_pfic(pfic): - parts = pfic.split('-') - return tuple(int(part) if part.isdigit() else part for part in parts) +import logging + +class UILogHandler(logging.Handler): + def __init__(self): + super().__init__() + + def emit(self, record): + log_entry = self.format(record) # Format the log message + event_system.emit('update_log_display', log_entry) + +class PokemonFormGatherer(QThread): + progress_signal = pyqtSignal(str) + finished_signal = pyqtSignal() + + def run(self): + cache = CacheManager() + debugpy.debug_this_thread() + from DataGatherers.pokemondb_scraper import retrieve_all_pokemon_forms + retrieve_all_pokemon_forms(cache, progress_callback=self.progress_signal.emit) + self.finished_signal.emit() + +class PokemonHomeStatusUpdater(QThread): + progress_signal = pyqtSignal(str) + finished_signal = pyqtSignal() + + def run(self): + cache = CacheManager() + debugpy.debug_this_thread() + from DataGatherers.update_storable_in_home import update_storable_in_home + update_storable_in_home(cache, progress_callback=self.progress_signal.emit) + self.finished_signal.emit() + +class PokemonEvolutionUpdater(QThread): + progress_signal = pyqtSignal(str) + finished_signal = pyqtSignal() + + def run(self): + time.sleep(0.1) + #pdb.set_trace() + debugpy.debug_this_thread() + cache = CacheManager() + from DataGatherers.Update_evolution_information import update_evolution_chains + update_evolution_chains(cache, progress_callback=self.progress_signal.emit) + self.finished_signal.emit() + +class PokemonEncounterUpdater(QThread): + progress_signal = pyqtSignal(str) + finished_signal = pyqtSignal() + + def run(self): + time.sleep(0.1) + debugpy.debug_this_thread() + cache = CacheManager() + from DataGatherers.update_location_information import update_location_information + update_location_information(cache, progress_callback=self.progress_signal.emit) + self.finished_signal.emit() class DBEditor(QMainWindow): def __init__(self): super().__init__() + self.setup_logging() self.setWindowTitle("Pokémon Database Editor") self.setGeometry(100, 100, 1000, 600) - event_system.add_listener('get_pokemon_data', self.load_pokemon_details) event_system.add_listener('save_changes', self.save_changes) event_system.add_listener('add_new_encounter', self.add_new_encounter) - event_system.add_listener('get_pokemon_list', self.send_pokemon_list) - event_system.add_listener('get_home_storable', self.get_home_storable) - event_system.add_listener('get_evolution_chain', self.get_evolution_chain) - event_system.add_listener('get_evolution_parent', self.get_evolution_parent) + event_system.add_listener('refresh_pokemon_encounters', self.refresh_pokemon_encounters) + event_system.add_listener('gather_pokemon_forms', self.gather_pokemon_forms) + event_system.add_listener('gather_home_storage_info', self.gather_home_storage_info) + event_system.add_listener('gather_evolution_info', self.gather_evolution_info) + event_system.add_listener('gather_encounter_info', self.gather_encounter_info) + event_system.add_listener('reinitialize_database', self.reinitialize_database) self.conn = sqlite3.connect(':memory:', check_same_thread=False) # Use in-memory database for runtime self.cursor = self.conn.cursor() self.init_database() - self.patches = self.load_and_apply_patches() + #self.patches = self.load_and_apply_patches() + self.patches = {} - self.encounter_cache = {} # Add this line self.init_ui() + def init_database(self): - # Create or open the file-based database - disk_conn = sqlite3.connect('pokemon_forms.db') - disk_cursor = disk_conn.cursor() - - # Create tables in the file-based database - self.create_games_table(disk_cursor) - self.create_pokemon_forms_table(disk_cursor) - self.create_pokemon_storage_table(disk_cursor) - self.create_evolution_chains_table(disk_cursor) - self.create_exclusive_encounter_groups_table(disk_cursor) - self.create_encounters_table(disk_cursor) - self.create_mark_table(disk_cursor) - - # Commit changes to the file-based database - disk_conn.commit() - - # Copy the file-based database to the in-memory database - disk_conn.backup(self.conn) - - # Close the file-based database connection - disk_conn.close() - - # Create tables in the in-memory database (in case they weren't copied) - self.create_pokemon_forms_table(self.cursor) - self.create_pokemon_storage_table(self.cursor) - self.create_evolution_chains_table(self.cursor) - self.create_exclusive_encounter_groups_table(self.cursor) - self.create_encounters_table(self.cursor) - - # Commit changes to the in-memory database - self.conn.commit() + self.db_controller = DBController() + self.db_controller.init_database() - def create_pokemon_forms_table(self, cursor): - cursor.execute(''' - CREATE TABLE IF NOT EXISTS pokemon_forms ( - PFIC TEXT PRIMARY KEY, - name TEXT NOT NULL, - form_name TEXT, - national_dex INTEGER NOT NULL, - generation INTEGER NOT NULL, - is_baby_form BOOLEAN - ) - ''') - - def create_pokemon_storage_table(self, cursor): - cursor.execute(''' - CREATE TABLE IF NOT EXISTS pokemon_storage ( - PFIC TEXT PRIMARY KEY, - storable_in_home BOOLEAN NOT NULL, - FOREIGN KEY (PFIC) REFERENCES pokemon_forms (PFIC) - ) - ''') - - def create_evolution_chains_table(self, cursor): - cursor.execute(''' - CREATE TABLE IF NOT EXISTS evolution_chains ( - from_pfic TEXT, - to_pfic TEXT, - method TEXT, - PRIMARY KEY (from_pfic, to_pfic), - FOREIGN KEY (from_pfic) REFERENCES pokemon_forms (PFIC), - FOREIGN KEY (to_pfic) REFERENCES pokemon_forms (PFIC) - ) - ''') - - def create_exclusive_encounter_groups_table(self, cursor): - cursor.execute(''' - CREATE TABLE IF NOT EXISTS exclusive_encounter_groups ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - group_name TEXT NOT NULL, - description TEXT - ) - ''') - - def create_encounters_table(self, cursor): - # First, check if the table exists - cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='encounters'") - table_exists = cursor.fetchone() is not None - - if not table_exists: - # If the table doesn't exist, create it with all columns - cursor.execute(''' - CREATE TABLE encounters ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - pfic TEXT, - game TEXT, - location TEXT, - day TEXT, - time TEXT, - dual_slot TEXT, - static_encounter BOOLEAN, - static_encounter_count INTEGER, - extra_text TEXT, - stars TEXT, - fishing BOOLEAN, - rods TEXT, - exclusive_group_id INTEGER, - FOREIGN KEY (pfic) REFERENCES pokemon_forms (PFIC), - FOREIGN KEY (exclusive_group_id) REFERENCES exclusive_encounter_groups (id) - ) - ''') - else: - # If the table exists, check if the exclusive_group_id column exists - cursor.execute("PRAGMA table_info(encounters)") - columns = [column[1] for column in cursor.fetchall()] - - if 'exclusive_group_id' not in columns: - # If the column doesn't exist, add it - cursor.execute(''' - ALTER TABLE encounters - ADD COLUMN exclusive_group_id INTEGER - REFERENCES exclusive_encounter_groups (id) - ''') - - if 'starter' not in columns: - # If the column doesn't exist, add it - cursor.execute(''' - ALTER TABLE encounters - ADD COLUMN starter BOOLEAN - ''') - - def create_mark_table(self, cursor): - - cursor.execute(''' - CREATE TABLE IF NOT EXISTS marks ( - id INTEGER PRIMARY KEY, - name TEXT NOT NULL, - icon_path TEXT NOT NULL - ) - ''') - - cursor.execute(''' - CREATE TABLE IF NOT EXISTS mark_game_associations ( - mark_id INTEGER, - game_id INTEGER, - FOREIGN KEY (mark_id) REFERENCES marks (id), - FOREIGN KEY (game_id) REFERENCES games (id), - PRIMARY KEY (mark_id, game_id) - ) - ''') - - marks = [ - ("Game Boy", "images/marks/GB_icon_HOME.png", ["Red", "Blue", "Yellow", "Gold", "Silver", "Crystal", "Ruby", "Sapphire", "Emerald", "FireRed", "LeafGreen"]), - ("Kalos", "images/marks/Blue_pentagon_HOME.png", ["X", "Y", "Omega Ruby", "Alpha Sapphire"]), - ("Alola", "images/marks/Black_clover_HOME.png", ["Sun", "Moon", "Ultra Sun", "Ultra Moon"]), - ("Let's Go", "images/marks/Let's_Go_icon_HOME.png", ["Let's Go Pikachu", "Let's Go Eevee"]), - ("Galar", "images/marks/Galar_symbol_HOME.png", ["Sword", "Shield"]), - ("Sinnoh", "images/marks/BDSP_icon_HOME.png", ["Brilliant Diamond", "Shining Pearl"]), - ("Hisui", "images/marks/Arceus_mark_HOME.png", ["Legends Arceus"]), - ("Paldea", "images/marks/Paldea_icon_HOME.png", ["Scarlet", "Violet"]), - ] - - for mark in marks: - cursor.execute(''' - INSERT OR IGNORE INTO marks (name, icon_path) - VALUES (?, ?) - ''', (mark[0], mark[1])) - - mark_id = cursor.lastrowid - - for game_name in mark[2]: - cursor.execute(''' - INSERT OR IGNORE INTO mark_game_associations (mark_id, game_id) - SELECT ?, id FROM games WHERE name = ? - ''', (mark_id, game_name)) - - def create_games_table(self, cursor): - - cursor.execute(''' - CREATE TABLE IF NOT EXISTS games ( - id INTEGER PRIMARY KEY, - name TEXT NOT NULL, - generation INTEGER NOT NULL - ) - ''') - - cursor.execute(''' - CREATE TABLE IF NOT EXISTS alternate_game_names ( - id INTEGER PRIMARY KEY, - game_id INTEGER NOT NULL, - alternate_name TEXT NOT NULL, - FOREIGN KEY (game_id) REFERENCES games (id), - UNIQUE (alternate_name COLLATE NOCASE) - ) - ''') - - games = [ - ("Red", 1, ["Red Version"]), - ("Blue", 1, ["Blue Version"]), - ("Yellow", 1, ["Yellow Version"]), - ("Gold", 2, ["Gold Version"]), - ("Silver", 2, ["Silver Version"]), - ("Crystal", 2, ["Crystal Version"]), - ("Ruby", 3, ["Ruby Version"]), - ("Sapphire", 3, ["Sapphire Version"]), - ("Emerald", 3, ["Emerald Version"]), - ("FireRed", 3, ["Fire Red", "Fire-Red"]), - ("LeafGreen", 3, ["Leaf Green", "Leaf-Green"]), - ("Diamond", 4, ["Diamond Version"]), - ("Pearl", 4, ["Pearl Version"]), - ("Platinum", 4, ["Platinum Version"]), - ("HeartGold", 4, ["Heart Gold", "Heart-Gold"]), - ("SoulSilver", 4, ["Soul Silver", "Soul-Silver"]), - ("Black", 5, ["Black Version"]), - ("White", 5, ["White Version"]), - ("Black 2", 5, ["Black Version 2", "Black-2"]), - ("White 2", 5, ["White Version 2", "White-2"]), - ("X", 6, ["X Version"]), - ("Y", 6, ["Y Version"]), - ("Omega Ruby", 6, ["Omega Ruby Version", "Omega-Ruby"]), - ("Alpha Sapphire", 6, ["Alpha Sapphire Version", "Alpha-Sapphire"]), - ("Sun", 7, ["Sun Version"]), - ("Moon", 7, ["Moon Version"]), - ("Ultra Sun", 7, ["Ultra Sun Version", "Ultra-Sun"]), - ("Ultra Moon", 7, ["Ultra Moon Version", "Ultra-Moon"]), - ("Let's Go Pikachu", 7, ["Let's Go, Pikachu!", "Lets Go Pikachu"]), - ("Let's Go Eevee", 7, ["Let's Go, Eevee!", "Lets Go Eevee"]), - ("Sword", 8, ["Sword Version"]), - ("Shield", 8, ["Shield Version"]), - ("Expansion Pass", 8, ["Expansion Pass (Sword)", "Expansion Pass (Shield)"]), - ("Brilliant Diamond", 8, ["Brilliant Diamond Version", "Brilliant-Diamond"]), - ("Shining Pearl", 8, ["Shining Pearl Version", "Shining-Pearl"]), - ("Legends Arceus", 8, ["Legends: Arceus", "Legends-Arceus"]), - ("Scarlet", 9, ["Scarlet Version"]), - ("Violet", 9, ["Violet Version"]), - ("The Teal Mask", 9, ["The Teal Mask Version", "The Teal Mask (Scarlet)", "The Teal Mask (Violet)"]), - ("The Hidden Treasure of Area Zero", 9, ["The Hidden Treasure of Area Zero Version", "The Hidden Treasure of Area Zero (Scarlet)", "The Hidden Treasure of Area Zero (Violet)"]), - - ("Pokémon Home", 98, ["Pokémon HOME"]), - ("Pokémon Go", 99, ["Pokémon GO"]), - ] - - for game in games: - cursor.execute(''' - INSERT OR IGNORE INTO games (name, generation) - VALUES (?, ?) - ''', (game[0], game[1])) - - game_id = cursor.lastrowid - - # Insert alternate names - for alt_name in game[2]: - cursor.execute(''' - INSERT OR IGNORE INTO alternate_game_names (game_id, alternate_name) - VALUES (?, ?) - ''', (game_id, alt_name)) + def setup_logging(self): + # Create the logger with the name 'ui_feedback' + self.logger = logging.getLogger('ui_feedback') + self.logger.setLevel(logging.DEBUG) # Set the logging level + + # Create handlers + console_handler = logging.StreamHandler() # Log to the console + file_handler = logging.FileHandler('ui_feedback.log') # Log to a file + ui_handler = UILogHandler() + + # Create formatters and add them to handlers + formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + console_handler.setFormatter(formatter) + file_handler.setFormatter(formatter) + ui_handler.setFormatter(formatter) + + # Add the handler to the logger + self.logger.addHandler(ui_handler) + + # Add handlers to the logger + self.logger.addHandler(console_handler) + self.logger.addHandler(file_handler) def load_and_apply_patches(self): try: @@ -333,16 +173,6 @@ class DBEditor(QMainWindow): with open('patches.json', 'w') as f: json.dump(self.patches, f) - def load_pokemon_details(self, pfic): - self.cursor.execute(''' - SELECT pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home - FROM pokemon_forms pf - LEFT JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC - WHERE pf.PFIC = ? - ''', (pfic,)) - - return self.cursor.fetchone() - def save_changes(self, data): # Your existing code to save changes pass @@ -351,18 +181,6 @@ class DBEditor(QMainWindow): # Your existing code to add a new encounter pass - def send_pokemon_list(self, callback): - # Fetch pokemon list from database - self.cursor.execute(''' - SELECT pf.PFIC, pf.name, pf.form_name, pf.national_dex - FROM pokemon_forms pf - ''') - pokemon_data = self.cursor.fetchall() - - # Sort the pokemon_data based on PFIC - pokemon_data.sort(key=lambda x: parse_pfic(x[0])) - callback(pokemon_data) - def init_ui(self): # Create a central widget for the main window central_widget = QWidget() @@ -373,12 +191,6 @@ class DBEditor(QMainWindow): self.pokemon_ui = PokemonUI(self) main_layout.addWidget(self.pokemon_ui) - def get_home_storable(self, pfic): - self.cursor.execute('SELECT storable_in_home FROM pokemon_storage WHERE PFIC = ?', (pfic,)) - result = self.cursor.fetchone() - home_storable = result[0] if result else False - return home_storable - def update_home_storable(self): if hasattr(self, 'current_pfic'): storable_in_home = self.home_checkbox.isChecked() @@ -440,131 +252,10 @@ class DBEditor(QMainWindow): # Refresh the evolution chain display # self.load_evolution_chain(self.current_pfic) - - def get_evolution_chain(self, pfic): - def follow_chain(start_pfic, visited=None): - if visited is None: - visited = set() - - chain = [] - stack = [(start_pfic, None)] - - while stack: - current_pfic, method = stack.pop() - if current_pfic in visited: - continue - - visited.add(current_pfic) - self.cursor.execute('SELECT name, form_name FROM pokemon_forms WHERE PFIC = ?', (current_pfic,)) - name, form_name = self.cursor.fetchone() - - chain.append((current_pfic, name, form_name, method)) - - # Get previous evolutions - self.cursor.execute('SELECT from_pfic, method FROM evolution_chains WHERE to_pfic = ?', (current_pfic,)) - prev_evolutions = self.cursor.fetchall() - for prev_pfic, prev_method in prev_evolutions: - if prev_pfic not in visited: - stack.append((prev_pfic, prev_method)) - - # Get next evolutions - self.cursor.execute('SELECT to_pfic, method FROM evolution_chains WHERE from_pfic = ?', (current_pfic,)) - next_evolutions = self.cursor.fetchall() - for next_pfic, next_method in next_evolutions: - if next_pfic not in visited: - stack.append((next_pfic, next_method)) - - return chain - - return follow_chain(pfic) - def get_evolution_parent(self, pfic): - self.cursor.execute('SELECT from_pfic FROM evolution_chains WHERE to_pfic = ?', (pfic,)) - return self.cursor.fetchone() - def closeEvent(self, event): self.conn.close() - event.accept() - - def load_encounter_locations(self, pfic): - self.locations_tree.clear() - self.cursor.execute(''' - SELECT game, location, day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, rods, fishing - FROM encounters - WHERE pfic = ? - ORDER BY game, location - ''', (pfic,)) - encounters = self.cursor.fetchall() - - game_items = {} - for encounter in encounters: - game, location, day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, rods, fishing = encounter - - if game not in game_items: - game_item = QTreeWidgetItem([game]) - game_items[game] = game_item - # Use generation for sorting, default to 0 if not found - game_item.setData(0, Qt.ItemDataRole.UserRole, self.game_generations.get(game, 0)) - - location_item = QTreeWidgetItem([location]) - details = [] - if day: - details.append(f"Day: {day}") - if time: - details.append(f"Time: {time}") - if dual_slot: - details.append(f"Dual Slot: {dual_slot}") - if static_encounter: - details.append(f"Static Encounter (Count: {static_encounter_count})") - if extra_text: - details.append(f"Extra: {extra_text}") - if stars: - details.append(f"Stars: {stars}") - if fishing: - details.append(f"Fishing") - if rods: - details.append(f"Rods: {rods}") - - location_item.setText(1, ", ".join(details)) - game_items[game].addChild(location_item) - - # Sort game items by generation and add them to the tree - sorted_game_items = sorted(game_items.values(), key=lambda x: x.data(0, Qt.ItemDataRole.UserRole)) - self.locations_tree.addTopLevelItems(sorted_game_items) - self.locations_tree.expandAll() - - # Update the cache for this Pokémon - self.encounter_cache[pfic] = len(encounters) > 0 - - # After updating the locations tree - self.update_pokemon_list_highlights() - - # Add this as a class attribute in the DBEditor class - game_generations = { - "Red": 1, "Blue": 1, "Yellow": 1, - "Gold": 2, "Silver": 2, "Crystal": 2, - "Ruby": 3, "Sapphire": 3, "Emerald": 3, "FireRed": 3, "LeafGreen": 3, - "Diamond": 4, "Pearl": 4, "Platinum": 4, "HeartGold": 4, "SoulSilver": 4, - "Black": 5, "White": 5, "Black 2": 5, "White 2": 5, - "X": 6, "Y": 6, "Omega Ruby": 6, "Alpha Sapphire": 6, - "Sun": 7, "Moon": 7, "Ultra Sun": 7, "Ultra Moon": 7, - "Sword": 8, "Shield": 8, "Brilliant Diamond": 8, "Shining Pearl": 8, "Expansion Pass": 8, - "Legends: Arceus": 8, - "Scarlet": 9, "Violet": 9, "The Teal Mask": 9, "The Hidden Treasure of Area Zero": 9, "The Hidden Treasure of Area Zero (Scarlet)": 9, "The Hidden Treasure of Area Zero (Violet)": 9, "The Teal Mask (Scarlet)": 9, "The Teal Mask (Violet)": 9, - "Pokémon Go": 0, "Pokémon Home": 0 - } - - def update_encounter_cache(self): - self.cursor.execute(''' - SELECT DISTINCT pfic - FROM encounters - ''') - pokemon_with_encounters = set(row[0] for row in self.cursor.fetchall()) - - #for i in range(self.pokemon_list.count()): - # item = self.pokemon_list.item(i) - # pfic = item.data(Qt.ItemDataRole.UserRole) - # self.encounter_cache[pfic] = pfic in pokemon_with_encounters + event.accept() def check_pokemon_has_encounters(self, pfic): return self.encounter_cache.get(pfic, False) @@ -606,16 +297,24 @@ class DBEditor(QMainWindow): name_edit = QLineEdit() description_edit = QLineEdit() + game_combo = QComboBox() layout.addRow("Group Name:", name_edit) layout.addRow("Description:", description_edit) + layout.addRow("Game:", game_combo) + + # Populate game combo box + self.cursor.execute('SELECT id, name FROM games ORDER BY name') + for game_id, game_name in self.cursor.fetchall(): + game_combo.addItem(game_name, game_id) if item: group_id = item.data(Qt.ItemDataRole.UserRole) - self.cursor.execute('SELECT group_name, description FROM exclusive_encounter_groups WHERE id = ?', (group_id,)) - group_name, description = self.cursor.fetchone() + self.cursor.execute('SELECT group_name, description, game_id FROM exclusive_encounter_groups WHERE id = ?', (group_id,)) + group_name, description, game_id = self.cursor.fetchone() name_edit.setText(group_name) description_edit.setText(description) + game_combo.setCurrentIndex(game_combo.findData(game_id)) buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) buttons.accepted.connect(dialog.accept) @@ -625,13 +324,14 @@ class DBEditor(QMainWindow): if dialog.exec() == QDialog.DialogCode.Accepted: name = name_edit.text() description = description_edit.text() + game_id = game_combo.currentData() if item: - self.cursor.execute('UPDATE exclusive_encounter_groups SET group_name = ?, description = ? WHERE id = ?', (name, description, group_id)) - item.setText(f"{name} - {description}") + self.cursor.execute('UPDATE exclusive_encounter_groups SET group_name = ?, description = ?, game_id = ? WHERE id = ?', (name, description, game_id, group_id)) + item.setText(f"{name} - {description} ({game_combo.currentText()})") else: - self.cursor.execute('INSERT INTO exclusive_encounter_groups (group_name, description) VALUES (?, ?)', (name, description)) + self.cursor.execute('INSERT INTO exclusive_encounter_groups (group_name, description, game_id) VALUES (?, ?, ?)', (name, description, game_id)) group_id = self.cursor.lastrowid - new_item = QListWidgetItem(f"{name} - {description}") + new_item = QListWidgetItem(f"{name} - {description} ({game_combo.currentText()})") new_item.setData(Qt.ItemDataRole.UserRole, group_id) group_list.addItem(new_item) self.conn.commit() @@ -646,35 +346,15 @@ class DBEditor(QMainWindow): self.conn.commit() group_list.takeItem(group_list.row(item)) - def show_pokemon_context_menu(self, position): - item = self.pokemon_list.itemAt(position) - if item is not None: - context_menu = QMenu(self) - refresh_action = QAction("Refresh Encounters", self) - refresh_action.triggered.connect(lambda: self.refresh_pokemon_encounters(item)) - context_menu.addAction(refresh_action) - context_menu.exec(self.pokemon_list.viewport().mapToGlobal(position)) - - def refresh_pokemon_encounters(self, item): - pfic = item.data(Qt.ItemDataRole.UserRole) - self.cursor.execute(''' - SELECT name, form_name, national_dex - FROM pokemon_forms - WHERE PFIC = ? - ''', (pfic,)) - pokemon_data = self.cursor.fetchone() + def refresh_pokemon_encounters(self, pfic): + pokemon_data = event_system.call_sync('get_pokemon_data', pfic) + if pokemon_data: - name, form, national_dex = pokemon_data - - # Import the necessary function and classes - #from DataGatherers.update_location_information import process_pokemon_for_location_data - - import json + name, form_name, national_dex, generation, storable_in_home, is_baby_form = pokemon_data # Create a temporary connection for this operation temp_conn = sqlite3.connect('pokemon_forms.db') - - # Load default forms + try: with open('./DataGatherers/DefaultForms.json', 'r') as f: default_forms = json.load(f) @@ -684,73 +364,98 @@ class DBEditor(QMainWindow): # Create a cache manager instance cache = CacheManager() - # Delete existing encounters for this Pokémon - self.cursor.execute('DELETE FROM encounters WHERE pfic = ?', (pfic,)) - self.conn.commit() + event_system.emit_sync('clear_encounters_for_pokemon', pfic) # Process the Pokémon data - process_pokemon_for_location_data(pfic, name, form, national_dex, default_forms, cache, temp_conn) + process_pokemon_for_location_data(pfic, name, form_name, national_dex, default_forms, cache, temp_conn) - temp_conn.backup(self.conn) + event_system.emit_sync('refresh_in_memory_db', temp_conn) # Close the temporary connection temp_conn.close() - # Refresh the encounter locations in the UI - self.load_encounter_locations(pfic) - - # Update the encounter cache and highlights - self.update_encounter_cache() - self.update_pokemon_list_highlights() - - print(f"Refreshed encounters for {name} {form if form else ''}") - - def gather_pokemon_forms(self): - self.progress_text.clear() # Clear previous progress text - self.progress_text.append("Starting to gather Pokémon forms...") - # Implement the logic to gather Pokémon forms - # Update progress as you go, for example: - self.progress_text.append("Processed 100 Pokémon...") - self.progress_text.append("Processed 200 Pokémon...") - # ... - self.progress_text.append("Finished gathering Pokémon forms.") - - def gather_home_storage_info(self): - self.progress_text.clear() - self.progress_text.append("Starting to gather Home storage information...") - # Implement the logic - # ... - - def gather_evolution_info(self): - self.progress_text.clear() - self.progress_text.append("Starting to gather evolution information...") - # Implement the logic - # ... - - def gather_encounter_info(self): - self.progress_text.clear() - self.progress_text.append("Starting to gather encounter information...") - # Implement the logic - # ... - - def reinitialize_database(self): + event_system.emit_sync('refresh_pokemon_details_panel', pfic) + + print(f"Refreshed encounters for {name} {form_name if form_name else ''}") + + def gather_pokemon_forms(self, data): + event_system.emit_sync('clear_log_display') + self.logger.info("Starting to gather Pokémon forms...") + + self.form_gatherer = PokemonFormGatherer() + self.form_gatherer.progress_signal.connect(self.update_progress) + self.form_gatherer.finished_signal.connect(self.gathering_finished) + self.form_gatherer.start() + + def update_progress(self, message): + self.logger.info(message) + + def gathering_finished(self): + self.logger.info("Finished gathering Pokémon forms.") + + def gather_home_storage_info(self, data): + event_system.emit_sync('clear_log_display') + self.logger.info("Starting to gather Home storage information...") + self.home_storage_updater = PokemonHomeStatusUpdater() + self.home_storage_updater.progress_signal.connect(self.update_progress) + self.home_storage_updater.finished_signal.connect(self.updating_home_storage_finished) + self.home_storage_updater.start() + + def updating_home_storage_finished(self): + self.logger.info("Finished updating Home storage information.") + + def gather_evolution_info(self, data): + event_system.call_sync('clear_log_display') + self.logger.info("Starting to gather evolution information...") + self.evolution_updater = PokemonEvolutionUpdater() + self.evolution_updater.progress_signal.connect(self.update_progress) + self.evolution_updater.finished_signal.connect(self.updating_evolution_info_finished) + self.evolution_updater.start() + + def updating_evolution_info_finished(self): + self.logger.info("Finished updating evolution information.") + + + def gather_encounter_info(self, data): + event_system.call_sync('clear_log_display') + self.logger.info("Starting to gather encounter information...") + self.encounter_updater = PokemonEncounterUpdater() + self.encounter_updater.progress_signal.connect(self.update_progress) + self.encounter_updater.finished_signal.connect(self.updating_encounter_info_finished) + self.encounter_updater.start() + + def updating_encounter_info_finished(self): + self.logger.info("Finished updating encounter information.") + + def reinitialize_database(self, data): reply = QMessageBox.question(self, 'Confirm Action', 'Are you sure you want to clear and reinitialize the database? This action cannot be undone.', QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No) if reply == QMessageBox.StandardButton.Yes: - self.progress_text.clear() - self.progress_text.append("Starting database reinitialization...") + self.logger.info("Starting database reinitialization...") # Implement the logic to clear and reinitialize the database self.conn.close() os.remove('pokemon_forms.db') # Remove the existing database file self.conn = sqlite3.connect('pokemon_forms.db') self.cursor = self.conn.cursor() self.init_database() # Reinitialize the database structure - self.progress_text.append("Database reinitialized successfully.") + self.logger.info("Database reinitialized successfully.") QMessageBox.information(self, 'Database Reinitialized', 'The database has been cleared and reinitialized.') + + +def qt_message_handler(mode, context, message): + print(f"Qt Message: {mode} {context} {message}") + +def exception_hook(exctype, value, tb): + print(''.join(traceback.format_exception(exctype, value, tb))) + sys.exit(1) + +sys.excepthook = exception_hook + if __name__ == '__main__': app = QApplication(sys.argv) + qInstallMessageHandler(qt_message_handler) editor = DBEditor() editor.show() - sys.exit(app.exec()) \ No newline at end of file + sys.exit(app.exec()) diff --git a/DBEditor/db_controller.py b/DBEditor/db_controller.py new file mode 100644 index 0000000..09831f2 --- /dev/null +++ b/DBEditor/db_controller.py @@ -0,0 +1,382 @@ +import sqlite3 +import sys +import os + +from event_system import event_system + +def parse_pfic(pfic): + parts = pfic.split('-') + return tuple(int(part) if part.isdigit() else part for part in parts) + +class DBController: + def __init__(self): + self.conn = sqlite3.connect(':memory:', check_same_thread=False) # Use in-memory database for runtime + self.cursor = self.conn.cursor() + + event_system.add_listener('get_pokemon_data', self.load_pokemon_details) + event_system.add_listener('get_pokemon_list', self.send_pokemon_list) + event_system.add_listener('get_home_storable', self.get_home_storable) + event_system.add_listener('get_evolution_chain', self.get_evolution_chain) + event_system.add_listener('get_evolution_parent', self.get_evolution_parent) + event_system.add_listener('get_encounter_locations', self.get_encounter_locations) + event_system.add_listener('get_game_generation', self.get_game_generation) + event_system.add_listener('get_pokemon_with_encounters', self.get_pokemon_with_encounters) + event_system.add_listener('refresh_in_memory_db', self.refresh_in_memory_db) + event_system.add_listener('clear_encounters_for_pokemon', self.clear_encounters_for_pokemon) + event_system.add_listener('get_game_id_for_name', self.get_game_id_for_name) + + def init_database(self): + disk_conn = sqlite3.connect('pokemon_forms.db') + disk_cursor = disk_conn.cursor() + + # Create tables in the file-based database + self.create_games_table(disk_cursor) + self.create_pokemon_forms_table(disk_cursor) + self.create_pokemon_storage_table(disk_cursor) + self.create_evolution_chains_table(disk_cursor) + self.create_exclusive_encounter_groups_table(disk_cursor) + self.create_encounters_table(disk_cursor) + self.create_mark_table(disk_cursor) + + # Commit changes to the file-based database + disk_conn.commit() + + # Copy the file-based database to the in-memory database + disk_conn.backup(self.conn) + + # Close the file-based database connection + disk_conn.close() + + def create_pokemon_forms_table(self, cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS pokemon_forms ( + PFIC TEXT PRIMARY KEY, + name TEXT NOT NULL, + form_name TEXT, + national_dex INTEGER NOT NULL, + generation INTEGER NOT NULL, + is_baby_form BOOLEAN + ) + ''') + + def create_pokemon_storage_table(self, cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS pokemon_storage ( + PFIC TEXT PRIMARY KEY, + storable_in_home BOOLEAN NOT NULL, + FOREIGN KEY (PFIC) REFERENCES pokemon_forms (PFIC) + ) + ''') + + def create_evolution_chains_table(self, cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS evolution_chains ( + from_pfic TEXT, + to_pfic TEXT, + method TEXT, + PRIMARY KEY (from_pfic, to_pfic), + FOREIGN KEY (from_pfic) REFERENCES pokemon_forms (PFIC), + FOREIGN KEY (to_pfic) REFERENCES pokemon_forms (PFIC) + ) + ''') + + def create_exclusive_encounter_groups_table(self, cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS exclusive_encounter_groups ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + group_name TEXT NOT NULL, + description TEXT, + game_id INTEGER, + FOREIGN KEY (game_id) REFERENCES games (id) + ) + ''') + + def create_encounter_exclusive_group_table(self, cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS encounter_exclusive_groups ( + encounter_id INTEGER, + group_id INTEGER, + FOREIGN KEY (encounter_id) REFERENCES encounters (id), + FOREIGN KEY (group_id) REFERENCES exclusive_encounter_groups (id), + PRIMARY KEY (encounter_id, group_id) + ) + ''') + + def create_encounters_table(self, cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS encounters ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + pfic TEXT, + game_id INTEGER, + location TEXT, + day TEXT, + time TEXT, + dual_slot TEXT, + static_encounter BOOLEAN, + static_encounter_count INTEGER, + extra_text TEXT, + stars TEXT, + fishing BOOLEAN, + rods TEXT, + starter BOOLEAN, + FOREIGN KEY (pfic) REFERENCES pokemon_forms (PFIC), + FOREIGN KEY (game_id) REFERENCES games (id) + ) + ''') + + def create_mark_table(self, cursor): + cursor.execute(''' + CREATE TABLE IF NOT EXISTS marks ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + icon_path TEXT NOT NULL + ) + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS mark_game_associations ( + mark_id INTEGER, + game_id INTEGER, + FOREIGN KEY (mark_id) REFERENCES marks (id), + FOREIGN KEY (game_id) REFERENCES games (id), + PRIMARY KEY (mark_id, game_id) + ) + ''') + + marks = [ + ("Game Boy", "images/marks/GB_icon_HOME.png", ["Red", "Blue", "Yellow", "Gold", "Silver", "Crystal"]), + ("Kalos", "images/marks/Blue_pentagon_HOME.png", ["X", "Y", "Omega Ruby", "Alpha Sapphire"]), + ("Alola", "images/marks/Black_clover_HOME.png", ["Sun", "Moon", "Ultra Sun", "Ultra Moon"]), + ("Let's Go", "images/marks/Let's_Go_icon_HOME.png", ["Let's Go Pikachu", "Let's Go Eevee"]), + ("Galar", "images/marks/Galar_symbol_HOME.png", ["Sword", "Shield"]), + ("Sinnoh", "images/marks/BDSP_icon_HOME.png", ["Brilliant Diamond", "Shining Pearl"]), + ("Hisui", "images/marks/Arceus_mark_HOME.png", ["Legends Arceus"]), + ("Paldea", "images/marks/Paldea_icon_HOME.png", ["Scarlet", "Violet"]), + ] + + # Check if marks already exist + cursor.execute('SELECT COUNT(*) FROM marks') + marks_count = cursor.fetchone()[0] + + if marks_count == 0: + for mark in marks: + cursor.execute(''' + INSERT OR IGNORE INTO marks (name, icon_path) + VALUES (?, ?) + ''', (mark[0], mark[1])) + + mark_id = cursor.lastrowid + + for game_name in mark[2]: + cursor.execute(''' + INSERT OR IGNORE INTO mark_game_associations (mark_id, game_id) + SELECT ?, id FROM games WHERE name = ? + ''', (mark_id, game_name)) + + def create_games_table(self, cursor): + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS games ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + generation INTEGER NOT NULL + ) + ''') + + cursor.execute(''' + CREATE TABLE IF NOT EXISTS alternate_game_names ( + id INTEGER PRIMARY KEY, + game_id INTEGER NOT NULL, + alternate_name TEXT NOT NULL, + FOREIGN KEY (game_id) REFERENCES games (id), + UNIQUE (alternate_name COLLATE NOCASE) + ) + ''') + + games = [ + ("Red", 1, ["Red Version"]), + ("Blue", 1, ["Blue Version"]), + ("Yellow", 1, ["Yellow Version"]), + ("Gold", 2, ["Gold Version"]), + ("Silver", 2, ["Silver Version"]), + ("Crystal", 2, ["Crystal Version"]), + ("Ruby", 3, ["Ruby Version"]), + ("Sapphire", 3, ["Sapphire Version"]), + ("Emerald", 3, ["Emerald Version"]), + ("FireRed", 3, ["Fire Red", "Fire-Red"]), + ("LeafGreen", 3, ["Leaf Green", "Leaf-Green"]), + ("Diamond", 4, ["Diamond Version"]), + ("Pearl", 4, ["Pearl Version"]), + ("Platinum", 4, ["Platinum Version"]), + ("HeartGold", 4, ["Heart Gold", "Heart-Gold"]), + ("SoulSilver", 4, ["Soul Silver", "Soul-Silver"]), + ("Black", 5, ["Black Version"]), + ("White", 5, ["White Version"]), + ("Black 2", 5, ["Black Version 2", "Black-2"]), + ("White 2", 5, ["White Version 2", "White-2"]), + ("X", 6, ["X Version"]), + ("Y", 6, ["Y Version"]), + ("Omega Ruby", 6, ["Omega Ruby Version", "Omega-Ruby"]), + ("Alpha Sapphire", 6, ["Alpha Sapphire Version", "Alpha-Sapphire"]), + ("Sun", 7, ["Sun Version"]), + ("Moon", 7, ["Moon Version"]), + ("Ultra Sun", 7, ["Ultra Sun Version", "Ultra-Sun"]), + ("Ultra Moon", 7, ["Ultra Moon Version", "Ultra-Moon"]), + ("Let's Go Pikachu", 7, ["Let's Go, Pikachu!", "Lets Go Pikachu"]), + ("Let's Go Eevee", 7, ["Let's Go, Eevee!", "Lets Go Eevee"]), + ("Sword", 8, ["Sword Version"]), + ("Shield", 8, ["Shield Version"]), + ("Expansion Pass", 8, ["Expansion Pass (Sword)", "Expansion Pass (Shield)"]), + ("Brilliant Diamond", 8, ["Brilliant Diamond Version", "Brilliant-Diamond"]), + ("Shining Pearl", 8, ["Shining Pearl Version", "Shining-Pearl"]), + ("Legends Arceus", 8, ["Legends: Arceus", "Legends-Arceus"]), + ("Scarlet", 9, ["Scarlet Version"]), + ("Violet", 9, ["Violet Version"]), + ("The Teal Mask", 9, ["The Teal Mask Version", "The Teal Mask (Scarlet)", "The Teal Mask (Violet)"]), + ("The Hidden Treasure of Area Zero", 9, ["The Hidden Treasure of Area Zero Version", "The Hidden Treasure of Area Zero (Scarlet)", "The Hidden Treasure of Area Zero (Violet)"]), + + ("Pokémon Home", 98, ["Pokémon HOME"]), + ("Pokémon Go", 99, ["Pokémon GO"]), + ] + + for game in games: + cursor.execute(''' + INSERT OR IGNORE INTO games (name, generation) + VALUES (?, ?) + ''', (game[0], game[1])) + + game_id = cursor.lastrowid + + # Insert alternate names + for alt_name in game[2]: + cursor.execute(''' + INSERT OR IGNORE INTO alternate_game_names (game_id, alternate_name) + VALUES (?, ?) + ''', (game_id, alt_name)) + + def load_pokemon_details(self, pfic): + self.cursor.execute(''' + SELECT pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home, pf.is_baby_form + FROM pokemon_forms pf + LEFT JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC + WHERE pf.PFIC = ? + ''', (pfic,)) + + return self.cursor.fetchone() + + def send_pokemon_list(self, data): + # Fetch pokemon list from database + self.cursor.execute(''' + SELECT pf.PFIC, pf.name, pf.form_name, pf.national_dex + FROM pokemon_forms pf + ''') + pokemon_data = self.cursor.fetchall() + + # Sort the pokemon_data based on PFIC + pokemon_data.sort(key=lambda x: parse_pfic(x[0])) + return pokemon_data + + def get_home_storable(self, pfic): + self.cursor.execute('SELECT storable_in_home FROM pokemon_storage WHERE PFIC = ?', (pfic,)) + result = self.cursor.fetchone() + home_storable = result[0] if result else False + return home_storable + + def get_evolution_chain(self, pfic): + def follow_chain(start_pfic, visited=None): + if visited is None: + visited = set() + + chain = [] + stack = [(start_pfic, None)] + + while stack: + current_pfic, method = stack.pop() + if current_pfic in visited: + continue + + visited.add(current_pfic) + self.cursor.execute('SELECT name, form_name FROM pokemon_forms WHERE PFIC = ?', (current_pfic,)) + name, form_name = self.cursor.fetchone() + + chain.append((current_pfic, name, form_name, method)) + + # Get previous evolutions + self.cursor.execute('SELECT from_pfic, method FROM evolution_chains WHERE to_pfic = ?', (current_pfic,)) + prev_evolutions = self.cursor.fetchall() + for prev_pfic, prev_method in prev_evolutions: + if prev_pfic not in visited: + stack.append((prev_pfic, prev_method)) + + # Get next evolutions + self.cursor.execute('SELECT to_pfic, method FROM evolution_chains WHERE from_pfic = ?', (current_pfic,)) + next_evolutions = self.cursor.fetchall() + for next_pfic, next_method in next_evolutions: + if next_pfic not in visited: + stack.append((next_pfic, next_method)) + + return chain + + return follow_chain(pfic) + + def get_evolution_parent(self, pfic): + self.cursor.execute('SELECT from_pfic FROM evolution_chains WHERE to_pfic = ?', (pfic,)) + return self.cursor.fetchone() + + def get_encounter_locations(self, pfic): + self.cursor.execute(''' + SELECT g.name, e.location, e.day, e.time, e.dual_slot, e.static_encounter_count, e.static_encounter, e.extra_text, e.stars, e.rods, e.fishing + FROM encounters e + JOIN games g ON e.game_id = g.id + WHERE e.pfic = ? + ORDER BY g.name, e.location + ''', (pfic,)) + return self.cursor.fetchall() + + def get_game_generation(self, game): + self.cursor.execute(''' + SELECT g.generation + FROM games g + LEFT JOIN alternate_game_names agn ON g.id = agn.game_id + WHERE g.name = ? OR agn.alternate_name = ? + LIMIT 1 + ''', (game, game)) + result = self.cursor.fetchone() + return result[0] if result else None + + def get_game_id_for_name(self, game): + # First, try to find the game in the main games table + self.cursor.execute(''' + SELECT id + FROM games + WHERE name = ? + ''', (game,)) + result = self.cursor.fetchone() + + if result: + return result[0] + + # If not found, check the alternate_game_names table + self.cursor.execute(''' + SELECT game_id + FROM alternate_game_names + WHERE alternate_name = ? + ''', (game,)) + result = self.cursor.fetchone() + + return result[0] if result else None + + def get_pokemon_with_encounters(self, data): + self.cursor.execute(''' + SELECT DISTINCT pfic + FROM encounters + ''') + pokemon_with_encounters = set(row[0] for row in self.cursor.fetchall()) + return pokemon_with_encounters + + def refresh_in_memory_db(self, temp_conn): + temp_conn.backup(self.conn) + + def clear_encounters_for_pokemon(self, pfic): + self.cursor.execute('DELETE FROM encounters WHERE pfic = ?', (pfic,)) + self.conn.commit() diff --git a/DBEditor/event_system.py b/DBEditor/event_system.py index da891db..339d8df 100644 --- a/DBEditor/event_system.py +++ b/DBEditor/event_system.py @@ -20,35 +20,28 @@ class EventSystem: with self.lock: self.listeners[event_type].remove(callback) - def emit(self, event_type, data=None, callback=None): - self.event_queue.put((event_type, data, callback)) + def emit(self, event_type, data=None): + self.event_queue.put((event_type, data)) def emit_sync(self, event_type, data=None): - results = [] - with self.lock: - for listener in self.listeners[event_type]: - result = listener(data) - results.append(result) - return results + #with self.lock: + for listener in self.listeners[event_type]: + listener(data) def call_sync(self, event_type, data=None): - with self.lock: - if event_type in self.listeners and self.listeners[event_type]: - # Call only the first registered listener - return self.listeners[event_type][0](data) + #with self.lock: + if event_type in self.listeners and self.listeners[event_type]: + # Call only the first registered listener + return self.listeners[event_type][0](data) return None def _process_events(self): while not self._stop_event.is_set(): try: - event_type, data, callback = self.event_queue.get(timeout=0.1) - results = [] + event_type, data = self.event_queue.get(timeout=0.1) with self.lock: for listener in self.listeners[event_type]: - result = listener(data) - results.append(result) - if callback: - callback(results) + listener(data) except Empty: pass diff --git a/DBEditor/plan.py b/DBEditor/plan.py new file mode 100644 index 0000000..88ee68d --- /dev/null +++ b/DBEditor/plan.py @@ -0,0 +1,269 @@ +import sqlite3 +from collections import defaultdict + +class OriginDexPlanner: + def __init__(self, db_path): + self.conn = sqlite3.connect(db_path) + self.conn.row_factory = sqlite3.Row + + def get_game_data(self): + """Fetch game and pokemon information from the database.""" + cursor = self.conn.cursor() + cursor.execute("SELECT * FROM games") + games = cursor.fetchall() + + cursor.execute("SELECT * FROM pokemon_forms WHERE name IN ('Elekid', 'Electabuzz', 'Electivire')") + pokemon_forms = cursor.fetchall() + + cursor.execute("SELECT * FROM encounters") + encounters = cursor.fetchall() + + exclusive_encounters = [] + cursor.execute("SELECT * FROM evolution_chains WHERE from_pfic IN (SELECT PFIC FROM pokemon_forms WHERE name IN ('Elekid', 'Electabuzz', 'Electivire'))") + evolutions = cursor.fetchall() + + return games, pokemon_forms, encounters, exclusive_encounters, evolutions + + def build_pokemon_data(self): + """Construct data dictionaries to store relationships between the Pokemon and encounters.""" + games, pokemon_forms, encounters, exclusive_encounters, evolutions = self.get_game_data() + + pokemon_by_gen = defaultdict(list) + game_by_gen = defaultdict(list) + encounter_data = defaultdict(list) + + for game in games: + game_by_gen[game['generation']].append(game) + + for pokemon in pokemon_forms: + pokemon_by_gen[pokemon['generation']].append(pokemon) + + # Build a dict of encounters, mapping game_id to Pokemon encountered in it + for encounter in encounters: + encounter_data[encounter['game_id']].append(encounter) + + evolution_map = defaultdict(list) + for evolution in evolutions: + from_pfic = evolution['from_pfic'] + to_pfic = evolution['to_pfic'] + # Lookup generation from pokemon_forms table + cursor = self.conn.cursor() + cursor.execute("SELECT generation FROM pokemon_forms WHERE PFIC = ?", (to_pfic,)) + to_generation = cursor.fetchone()['generation'] + evolution_map[from_pfic].append((to_pfic, to_generation)) + + exclusive_group_map = defaultdict(list) + for exclusive_encounter in exclusive_encounters: + exclusive_group_map[exclusive_encounter['group_id']].append(exclusive_encounter['encounter_id']) + + return pokemon_by_gen, game_by_gen, encounter_data, evolution_map, exclusive_group_map + + def generate_plan(self, generations_to_group_list=None): + """Generate a game plan to catch all Pokemon in their origin generation.""" + if generations_to_group_list is None: + generations_to_group_list = [] + + pokemon_by_gen, game_by_gen, encounter_data, evolution_map, exclusive_group_map = self.build_pokemon_data() + + plan = [] + pokemon_to_catch = defaultdict(list) + caught_pokemon = set() + pokemon_names = {} + + # Handle multiple sets of grouped generations + grouped_generations_sets = [set(generations) for generations in generations_to_group_list] + for grouped_generations in grouped_generations_sets: + grouped_games = [] + grouped_pokemon_list = [] + for gen in grouped_generations: + if gen in game_by_gen: + grouped_games.extend(game_by_gen[gen]) + grouped_pokemon_list.extend(pokemon_by_gen[gen]) + + if grouped_games: + plan.extend(self.generate_plan_for_generation(grouped_games, grouped_pokemon_list, encounter_data, evolution_map, exclusive_group_map, pokemon_names, caught_pokemon, game_by_gen)) + + # Loop through each generation, generating a plan for each game + for gen in sorted(game_by_gen.keys()): + # Skip generations that have been grouped + if any(gen in grouped_generations for grouped_generations in grouped_generations_sets): + continue + games = game_by_gen[gen] + pokemon_list = pokemon_by_gen[gen] + + plan.extend(self.generate_plan_for_generation(games, pokemon_list, encounter_data, evolution_map, exclusive_group_map, pokemon_names, caught_pokemon, game_by_gen)) + + return plan + + def generate_plan_for_generation(self, games, pokemon_list, encounter_data, evolution_map, exclusive_group_map, pokemon_names, caught_pokemon, game_by_gen): + """Generate a game plan for a specific generation or group of generations.""" + plan = [] + pokemon_to_catch = defaultdict(list) + pokemon_to_breed = defaultdict(list) + catchable_pokemon = set() + + # Create a set of baby Pokémon PFICs + baby_pokemon = set(pokemon['PFIC'] for pokemon in pokemon_list if pokemon['is_baby_form']) + + # Identify unique evolution chains and the starting point + for pokemon in pokemon_list: + pfic = pokemon['PFIC'] + pokemon_names[pfic] = f'{pokemon["name"]} ({pokemon["form_name"] if pokemon["form_name"] is not None else ""})' + if pfic not in evolution_map: # Not evolved from anything + catchable_pokemon.add(pfic) + else: + catchable_pokemon.add(pfic) + # Add all evolution stages to catchable list if they belong to the current or previous generations + current = pfic + current_generation = pokemon['generation'] + while current in evolution_map: + next_pfic, next_generation = evolution_map[current][0] + if any(p['PFIC'] == next_pfic for p in pokemon_list): + if next_generation <= current_generation: + catchable_pokemon.add(next_pfic) + current = next_pfic + + # Determine the best game to catch the most Pokemon + best_game = None + max_catchable = 0 + game_catchable_pokemon = defaultdict(set) + for game in games: + game_id = game['id'] + encounters = encounter_data[game_id] + + # Track how many unique Pokemon are available in this game + for encounter in encounters: + pfic = encounter['pfic'] + if pfic in catchable_pokemon: + game_catchable_pokemon[game_id].add(pfic) + + # Update the best game if this game has more catchable Pokemon + if len(game_catchable_pokemon[game_id]) > max_catchable: + max_catchable = len(game_catchable_pokemon[game_id]) + best_game = game + + # Use the best game to catch as many unique Pokemon as possible + remaining_games = [game for game in games if game != best_game] + if best_game: + game_id = best_game['id'] + game_name = best_game['name'] + encounters = encounter_data[game_id] + + for encounter in encounters: + pfic = encounter['pfic'] + if pfic in catchable_pokemon and pfic not in caught_pokemon: + evolution_chain = self.get_full_evolution_chain(pfic, evolution_map) + base_pokemon = evolution_chain[0] + if base_pokemon not in caught_pokemon: + # Calculate the number of Pokemon needed for the full evolution chain + count = len(evolution_chain) + if encounter['static_encounter']: + count = min(count, encounter['static_encounter_count'] or 1) + + if base_pokemon in baby_pokemon: + # For baby Pokémon, catch the first non-baby evolution and breed for the baby + non_baby_pokemon = next((p for p in evolution_chain if p not in baby_pokemon), None) + if non_baby_pokemon: + pokemon_to_catch[game_name].append({'pfic': non_baby_pokemon, 'count': 1}) + pokemon_to_breed[game_name].append({'pfic': base_pokemon, 'count': 1}) + else: + pokemon_to_catch[game_name].append({'pfic': base_pokemon, 'count': count}) + + caught_pokemon.update(evolution_chain) + + # Account for exclusive encounters + exclusive_group_ids = [group['group_id'] for group in exclusive_group_map if group['encounter_id'] == encounter['id']] + if exclusive_group_ids: + other_options = exclusive_group_map[exclusive_group_ids[0]] + if len(other_options) > 1: + # Pick one of the options, mark the rest to catch in another game + catchable_pokemon.remove(pfic) + else: + continue + + # Use remaining games to catch any remaining Pokemon + for game in remaining_games: + game_id = game['id'] + game_name = game['name'] + encounters = encounter_data[game_id] + + for encounter in encounters: + pfic = encounter['pfic'] + if pfic in catchable_pokemon and pfic not in caught_pokemon: + evolution_chain = self.get_full_evolution_chain(pfic, evolution_map) + base_pokemon = evolution_chain[0] + if base_pokemon not in caught_pokemon: + # Calculate the number of Pokemon needed for the full evolution chain + count = len(evolution_chain) + if encounter['static_encounter']: + count = min(count, encounter['static_encounter_count'] or 1) + + if base_pokemon in baby_pokemon: + # For baby Pokémon, catch the first non-baby evolution and breed for the baby + non_baby_pokemon = next((p for p in evolution_chain if p not in baby_pokemon), None) + if non_baby_pokemon: + pokemon_to_catch[game_name].append({'pfic': non_baby_pokemon, 'count': 1}) + pokemon_to_breed[game_name].append({'pfic': base_pokemon, 'count': 1}) + else: + pokemon_to_catch[game_name].append({'pfic': base_pokemon, 'count': count}) + + caught_pokemon.update(evolution_chain) + + # Handle new evolutions or forms added in later generations + for pfic in list(caught_pokemon): + if pfic in evolution_map: + for new_evolution, new_generation in evolution_map[pfic]: + # Check if the new evolution is from a later generation + full_evolution_chain = self.get_full_evolution_chain(pfic, evolution_map) + current_generation = min((pokemon['generation'] for pokemon in pokemon_list if pokemon['PFIC'] in full_evolution_chain), default=None) + if new_generation and current_generation and new_generation > current_generation: + # Add the baby/base form to be caught in the new generation if required + base_pokemon = full_evolution_chain[0] + new_gen_games = game_by_gen[new_generation] + for game in new_gen_games: + game_id = game['id'] + game_name = game['name'] + encounters = encounter_data[game_id] + for encounter in encounters: + if encounter['pfic'] == base_pokemon and base_pokemon not in caught_pokemon: + if base_pokemon in baby_pokemon: + non_baby_pokemon = next((p for p in full_evolution_chain if p not in baby_pokemon), None) + if non_baby_pokemon: + pokemon_to_catch[game_name].append({'pfic': non_baby_pokemon, 'count': 1}) + pokemon_to_breed[game_name].append({'pfic': base_pokemon, 'count': 1}) + else: + pokemon_to_catch[game_name].append({'pfic': base_pokemon, 'count': 1}) + caught_pokemon.add(base_pokemon) + break + + # Generate the plan for this generation or group of generations + for game_name in set(list(pokemon_to_catch.keys()) + list(pokemon_to_breed.keys())): + plan.append(f"Play {game_name}:") + if game_name in pokemon_to_catch: + plan.append(f" Catch {len(pokemon_to_catch[game_name])} unique Pokemon:") + for pokemon in pokemon_to_catch[game_name]: + plan.append(f" - {pokemon_names[pokemon['pfic']]}: {pokemon['count']} times") + + if game_name in pokemon_to_breed: + plan.append(f" Breed {len(pokemon_to_breed[game_name])} Pokemon:") + for pokemon in pokemon_to_breed[game_name]: + plan.append(f" - {pokemon_names[pokemon['pfic']]}: {pokemon['count']} times") + + return plan + + def get_full_evolution_chain(self, pfic, evolution_map): + """Get the full evolution chain for a given PFIC.""" + chain = [pfic] + while pfic in evolution_map: + pfic = evolution_map[pfic][0][0] + chain.append(pfic) + return chain + + def display_plan(self, generations_to_group_list=None): + plan = self.generate_plan(generations_to_group_list) + for step in plan: + print(step) + +# Example usage +planner = OriginDexPlanner('pokemon_forms.db') +planner.display_plan(generations_to_group_list=[[1, 2], [3, 4, 5, 6]]) \ No newline at end of file diff --git a/DBEditor/plan2.py b/DBEditor/plan2.py new file mode 100644 index 0000000..d1a158d --- /dev/null +++ b/DBEditor/plan2.py @@ -0,0 +1,262 @@ +import sqlite3 +import os +from collections import defaultdict + +class EfficiencyOriginDexPlanner: + def __init__(self, db_path): + self.conn = sqlite3.connect(db_path) + self.conn.row_factory = sqlite3.Row + + def get_all_data(self): + cursor = self.conn.cursor() + cursor.execute("SELECT * FROM games ORDER BY generation, id") + games = cursor.fetchall() + + cursor.execute("SELECT * FROM pokemon_forms ORDER BY generation, national_dex") + pokemon_forms = cursor.fetchall() + + cursor.execute("SELECT * FROM encounters") + encounters = cursor.fetchall() + + cursor.execute("SELECT * FROM evolution_chains") + evolutions = cursor.fetchall() + + return games, pokemon_forms, encounters, evolutions + + def build_data_structures(self): + games, pokemon_forms, encounters, evolutions = self.get_all_data() + + pokemon_by_gen = defaultdict(list) + game_by_gen = defaultdict(list) + encounter_data = defaultdict(list) + evolution_map = defaultdict(list) + + for game in games: + game_by_gen[game['generation']].append(game) + + for pokemon in pokemon_forms: + pokemon_by_gen[pokemon['generation']].append(pokemon) + + for encounter in encounters: + encounter_data[encounter['game_id']].append(encounter) + + for evolution in evolutions: + evolution_map[evolution['from_pfic']].append(evolution['to_pfic']) + + return pokemon_by_gen, game_by_gen, encounter_data, evolution_map + + def generate_efficient_plan(self, generation_groups): + pokemon_by_gen, game_by_gen, encounter_data, evolution_map = self.build_data_structures() + plan = [] + caught_pokemon = set() + + for group in generation_groups: + group_plan = self.plan_for_group(group, pokemon_by_gen, game_by_gen, encounter_data, evolution_map, caught_pokemon) + plan.extend(group_plan) + + return plan + + def plan_for_group(self, generations, pokemon_by_gen, game_by_gen, encounter_data, evolution_map, caught_pokemon): + group_plan = [] + needed_pokemon = set() + games_in_group = [] + + for gen in generations: + needed_pokemon.update(pokemon['PFIC'] for pokemon in pokemon_by_gen[gen]) + games_in_group.extend(game_by_gen[gen]) + + # Check for new evolutions of already caught Pokémon + new_evolutions = set() + for pfic in caught_pokemon: + if pfic in evolution_map: + for evolved_pfic in evolution_map[pfic]: + if self.get_pokemon_generation(evolved_pfic) in generations and evolved_pfic not in caught_pokemon: + new_evolutions.add(pfic) + needed_pokemon.add(evolved_pfic) + print(f"New evolution: {self.get_pokemon_name(pfic)} into {self.get_pokemon_name(evolved_pfic)}") + + games_in_group.sort(key=lambda g: len([e for e in encounter_data[g['id']] if e['pfic'] in needed_pokemon]), reverse=True) + + for game in games_in_group: + game_plan = self.plan_for_game(game, needed_pokemon, encounter_data, evolution_map, caught_pokemon, set(generations), new_evolutions) + if game_plan: + group_plan.extend(game_plan) + + return group_plan + + def plan_for_game(self, game, needed_pokemon, encounter_data, evolution_map, caught_pokemon, target_generations, new_evolutions): + game_plan = [] + to_catch = defaultdict(int) + to_evolve = defaultdict(list) + to_breed = defaultdict(list) + planned_evolutions = defaultdict(int) + processed_chains = set() + + # First, handle new evolutions for already caught Pokémon + for pfic in new_evolutions: + evolution_chains, visit_counts, baby_forms = self.get_evolution_chains(pfic, evolution_map, target_generations) + + new_evolutions_count = sum(1 for chain in evolution_chains for pokemon in chain if pokemon not in caught_pokemon) + + if new_evolutions_count > 0: + if any(encounter['pfic'] == pfic for encounter in encounter_data[game['id']]): + to_catch[pfic] += new_evolutions_count - planned_evolutions[pfic] + planned_evolutions[pfic] += new_evolutions_count + + for chain in evolution_chains: + if len(chain) > 1: + for i in range(len(chain) - 1): + from_pfic, to_pfic = chain[i], chain[i+1] + if to_pfic not in caught_pokemon: + to_evolve[from_pfic].append(to_pfic) + caught_pokemon.add(to_pfic) + needed_pokemon.discard(to_pfic) + + # Then proceed with the regular planning + for encounter in encounter_data[game['id']]: + if encounter['pfic'] in needed_pokemon and encounter['pfic'] not in caught_pokemon: + evolution_chains, visit_counts, baby_forms = self.get_evolution_chains(encounter['pfic'], evolution_map, target_generations) + base_form = evolution_chains[0][0] + + if base_form not in caught_pokemon: + chain_key = tuple(sorted(set(pokemon for chain in evolution_chains for pokemon in chain))) + if chain_key not in processed_chains: + processed_chains.add(chain_key) + + num_to_catch = max(0, visit_counts[base_form] - planned_evolutions[base_form]) + if num_to_catch > 0: + to_catch[encounter['pfic']] += num_to_catch + planned_evolutions[base_form] += num_to_catch + + for chain in evolution_chains: + if len(chain) > 1: + for i in range(len(chain) - 1): + from_pfic, to_pfic = chain[i], chain[i+1] + if from_pfic not in baby_forms: + if not self.is_final_evolution(to_pfic, evolution_map) or (self.is_final_evolution(to_pfic, evolution_map) and not self.is_in_to_evolve(to_pfic, to_evolve)): + to_evolve[from_pfic].append(to_pfic) + else: + to_catch[encounter['pfic']] += -1 + planned_evolutions[base_form] += -1 + + if from_pfic in baby_forms and from_pfic not in encounter_data[game['id']]: + if to_pfic not in to_breed or from_pfic not in to_breed[to_pfic]: + to_breed[to_pfic].append(from_pfic) + + caught_pokemon.update(pfic for chain in evolution_chains for pfic in chain) + needed_pokemon.difference_update(pfic for chain in evolution_chains for pfic in chain) + + if to_catch or to_evolve or to_breed: + game_plan.append(f"Play {game['name']}:") + if to_catch: + game_plan.append(" Catch:") + for pfic, count in to_catch.items(): + game_plan.append(f" - {self.get_pokemon_name(pfic)}: {count} time(s)") + if to_evolve: + game_plan.append(" Evolve:") + for from_pfic, to_pfics in to_evolve.items(): + for to_pfic in to_pfics: + game_plan.append(f" - {self.get_pokemon_name(from_pfic)} into {self.get_pokemon_name(to_pfic)}") + if to_breed: + game_plan.append(" Breed:") + for parent_pfic, baby_pfics in to_breed.items(): + for baby_pfic in baby_pfics: + game_plan.append(f" - {self.get_pokemon_name(parent_pfic)} to get {self.get_pokemon_name(baby_pfic)}") + + return game_plan + + def plan_evolutions(self, evolution_chains, evolution_map, caught_pokemon): + chains, visit_counts = self.get_evolution_chains(evolution_chains[0][0], evolution_map) + evolution_plan = [] + needed_counts = defaultdict(int) + + # Count how many of each Pokémon we need based on visit counts + for pfic, count in visit_counts.items(): + if pfic not in caught_pokemon: + needed_counts[pfic] = count + + # Plan evolutions + for chain in chains: + for i in range(len(chain) - 1): + from_pfic, to_pfic = chain[i], chain[i+1] + if needed_counts[to_pfic] > 0: + evolution_plan.append((from_pfic, to_pfic)) + needed_counts[to_pfic] -= 1 + needed_counts[from_pfic] -= 1 + + return evolution_plan, needed_counts + + def get_evolution_chains(self, pfic, evolution_map, target_generations): + visited = defaultdict(int) + unique_paths = set() + baby_forms = set() + + def dfs(current_pfic, path): + path_tuple = tuple(path) + if path_tuple in unique_paths: + return + + unique_paths.add(path_tuple) + for pfic in path: + visited[pfic] += 1 + if self.is_baby_pokemon(pfic): + baby_forms.add(pfic) + + if current_pfic in evolution_map: + for next_pfic in evolution_map[current_pfic]: + if self.get_pokemon_generation(next_pfic) in target_generations: + dfs(next_pfic, path + [next_pfic]) + + dfs(pfic, [pfic]) + chains = [list(path) for path in unique_paths] + + # Adjust visit counts for baby Pokémon + for baby in baby_forms: + visited[baby] = 1 + + return chains, visited, baby_forms + + def get_pokemon_name(self, pfic): + cursor = self.conn.cursor() + cursor.execute("SELECT name, form_name FROM pokemon_forms WHERE PFIC = ?", (pfic,)) + result = cursor.fetchone() + if result['form_name']: + return f"{result['name']} ({result['form_name']})" + return result['name'] + + def display_plan(self, generation_groups, output_file='efficiency_plan.txt'): + plan = self.generate_efficient_plan(generation_groups) + + # Print to console + for step in plan: + print(step) + + # Write to file + with open(output_file, 'w', encoding='utf-8') as f: + for step in plan: + f.write(f"{step}\n") + + print(f"\nPlan has been written to {os.path.abspath(output_file)}") + + def is_baby_pokemon(self, pfic): + cursor = self.conn.cursor() + cursor.execute("SELECT is_baby_form FROM pokemon_forms WHERE PFIC = ?", (pfic,)) + result = cursor.fetchone() + return result['is_baby_form'] if result else False + + def get_pokemon_generation(self, pfic): + cursor = self.conn.cursor() + cursor.execute("SELECT generation FROM pokemon_forms WHERE PFIC = ?", (pfic,)) + result = cursor.fetchone() + return result['generation'] if result else None + + def is_final_evolution(self, pfic, evolution_map): + return pfic not in evolution_map + + def is_in_to_evolve(self, pfic, to_evolve): + return any(pfic in to_pfics for to_pfics in to_evolve.values()) + +# Example usage +planner = EfficiencyOriginDexPlanner('pokemon_forms.db') +planner.display_plan([[1, 2], [3, 4, 5, 6], [7], [8], [9]]) + diff --git a/DBEditor/pokemon_db_ui.py b/DBEditor/pokemon_db_ui.py index 3208cca..c743ac8 100644 --- a/DBEditor/pokemon_db_ui.py +++ b/DBEditor/pokemon_db_ui.py @@ -5,14 +5,18 @@ from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QH QLabel, QCheckBox, QPushButton, QFormLayout, QListWidgetItem, QSplitter, QTreeWidget, QTreeWidgetItem, QDialog, QDialogButtonBox, QComboBox, QMessageBox, QSpinBox, QMenu, QTabWidget, QTextEdit) -from PyQt6.QtCore import Qt, QSize +from PyQt6.QtCore import Qt, QSize, QTimer, QMetaObject from PyQt6.QtGui import QPixmap, QFontMetrics, QColor, QAction +from collections import deque + from event_system import event_system +import logging class EvolutionEditDialog(QDialog): def __init__(self, parent=None, from_pfic=None, to_pfic=None, method=None): super().__init__(parent) + self.setWindowTitle("Edit Evolution") self.setModal(True) @@ -59,8 +63,34 @@ class EvolutionEditDialog(QDialog): class PokemonUI(QWidget): # Change from QMainWindow to QWidget def __init__(self, parent=None): super().__init__(parent) + + self.log_queue = deque() # Queue to store log messages + self.log_timer = QTimer(self) + self.log_timer.timeout.connect(self.process_log_queue) + self.log_timer.start(100) + + event_system.add_listener('refresh_pokemon_details_panel', self.refresh) + event_system.add_listener('update_log_display', self.queue_log_message) + event_system.add_listener('clear_log_display', self.clear_log_display) + + self.logger = logging.getLogger('ui_feedback') + + self.encounter_cache = {} + self.evolution_load_timer = QTimer() + self.evolution_load_timer.setSingleShot(True) + self.evolution_load_timer.timeout.connect(self._load_evolution_chain) + self.current_evolution_pfic = None self.init_ui() self.request_pokemon_list() + self.logger.info("Initializing PokemonUI") + + def queue_log_message(self, message): + self.log_queue.append(message) + + def process_log_queue(self): + while self.log_queue: + message = self.log_queue.popleft() + self.update_log_display(message) def init_ui(self): main_layout = QVBoxLayout(self) # Use self directly instead of a central widget @@ -86,7 +116,7 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget self.pokemon_list = QListWidget() self.pokemon_list.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) - #self.pokemon_list.customContextMenuRequested.connect(self.show_pokemon_context_menu) + self.pokemon_list.customContextMenuRequested.connect(self.show_pokemon_context_menu) self.pokemon_list.currentItemChanged.connect(self.on_pokemon_selected) left_layout.addWidget(self.pokemon_list) @@ -103,9 +133,10 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget main_tab_layout.addLayout(left_layout, 1) # Right side: Edit panel - right_layout = QHBoxLayout() + right_layout = QVBoxLayout() # Left side of right panel: Text information + info_layout = QHBoxLayout() text_layout = QVBoxLayout() self.edit_form = QFormLayout() self.name_label = QLabel() @@ -124,54 +155,59 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget text_layout.addLayout(self.edit_form) + # Right side of right panel: Image + image_layout = QVBoxLayout() + self.image_label = QLabel() + self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.image_label.setFixedSize(150, 150) + image_layout.addWidget(self.image_label) + image_layout.addStretch(1) + + info_layout.addLayout(text_layout) + info_layout.addLayout(image_layout) + + second_half_layout = QVBoxLayout() # Evolution chain tree self.evolution_tree = QTreeWidget() self.evolution_tree.setHeaderLabels(["Pokémon", "Evolution Method"]) self.evolution_tree.setColumnWidth(0, 200) - text_layout.addWidget(self.evolution_tree) + second_half_layout.addWidget(self.evolution_tree) # Add Locations tree self.locations_tree = QTreeWidget() self.locations_tree.setHeaderLabels(["Game/Location", "Details"]) self.locations_tree.setColumnWidth(0, 200) self.locations_tree.itemDoubleClicked.connect(self.edit_encounter) - text_layout.addWidget(QLabel("Locations:")) - text_layout.addWidget(self.locations_tree) + second_half_layout.addWidget(QLabel("Locations:")) + second_half_layout.addWidget(self.locations_tree) # Add New Encounter button self.add_encounter_button = QPushButton("Add New Encounter") self.add_encounter_button.clicked.connect(self.add_new_encounter) - text_layout.addWidget(self.add_encounter_button) + second_half_layout.addWidget(self.add_encounter_button) # Move buttons to the bottom - text_layout.addStretch(1) - - self.save_button = QPushButton("Save Changes") - self.save_button.clicked.connect(self.save_changes) - text_layout.addWidget(self.save_button) - - self.export_button = QPushButton("Export Database") - self.export_button.clicked.connect(self.export_database) - text_layout.addWidget(self.export_button) + second_half_layout.addStretch(1) # Add New Evolution button self.add_evolution_button = QPushButton("Add New Evolution") self.add_evolution_button.clicked.connect(self.add_new_evolution) - text_layout.addWidget(self.add_evolution_button) + second_half_layout.addWidget(self.add_evolution_button) - # Right side of right panel: Image - image_layout = QVBoxLayout() - self.image_label = QLabel() - self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.image_label.setFixedSize(200, 200) - image_layout.addWidget(self.image_label) - image_layout.addStretch(1) - - right_layout.addLayout(text_layout) - right_layout.addLayout(image_layout) + right_layout.addLayout(info_layout) + right_layout.addLayout(second_half_layout) main_tab_layout.addLayout(right_layout, 1) + + self.save_button = QPushButton("Save Changes") + self.save_button.clicked.connect(self.save_changes) + main_layout.addWidget(self.save_button) + + self.export_button = QPushButton("Export Database") + self.export_button.clicked.connect(self.export_database) + main_layout.addWidget(self.export_button) + # Database Operations tab db_tab = QWidget() db_tab_layout = QVBoxLayout(db_tab) @@ -179,19 +215,19 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget # Add buttons to the Database Operations tab gather_forms_btn = QPushButton("Gather Pokémon Forms") - #gather_forms_btn.clicked.connect(self.gather_pokemon_forms) + gather_forms_btn.clicked.connect(self.gather_pokemon_forms) db_tab_layout.addWidget(gather_forms_btn) gather_home_btn = QPushButton("Gather Home Storage Info") - #gather_home_btn.clicked.connect(self.gather_home_storage_info) + gather_home_btn.clicked.connect(self.gather_home_storage_info) db_tab_layout.addWidget(gather_home_btn) gather_evolutions_btn = QPushButton("Gather Evolution Information") - #gather_evolutions_btn.clicked.connect(self.gather_evolution_info) + gather_evolutions_btn.clicked.connect(self.gather_evolution_info) db_tab_layout.addWidget(gather_evolutions_btn) gather_encounters_btn = QPushButton("Gather Encounter Information") - #gather_encounters_btn.clicked.connect(self.gather_encounter_info) + gather_encounters_btn.clicked.connect(self.gather_encounter_info) db_tab_layout.addWidget(gather_encounters_btn) # Add QTextEdit for progress reporting @@ -203,28 +239,40 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget db_tab_layout.addStretch(1) # Add stretch to separate the last button reinit_db_btn = QPushButton("Clear and Reinitialize Database") - #reinit_db_btn.clicked.connect(self.reinitialize_database) + reinit_db_btn.clicked.connect(self.reinitialize_database) db_tab_layout.addWidget(reinit_db_btn) + encounter_tab = QWidget() + encounter_tab_layout = QVBoxLayout(encounter_tab) + self.tab_widget.addTab(encounter_tab, "Manage Encounters") + def on_pokemon_selected(self, item): pfic = item.data(Qt.ItemDataRole.UserRole) - pokemon_data = event_system.emit_sync('get_pokemon_data', data=pfic) + self.refresh_pokemon_details_panel(pfic) + + def refresh(self, pfic): + self.refresh_pokemon_details_panel(pfic) + self.update_encounter_cache() + self.update_pokemon_list_highlights() + + def refresh_pokemon_details_panel(self, pfic): + pokemon_data = event_system.call_sync('get_pokemon_data', data=pfic) if pokemon_data: - name, form_name, national_dex, generation, storable_in_home = pokemon_data[0] + name, form_name, national_dex, generation, storable_in_home, is_baby_form = pokemon_data self.name_label.setText(name) self.form_name_label.setText(form_name if form_name else "") self.national_dex_label.setText(str(national_dex)) self.generation_label.setText(str(generation)) self.home_checkbox.setChecked(bool(storable_in_home)) #self.home_checkbox.stateChanged.connect(self.update_home_storable) - self.is_baby_form_checkbox.setChecked(bool(False)) + self.is_baby_form_checkbox.setChecked(bool(is_baby_form)) # Load and display the image image_path = f"images-new/{pfic}.png" if os.path.exists(image_path): pixmap = QPixmap(image_path) - self.image_label.setPixmap(pixmap.scaled(200, 200, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) + self.image_label.setPixmap(pixmap.scaled(150, 150, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)) else: self.image_label.setText("Image not found") @@ -232,15 +280,33 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget self.load_evolution_chain(pfic) # Load and display encounter locations - #self.load_encounter_locations(pfic) + self.load_encounter_locations(pfic) self.current_pfic = pfic self.add_evolution_button.setEnabled(True) # Enable the button when a Pokémon is selected def load_evolution_chain(self, pfic): - self.evolution_tree.clear() + self.current_evolution_pfic = pfic + if self.evolution_load_timer.isActive(): + self.evolution_load_timer.stop() + self.evolution_load_timer.start(50) # 50ms delay + + def _load_evolution_chain(self): + if not hasattr(self, 'evolution_tree') or self.evolution_tree is None: + print("Evolution tree widget not initialized") + return + + pfic = self.current_evolution_pfic + if pfic is None: + return + + try: + self.evolution_tree.clear() + except RuntimeError: + print("Error clearing evolution tree. Widget might have been deleted.") + return - evolution_chain = event_system.emit_sync('get_evolution_chain', data=pfic)[0] + evolution_chain = event_system.call_sync('get_evolution_chain', data=pfic) # Create a dictionary to store tree items tree_items = {} @@ -261,7 +327,7 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget item = tree_items[current_pfic] # Find the parent of this item - parent_pfic = event_system.emit_sync('get_evolution_parent', data=current_pfic)[0] + parent_pfic = event_system.call_sync('get_evolution_parent', data=current_pfic) if parent_pfic: parent_item = tree_items.get(parent_pfic[0]) @@ -282,6 +348,58 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget # Connect double-click signal #self.evolution_tree.itemDoubleClicked.connect(self.edit_evolution) + def load_encounter_locations(self, pfic): + self.locations_tree.clear() + + encounters = event_system.call_sync('get_encounter_locations', data=pfic) + + game_items = {} + for encounter in encounters: + game, location, day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, rods, fishing = encounter + + if game not in game_items: + #print(f'finding generation for {game}') + game_item = QTreeWidgetItem([game]) + game_items[game] = game_item + + generation = event_system.call_sync('get_game_generation', data=game) + # Use generation for sorting, default to 0 if not found + game_item.setData(0, Qt.ItemDataRole.UserRole, generation) + #print(f'generation for {game} is {generation}') + + location_item = QTreeWidgetItem([location]) + details = [] + if day: + details.append(f"Day: {day}") + if time: + details.append(f"Time: {time}") + if dual_slot: + details.append(f"Dual Slot: {dual_slot}") + if static_encounter: + details.append(f"Static Encounter (Count: {static_encounter_count})") + if extra_text: + details.append(f"Extra: {extra_text}") + if stars: + details.append(f"Stars: {stars}") + if fishing: + details.append(f"Fishing") + if rods: + details.append(f"Rods: {rods}") + + location_item.setText(1, ", ".join(details)) + game_items[game].addChild(location_item) + + # Sort game items by generation and add them to the tree + sorted_game_items = sorted(game_items.values(), key=lambda x: x.data(0, Qt.ItemDataRole.UserRole)) + self.locations_tree.addTopLevelItems(sorted_game_items) + self.locations_tree.expandAll() + + # Update the cache for this Pokémon + self.encounter_cache[pfic] = len(encounters) > 0 + + # After updating the locations tree + self.update_pokemon_list_highlights() + def on_save_button_clicked(self): # Gather data from UI elements data = { @@ -292,7 +410,8 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget event_system.emit('save_changes', data) def request_pokemon_list(self): - event_system.emit('get_pokemon_list', self.update_pokemon_list) + pokemon_data = event_system.call_sync('get_pokemon_list') + self.update_pokemon_list(pokemon_data) def update_pokemon_list(self, pokemon_data): self.pokemon_list.clear() @@ -305,7 +424,7 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget item.setData(Qt.ItemDataRole.UserRole, pfic) self.pokemon_list.addItem(item) - #self.update_encounter_cache() + self.update_encounter_cache() self.update_pokemon_list_highlights() self.adjust_list_width() self.filter_pokemon_list() @@ -345,6 +464,14 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget def toggle_highlight_mode(self): self.update_pokemon_list_highlights() + def update_encounter_cache(self): + pokemon_with_encounters = event_system.call_sync('get_pokemon_with_encounters') + for i in range(self.pokemon_list.count()): + item = self.pokemon_list.item(i) + pfic = item.data(Qt.ItemDataRole.UserRole) + self.encounter_cache[pfic] = pfic in pokemon_with_encounters + + def update_pokemon_list_highlights(self): highlight_mode = self.highlight_no_encounters.isChecked() for i in range(self.pokemon_list.count()): @@ -396,24 +523,20 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget layout.addRow("Fishing:", fishing_check) layout.addRow("Rods:", rods_edit) + layout.addRow("Exclusive Group:", QLabel()) exclusive_group_combo = QComboBox() - exclusive_group_combo.addItem("None", None) - self.cursor.execute('SELECT id, group_name FROM exclusive_encounter_groups') - for group_id, group_name in self.cursor.fetchall(): - exclusive_group_combo.addItem(group_name, group_id) - - layout.addRow("Exclusive Group:", exclusive_group_combo) + layout.addRow(exclusive_group_combo) # Fetch current values self.cursor.execute(''' - SELECT day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods, exclusive_group_id + SELECT day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods FROM encounters WHERE pfic = ? AND game = ? AND location = ? ''', (self.current_pfic, game, location)) current_values = self.cursor.fetchone() if current_values: - day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods, exclusive_group_id = current_values + day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, fishing, rods = current_values day_edit.setText(day or "") time_edit.setText(time or "") dual_slot_edit.setText(dual_slot or "") @@ -453,11 +576,11 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget UPDATE encounters SET game = ?, location = ?, day = ?, time = ?, dual_slot = ?, static_encounter = ?, static_encounter_count = ?, extra_text = ?, - stars = ?, fishing = ?, rods = ?, exclusive_group_id = ? + stars = ?, fishing = ?, rods = ? WHERE pfic = ? AND game = ? AND location = ? ''', (new_game, new_location, new_day, new_time, new_dual_slot, new_static_encounter, new_static_encounter_count, new_extra_text, - new_stars, new_fishing, new_rods, new_exclusive_group_id, + new_stars, new_fishing, new_rods, self.current_pfic, game, location)) self.conn.commit() @@ -524,14 +647,15 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget stars = stars_edit.text() or None fishing = fishing_check.isChecked() rods = rods_edit.text() or None - exclusive_group_id = exclusive_group_combo.currentData() + + game_id = event_system.call_sync('get_game_id_for_name', game) # Insert new encounter into the database self.cursor.execute(''' INSERT INTO encounters - (pfic, game, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods, exclusive_group_id) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - ''', (self.current_pfic, game, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods, exclusive_group_id)) + (pfic, game_id, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ''', (self.current_pfic, game_id, location, day, time, dual_slot, static_encounter, static_encounter_count, extra_text, stars, fishing, rods)) self.conn.commit() # Update the cache @@ -582,4 +706,48 @@ class PokemonUI(QWidget): # Change from QMainWindow to QWidget self.save_patches() # Refresh the evolution chain display - self.load_evolution_chain(self.current_pfic) \ No newline at end of file + self.load_evolution_chain(self.current_pfic) + + def show_pokemon_context_menu(self, position): + item = self.pokemon_list.itemAt(position) + if item is not None: + context_menu = QMenu(self) + refresh_action = QAction("Refresh Encounters", self) + refresh_action.triggered.connect(lambda: self.refresh_pokemon_encounters(item)) + context_menu.addAction(refresh_action) + context_menu.exec(self.pokemon_list.viewport().mapToGlobal(position)) + + def refresh_pokemon_encounters(self, item): + pfic = item.data(Qt.ItemDataRole.UserRole) + event_system.emit_sync('refresh_pokemon_encounters', pfic) + + def update_log_display(self, message): + if self.progress_text is not None: + self.progress_text.append(message) + #QMetaObject.invokeMethod(self.progress_text, "append", Qt.ConnectionType.QueuedConnection, message) + # Scroll to the bottom + scrollbar = self.progress_text.verticalScrollBar() + scrollbar.setValue(scrollbar.maximum()) + + def clear_log_display(self, data): + if self.progress_text is not None: + self.progress_text.clear() + # Reset scroll to top + scrollbar = self.progress_text.verticalScrollBar() + scrollbar.setValue(scrollbar.minimum()) + + def gather_pokemon_forms(self): + event_system.emit_sync('gather_pokemon_forms') + + def gather_home_storage_info(self): + event_system.emit_sync('gather_home_storage_info') + + def gather_evolution_info(self): + event_system.emit_sync('gather_evolution_info') + + def reinitialize_database(self): + event_system.emit_sync('reinitialize_database') + + def gather_encounter_info(self): + event_system.emit_sync('gather_encounter_info') + diff --git a/DBVisualiser/index.html b/DBVisualiser/index.html deleted file mode 100644 index 666470d..0000000 --- a/DBVisualiser/index.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - Pokémon Database Visualizer - - - -
-
- - -
- -
-
-
- -
    -
    -
    -

    Pokémon Details

    -
    -
    - Pokémon Image -
    -

    -

    -

    -

    -
    - - -
    -
    -
    -
    -

    Evolution Chain

    -
    - - -
    -
    -
    -
    -
    -
    -
    - - - -
    -
    -
    - -
      -
      -
      -
      -
      - - -
      -
      -
      -
      -
      - - - - - - - \ No newline at end of file diff --git a/DBVisualiser/main.js b/DBVisualiser/main.js deleted file mode 100644 index ee1bb9a..0000000 --- a/DBVisualiser/main.js +++ /dev/null @@ -1,200 +0,0 @@ -const { app, BrowserWindow, ipcMain } = require('electron'); -const path = require('path'); -const sqlite3 = require('sqlite3').verbose(); - -app.commandLine.appendSwitch('remote-debugging-port', '9222'); - -let mainWindow; -let db; - -function createWindow() { - mainWindow = new BrowserWindow({ - width: 1200, - height: 800, - webPreferences: { - nodeIntegration: true, - contextIsolation: false - } - }); - - mainWindow.loadFile('index.html'); - - db = new sqlite3.Database('../pokemon_forms.db', (err) => { - if (err) { - console.error('Database opening error: ', err); - } - }); -} - -app.whenReady().then(createWindow); - -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit(); - } -}); - -app.on('activate', () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); - } -}); - -ipcMain.on('load-forms-data', (event) => { - db.all(` - SELECT pf.PFIC, pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home - FROM pokemon_forms pf - LEFT JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC - `, (err, rows) => { - if (err) { - console.error('Error fetching data: ', err); - event.reply('forms-data-response', { error: err.message }); - } else { - event.reply('forms-data-response', { data: rows }); - } - }); -}); - -ipcMain.on('search-evolution', (event, searchTerm) => { - db.all(` - SELECT DISTINCT name, PFIC - FROM pokemon_forms - WHERE LOWER(name) LIKE ? - `, [`%${searchTerm.toLowerCase()}%`], (err, rows) => { - if (err) { - console.error('Error searching evolution: ', err); - event.reply('evolution-search-response', { error: err.message }); - } else { - event.reply('evolution-search-response', { data: rows }); - } - }); -}); - -ipcMain.on('get-evolution-chain', (event, pfic) => { - function getEvolutions(currentPfic) { - return new Promise((resolve, reject) => { - db.all(` - SELECT ec.to_pfic as pfic, pf.name, pf.form_name, ec.method, ec.from_pfic - FROM evolution_chains ec - JOIN pokemon_forms pf ON ec.to_pfic = pf.PFIC - WHERE ec.from_pfic = ? - `, [currentPfic], (err, rows) => { - if (err) { - reject(err); - } else { - resolve(rows); - } - }); - }); - } - - async function buildChain(pfic) { - const pokemon = await new Promise((resolve, reject) => { - db.get(`SELECT PFIC as pfic, name, form_name FROM pokemon_forms WHERE PFIC = ?`, [pfic], (err, row) => { - if (err) reject(err); - else resolve(row); - }); - }); - - if (!pokemon) return null; - - const evolutions = await getEvolutions(pfic); - pokemon.evolutions = await Promise.all(evolutions.map(evo => buildChain(evo.pfic))); - - return pokemon; - } - - buildChain(pfic) - .then(chain => { - event.reply('evolution-chain-response', { data: chain }); - }) - .catch(err => { - console.error('Error building evolution chain:', err); - event.reply('evolution-chain-response', { error: err.message }); - }); -}); - -ipcMain.on('edit-pokemon', (event, data) => { - // Implement the logic to update the Pokémon in the database - console.log('Editing Pokémon:', data); - // Update the database and send a response back to the renderer -}); - -ipcMain.on('remove-pokemon', (event, data) => { - // Implement the logic to remove the Pokémon from the evolution chain in the database - console.log('Removing Pokémon:', data); - // Update the database and send a response back to the renderer -}); - -ipcMain.on('add-stage', (event, data) => { - // Implement the logic to add a new stage to the evolution chain in the database - console.log('Adding new stage:', data); - // Update the database and send a response back to the renderer -}); - -ipcMain.on('save-evolution-changes', (event, data) => { - // Implement the logic to save all changes to the evolution chain in the database - console.log('Saving evolution changes:', data); - - // Here you would update the database with the new evolution chain data - // This is a placeholder implementation - setTimeout(() => { - event.reply('save-evolution-changes-response', { success: true }); - }, 1000); - - // If there's an error, you would reply with: - // event.reply('save-evolution-changes-response', { error: 'Error message' }); -}); - -// Add more IPC handlers for other database operations - -// Add this IPC handler -ipcMain.on('load-all-pokemon', (event) => { - db.all(` - SELECT PFIC, name, form_name - FROM pokemon_forms - ORDER BY - CAST(SUBSTR(PFIC, 1, 4) AS INTEGER), -- National Dex number - CAST(SUBSTR(PFIC, 6, 2) AS INTEGER), -- Region code - CAST(SUBSTR(PFIC, 9, 3) AS INTEGER), -- Form index - CAST(SUBSTR(PFIC, 13, 1) AS INTEGER) -- Gender code - `, (err, rows) => { - if (err) { - console.error('Error fetching all Pokémon:', err); - event.reply('all-pokemon-response', { error: err.message }); - } else { - event.reply('all-pokemon-response', { data: rows }); - } - }); -}); - -ipcMain.on('get-pokemon-details', (event, pfic) => { - db.get(` - SELECT pf.PFIC, pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home - FROM pokemon_forms pf - LEFT JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC - WHERE pf.PFIC = ? - `, [pfic], (err, row) => { - if (err) { - console.error('Error fetching Pokémon details:', err); - event.reply('pokemon-details-response', { error: err.message }); - } else { - event.reply('pokemon-details-response', { data: row }); - } - }); -}); - -ipcMain.on('update-storable-in-home', (event, data) => { - db.run(` - UPDATE pokemon_storage - SET storable_in_home = ? - WHERE PFIC = ? - `, [data.storable ? 1 : 0, data.pfic], (err) => { - if (err) { - console.error('Error updating storable in home:', err); - event.reply('update-storable-in-home-response', { error: err.message }); - } else { - event.reply('update-storable-in-home-response', { success: true }); - } - }); -}); \ No newline at end of file diff --git a/DBVisualiser/package-lock.json b/DBVisualiser/package-lock.json deleted file mode 100644 index 0dc455f..0000000 --- a/DBVisualiser/package-lock.json +++ /dev/null @@ -1,5193 +0,0 @@ -{ - "name": "dbvisualiser", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "dbvisualiser", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "electron": "^32.1.2", - "electron-builder": "^25.1.7", - "sqlite3": "^5.1.7" - } - }, - "node_modules/@develar/schema-utils": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", - "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", - "license": "MIT", - "dependencies": { - "ajv": "^6.12.0", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/@electron/asar": { - "version": "3.2.13", - "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.13.tgz", - "integrity": "sha512-pY5z2qQSwbFzJsBdgfJIzXf5ElHTVMutC2dxh0FD60njknMu3n1NnTABOcQwbb5/v5soqE79m9UjaJryBf3epg==", - "license": "MIT", - "dependencies": { - "@types/glob": "^7.1.0", - "commander": "^5.0.0", - "glob": "^7.1.6", - "minimatch": "^3.0.4" - }, - "bin": { - "asar": "bin/asar.js" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/@electron/asar/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@electron/asar/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@electron/get": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz", - "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "global-agent": "^3.0.0" - } - }, - "node_modules/@electron/notarize": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", - "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "fs-extra": "^9.0.1", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@electron/notarize/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/notarize/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/notarize/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@electron/osx-sign": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.1.tgz", - "integrity": "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==", - "license": "BSD-2-Clause", - "dependencies": { - "compare-version": "^0.1.2", - "debug": "^4.3.4", - "fs-extra": "^10.0.0", - "isbinaryfile": "^4.0.8", - "minimist": "^1.2.6", - "plist": "^3.0.5" - }, - "bin": { - "electron-osx-flat": "bin/electron-osx-flat.js", - "electron-osx-sign": "bin/electron-osx-sign.js" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@electron/osx-sign/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", - "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", - "license": "MIT", - "engines": { - "node": ">= 8.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/@electron/osx-sign/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/osx-sign/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@electron/rebuild": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.1.tgz", - "integrity": "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==", - "license": "MIT", - "dependencies": { - "@malept/cross-spawn-promise": "^2.0.0", - "chalk": "^4.0.0", - "debug": "^4.1.1", - "detect-libc": "^2.0.1", - "fs-extra": "^10.0.0", - "got": "^11.7.0", - "node-abi": "^3.45.0", - "node-api-version": "^0.2.0", - "node-gyp": "^9.0.0", - "ora": "^5.1.0", - "read-binary-file-arch": "^1.0.6", - "semver": "^7.3.5", - "tar": "^6.0.5", - "yargs": "^17.0.1" - }, - "bin": { - "electron-rebuild": "lib/cli.js" - }, - "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/@electron/rebuild/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron/rebuild/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/rebuild/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@electron/rebuild/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@electron/universal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.1.tgz", - "integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==", - "license": "MIT", - "dependencies": { - "@electron/asar": "^3.2.7", - "@malept/cross-spawn-promise": "^2.0.0", - "debug": "^4.3.1", - "dir-compare": "^4.2.0", - "fs-extra": "^11.1.1", - "minimatch": "^9.0.3", - "plist": "^3.1.0" - }, - "engines": { - "node": ">=16.4" - } - }, - "node_modules/@electron/universal/node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/@electron/universal/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/universal/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@electron/universal/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@malept/cross-spawn-promise": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", - "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/malept" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" - } - ], - "license": "Apache-2.0", - "dependencies": { - "cross-spawn": "^7.0.1" - }, - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/@malept/flatpak-bundler": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", - "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "fs-extra": "^9.0.0", - "lodash": "^4.17.15", - "tmp-promise": "^3.0.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@malept/flatpak-bundler/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@malept/flatpak-bundler/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "license": "ISC", - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "license": "MIT", - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "license": "MIT", - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "node_modules/@types/fs-extra": { - "version": "9.0.13", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", - "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", - "license": "MIT", - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", - "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", - "license": "MIT" - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/minimatch": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", - "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", - "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.16.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.10.tgz", - "integrity": "sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/@types/plist": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", - "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*", - "xmlbuilder": ">=11.0.1" - } - }, - "node_modules/@types/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/verror": { - "version": "1.10.10", - "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.10.tgz", - "integrity": "sha512-l4MM0Jppn18hb9xmM6wwD1uTdShpf9Pn80aXTStnK1C94gtPvJcV2FrDmbOQUAQfJ1cKZHktkQUDwEqaAKXMMg==", - "license": "MIT", - "optional": true - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.10", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", - "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/7zip-bin": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", - "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", - "license": "MIT" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "license": "ISC" - }, - "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "license": "MIT", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/app-builder-bin": { - "version": "5.0.0-alpha.10", - "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.10.tgz", - "integrity": "sha512-Ev4jj3D7Bo+O0GPD2NMvJl+PGiBAfS7pUGawntBNpCbxtpncfUixqFj9z9Jme7V7s3LBGqsWZZP54fxBX3JKJw==", - "license": "MIT" - }, - "node_modules/app-builder-lib": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-25.1.7.tgz", - "integrity": "sha512-JxmN+D/Dn7BLQoN+cTFO+zbMHcpI10v/xjyjFO1FKpHbApOG+OQt/xUyVjKWp4FYplIfuHdpxqTXo1PN/Wzm/A==", - "license": "MIT", - "dependencies": { - "@develar/schema-utils": "~2.6.5", - "@electron/notarize": "2.5.0", - "@electron/osx-sign": "1.3.1", - "@electron/rebuild": "3.6.1", - "@electron/universal": "2.0.1", - "@malept/flatpak-bundler": "^0.4.0", - "@types/fs-extra": "9.0.13", - "async-exit-hook": "^2.0.1", - "bluebird-lst": "^1.0.9", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "chromium-pickle-js": "^0.2.0", - "config-file-ts": "0.2.8-rc1", - "debug": "^4.3.4", - "dotenv": "^16.4.5", - "dotenv-expand": "^11.0.6", - "ejs": "^3.1.8", - "electron-publish": "25.1.7", - "form-data": "^4.0.0", - "fs-extra": "^10.1.0", - "hosted-git-info": "^4.1.0", - "is-ci": "^3.0.0", - "isbinaryfile": "^5.0.0", - "js-yaml": "^4.1.0", - "json5": "^2.2.3", - "lazy-val": "^1.0.5", - "minimatch": "^10.0.0", - "resedit": "^1.7.0", - "sanitize-filename": "^1.6.3", - "semver": "^7.3.8", - "tar": "^6.1.12", - "temp-file": "^3.4.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "dmg-builder": "25.1.7", - "electron-builder-squirrel-windows": "25.1.7" - } - }, - "node_modules/app-builder-lib/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/app-builder-lib/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/app-builder-lib/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/app-builder-lib/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "license": "ISC" - }, - "node_modules/archiver": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz", - "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==", - "license": "MIT", - "peer": true, - "dependencies": { - "archiver-utils": "^2.1.0", - "async": "^3.2.4", - "buffer-crc32": "^0.2.1", - "readable-stream": "^3.6.0", - "readdir-glob": "^1.1.2", - "tar-stream": "^2.2.0", - "zip-stream": "^4.1.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/archiver-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", - "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", - "license": "MIT", - "peer": true, - "dependencies": { - "glob": "^7.1.4", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^2.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/archiver-utils/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/archiver-utils/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT", - "peer": true - }, - "node_modules/archiver-utils/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, - "node_modules/async-exit-hook": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", - "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "license": "MIT" - }, - "node_modules/bluebird-lst": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", - "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", - "license": "MIT", - "dependencies": { - "bluebird": "^3.5.5" - } - }, - "node_modules/boolean": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", - "license": "MIT", - "optional": true - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT" - }, - "node_modules/builder-util": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-25.1.7.tgz", - "integrity": "sha512-7jPjzBwEGRbwNcep0gGNpLXG9P94VA3CPAZQCzxkFXiV2GMQKlziMbY//rXPI7WKfhsvGgFXjTcXdBEwgXw9ww==", - "license": "MIT", - "dependencies": { - "@types/debug": "^4.1.6", - "7zip-bin": "~5.2.0", - "app-builder-bin": "5.0.0-alpha.10", - "bluebird-lst": "^1.0.9", - "builder-util-runtime": "9.2.10", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "debug": "^4.3.4", - "fs-extra": "^10.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "is-ci": "^3.0.0", - "js-yaml": "^4.1.0", - "source-map-support": "^0.5.19", - "stat-mode": "^1.0.0", - "temp-file": "^3.4.0" - } - }, - "node_modules/builder-util-runtime": { - "version": "9.2.10", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz", - "integrity": "sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/builder-util/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/builder-util/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/builder-util/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "license": "MIT", - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "license": "MIT", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/chromium-pickle-js": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", - "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", - "license": "MIT" - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "license": "MIT", - "optional": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/compare-version": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", - "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/compress-commons": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz", - "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==", - "license": "MIT", - "peer": true, - "dependencies": { - "buffer-crc32": "^0.2.13", - "crc32-stream": "^4.0.2", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/config-file-ts": { - "version": "0.2.8-rc1", - "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.8-rc1.tgz", - "integrity": "sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==", - "license": "MIT", - "dependencies": { - "glob": "^10.3.12", - "typescript": "^5.4.3" - } - }, - "node_modules/config-file-ts/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/config-file-ts/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/config-file-ts/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "license": "ISC" - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "license": "MIT" - }, - "node_modules/crc": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", - "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "buffer": "^5.1.0" - } - }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/crc32-stream": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz", - "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==", - "license": "MIT", - "peer": true, - "dependencies": { - "crc-32": "^1.2.0", - "readable-stream": "^3.4.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", - "optional": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "license": "MIT", - "optional": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "license": "MIT", - "optional": true - }, - "node_modules/dir-compare": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", - "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", - "license": "MIT", - "dependencies": { - "minimatch": "^3.0.5", - "p-limit": "^3.1.0 " - } - }, - "node_modules/dir-compare/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/dir-compare/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/dmg-builder": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-25.1.7.tgz", - "integrity": "sha512-Hac0AfXQrAV62JT99Had6bvUJb/f7vjJTaLOsmA/gAQcrc/cLmNAqCJ0ZZDqwKy2+LKXnxx45TvMXvovKd4iMg==", - "license": "MIT", - "dependencies": { - "app-builder-lib": "25.1.7", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "fs-extra": "^10.1.0", - "iconv-lite": "^0.6.2", - "js-yaml": "^4.1.0" - }, - "optionalDependencies": { - "dmg-license": "^1.0.11" - } - }, - "node_modules/dmg-builder/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/dmg-builder/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/dmg-builder/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/dmg-license": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", - "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "@types/plist": "^3.0.1", - "@types/verror": "^1.10.3", - "ajv": "^6.10.0", - "crc": "^3.8.0", - "iconv-corefoundation": "^1.1.7", - "plist": "^3.0.4", - "smart-buffer": "^4.0.2", - "verror": "^1.10.0" - }, - "bin": { - "dmg-license": "bin/dmg-license.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dotenv-expand": { - "version": "11.0.6", - "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.6.tgz", - "integrity": "sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==", - "license": "BSD-2-Clause", - "dependencies": { - "dotenv": "^16.4.4" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron": { - "version": "32.1.2", - "resolved": "https://registry.npmjs.org/electron/-/electron-32.1.2.tgz", - "integrity": "sha512-CXe6doFzhmh1U7daOvUzmF6Cj8hssdYWMeEPRnRO6rB9/bbwMlWctcQ7P8NJXhLQ88/vYUJQrJvlJPh8qM0BRQ==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@electron/get": "^2.0.0", - "@types/node": "^20.9.0", - "extract-zip": "^2.0.1" - }, - "bin": { - "electron": "cli.js" - }, - "engines": { - "node": ">= 12.20.55" - } - }, - "node_modules/electron-builder": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-25.1.7.tgz", - "integrity": "sha512-lsKtX93GSHWnmuteNRvBzgJIjRiiYB0qrJVRjShwBi75Ns+mRdWeOGZiXItqOWj+3g5UyY722kgoq2WlqCB87A==", - "license": "MIT", - "dependencies": { - "app-builder-lib": "25.1.7", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "chalk": "^4.1.2", - "dmg-builder": "25.1.7", - "fs-extra": "^10.1.0", - "is-ci": "^3.0.0", - "lazy-val": "^1.0.5", - "simple-update-notifier": "2.0.0", - "yargs": "^17.6.2" - }, - "bin": { - "electron-builder": "cli.js", - "install-app-deps": "install-app-deps.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/electron-builder-squirrel-windows": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-25.1.7.tgz", - "integrity": "sha512-nJMvw1FNy+6YP8HmjSb0JwMowpdlZpydZGab9KevKO/fIC9wTcr5rkhbLsTfEPOjdAqOTycRoK0mOJCFB/1uig==", - "license": "MIT", - "peer": true, - "dependencies": { - "app-builder-lib": "25.1.7", - "archiver": "^5.3.1", - "builder-util": "25.1.7", - "fs-extra": "^10.1.0" - } - }, - "node_modules/electron-builder-squirrel-windows/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-builder-squirrel-windows/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/electron-builder-squirrel-windows/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/electron-builder/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-builder/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/electron-builder/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/electron-publish": { - "version": "25.1.7", - "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-25.1.7.tgz", - "integrity": "sha512-+jbTkR9m39eDBMP4gfbqglDd6UvBC7RLh5Y0MhFSsc6UkGHj9Vj9TWobxevHYMMqmoujL11ZLjfPpMX+Pt6YEg==", - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^9.0.11", - "builder-util": "25.1.7", - "builder-util-runtime": "9.2.10", - "chalk": "^4.1.2", - "fs-extra": "^10.1.0", - "lazy-val": "^1.0.5", - "mime": "^2.5.2" - } - }, - "node_modules/electron-publish/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/electron-publish/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/electron-publish/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "license": "MIT" - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "license": "MIT", - "optional": true - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "license": "Apache-2.0" - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extsprintf": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", - "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", - "engines": [ - "node >=0.6.0" - ], - "license": "MIT", - "optional": true - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "license": "MIT" - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT" - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT" - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/global-agent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/global-agent/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "license": "MIT", - "optional": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", - "optional": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "license": "ISC" - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "license": "BSD-2-Clause" - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "license": "MIT", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/iconv-corefoundation": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", - "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "cli-truncate": "^2.1.0", - "node-addon-api": "^1.6.3" - }, - "engines": { - "node": "^8.11.2 || >=10" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "license": "ISC" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "license": "MIT", - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "license": "MIT" - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT", - "peer": true - }, - "node_modules/isbinaryfile": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.2.tgz", - "integrity": "sha512-GvcjojwonMjWbTkfMpnVHVqXW/wKMYDfEpY94/8zy8HFMOqb/VL6oeONq9v87q4ttVlaTLnGXnJD4B5B1OTGIg==", - "license": "MIT", - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/gjtorikian/" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jake/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/jake/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "license": "ISC", - "optional": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/lazy-val": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", - "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", - "license": "MIT" - }, - "node_modules/lazystream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", - "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", - "license": "MIT", - "peer": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lazystream/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "peer": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/lazystream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT", - "peer": true - }, - "node_modules/lazystream/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "peer": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", - "license": "MIT", - "peer": true - }, - "node_modules/lodash.difference": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", - "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==", - "license": "MIT", - "peer": true - }, - "node_modules/lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", - "license": "MIT", - "peer": true - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "license": "MIT", - "peer": true - }, - "node_modules/lodash.union": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", - "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==", - "license": "MIT", - "peer": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "license": "MIT", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/matcher": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "license": "MIT", - "optional": true, - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mime": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", - "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "license": "MIT", - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-abi": { - "version": "3.68.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.68.0.tgz", - "integrity": "sha512-7vbj10trelExNjFSBm5kTvZXXa7pZyKWx9RCKIyqe6I9Ev3IzGpQoqBP3a+cOdxY+pWj6VkP28n/2wWysBHD/A==", - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", - "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", - "license": "MIT", - "optional": true - }, - "node_modules/node-api-version": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.0.tgz", - "integrity": "sha512-fthTTsi8CxaBXMaBAD7ST2uylwvsnYxh2PfaScwpMhos6KlSFajXQPcM4ogNE1q2s3Lbz9GCGqeIHC+C6OZnKg==", - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - } - }, - "node_modules/node-api-version/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "license": "ISC", - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "license": "ISC" - }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/pe-library": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", - "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", - "license": "MIT", - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" - }, - "node_modules/plist": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", - "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=10.4.0" - } - }, - "node_modules/prebuild-install": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", - "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT", - "peer": true - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "license": "ISC" - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pump": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/read-binary-file-arch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", - "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "bin": { - "read-binary-file-arch": "cli.js" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdir-glob": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", - "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "minimatch": "^5.1.0" - } - }, - "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resedit": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.1.tgz", - "integrity": "sha512-/FJ6/gKAXbcHtivannhecWsa43kGVFK3aHHv9Jm3x0eFiM31MoGihkAOWbm3UsvjYLRVw0zTkfARy2dI96JL1Q==", - "license": "MIT", - "dependencies": { - "pe-library": "^0.4.1" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/jet2jet" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "license": "MIT" - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "license": "MIT", - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/roarr": { - "version": "2.15.4", - "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/sanitize-filename": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", - "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", - "license": "WTFPL OR ISC", - "dependencies": { - "truncate-utf8-bytes": "^1.0.0" - } - }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "license": "ISC" - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", - "license": "MIT", - "optional": true - }, - "node_modules/serialize-error": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "license": "MIT", - "optional": true, - "dependencies": { - "type-fest": "^0.13.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/simple-update-notifier": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", - "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "license": "MIT", - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "license": "MIT", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause" - }, - "node_modules/sqlite3": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", - "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "bindings": "^1.5.0", - "node-addon-api": "^7.0.0", - "prebuild-install": "^7.1.1", - "tar": "^6.1.11" - }, - "optionalDependencies": { - "node-gyp": "8.x" - }, - "peerDependencies": { - "node-gyp": "8.x" - }, - "peerDependenciesMeta": { - "node-gyp": { - "optional": true - } - } - }, - "node_modules/sqlite3/node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/sqlite3/node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "license": "MIT", - "optional": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sqlite3/node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/sqlite3/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/sqlite3/node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/sqlite3/node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "license": "MIT", - "optional": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/sqlite3/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/sqlite3/node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "license": "ISC", - "optional": true, - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/sqlite3/node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "license": "MIT", - "optional": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/sqlite3/node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "license": "MIT" - }, - "node_modules/sqlite3/node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "license": "MIT", - "optional": true, - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/sqlite3/node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/sqlite3/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sqlite3/node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/sqlite3/node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/sqlite3/node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/sqlite3/node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "license": "ISC", - "optional": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "license": "ISC", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/stat-mode": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", - "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sumchecker": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", - "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", - "license": "Apache-2.0", - "dependencies": { - "debug": "^4.1.0" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC" - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/temp-file": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", - "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", - "license": "MIT", - "dependencies": { - "async-exit-hook": "^2.0.1", - "fs-extra": "^10.0.0" - } - }, - "node_modules/temp-file/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/temp-file/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/temp-file/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tmp-promise": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", - "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", - "license": "MIT", - "dependencies": { - "tmp": "^0.2.0" - } - }, - "node_modules/truncate-utf8-bytes": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", - "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", - "license": "WTFPL", - "dependencies": { - "utf8-byte-length": "^1.0.1" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "license": "(MIT OR CC0-1.0)", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - }, - "node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "license": "ISC", - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/utf8-byte-length": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", - "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", - "license": "(WTFPL OR MIT)" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/verror": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", - "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", - "license": "MIT", - "optional": true, - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zip-stream": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", - "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "archiver-utils": "^3.0.4", - "compress-commons": "^4.1.2", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/zip-stream/node_modules/archiver-utils": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz", - "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==", - "license": "MIT", - "peer": true, - "dependencies": { - "glob": "^7.2.3", - "graceful-fs": "^4.2.0", - "lazystream": "^1.0.0", - "lodash.defaults": "^4.2.0", - "lodash.difference": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.isplainobject": "^4.0.6", - "lodash.union": "^4.6.0", - "normalize-path": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">= 10" - } - } - } -} diff --git a/DBVisualiser/package.json b/DBVisualiser/package.json deleted file mode 100644 index cdfa063..0000000 --- a/DBVisualiser/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "dbvisualiser", - "version": "1.0.0", - "main": "main.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "electron . --inspect=5858" - }, - "keywords": [], - "author": "", - "license": "ISC", - "description": "", - "dependencies": { - "electron": "^32.1.2", - "electron-builder": "^25.1.7", - "sqlite3": "^5.1.7" - } - -} diff --git a/DBVisualiser/pokemon_forms.db b/DBVisualiser/pokemon_forms.db deleted file mode 100644 index e69de29..0000000 diff --git a/DBVisualiser/renderer.js b/DBVisualiser/renderer.js deleted file mode 100644 index b5cd962..0000000 --- a/DBVisualiser/renderer.js +++ /dev/null @@ -1,483 +0,0 @@ -const { ipcRenderer } = require('electron'); - -// Add these variables at the top of the file -let currentEditingStageIndex, currentEditingPokemonIndex; -let allPokemon = []; // This will store all Pokémon for the select dropdown -let currentEvolutionChain = null; // Add this line -let allPokemonForms = []; - -document.addEventListener('DOMContentLoaded', () => { - loadFormsData(); - setupTabButtons(); - setupSearchButtons(); - setupSaveChangesButton(); - - const modal = document.getElementById('edit-pokemon-modal'); - const closeBtn = modal.querySelector('.close'); - const form = document.getElementById('edit-pokemon-form'); - - closeBtn.onclick = () => { - modal.style.display = 'none'; - }; - - window.onclick = (event) => { - if (event.target === modal) { - modal.style.display = 'none'; - } - }; - - form.onsubmit = (e) => { - e.preventDefault(); - const newPfic = document.getElementById('pokemon-select').value; - const newMethod = document.getElementById('evolution-method').value; - updatePokemonInChain(currentEditingStageIndex, currentEditingPokemonIndex, newPfic, newMethod); - modal.style.display = 'none'; - }; - - loadAllPokemon(); - setupPokemonFilter(); -}); - -function setupTabButtons() { - const tabButtons = document.querySelectorAll('.tab-button'); - tabButtons.forEach(button => { - button.addEventListener('click', () => { - const tabName = button.getAttribute('data-tab'); - activateTab(tabName); - }); - }); -} - -function activateTab(tabName) { - document.querySelectorAll('.tab-button').forEach(btn => btn.classList.remove('active')); - document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active')); - - document.querySelector(`.tab-button[data-tab="${tabName}"]`).classList.add('active'); - document.getElementById(`${tabName}-tab`).classList.add('active'); -} - -function setupSearchButtons() { - //document.getElementById('forms-search-button').addEventListener('click', searchForms); - //document.getElementById('evolution-search-button').addEventListener('click', searchEvolution); -} - -function setupSaveChangesButton() { - //document.getElementById('save-changes').addEventListener('click', saveChanges); -} - -function loadFormsData() { - ipcRenderer.send('load-all-pokemon'); -} - -ipcRenderer.on('all-pokemon-response', (event, response) => { - if (response.error) { - console.error('Error loading all Pokémon:', response.error); - } else { - allPokemonForms = response.data; - populateFormsList(); - setupFormsFilter(); - } -}); - -function populateFormsList() { - const listElement = document.getElementById('forms-list-items'); - listElement.innerHTML = ''; - allPokemonForms.forEach(pokemon => { - const li = document.createElement('li'); - li.textContent = `${pokemon.name} ${pokemon.form_name ? `(${pokemon.form_name})` : ''}`; - li.addEventListener('click', () => showPokemonDetails(pokemon.PFIC)); - listElement.appendChild(li); - }); -} - -function setupFormsFilter() { - const filterInput = document.getElementById('forms-filter'); - filterInput.addEventListener('input', () => { - const filterValue = filterInput.value.toLowerCase(); - const listItems = document.querySelectorAll('#forms-list-items li'); - listItems.forEach(item => { - const text = item.textContent.toLowerCase(); - item.style.display = text.includes(filterValue) ? '' : 'none'; - }); - }); -} - -function showPokemonDetails(pfic) { - ipcRenderer.send('get-pokemon-details', pfic); -} - -ipcRenderer.on('pokemon-details-response', (event, response) => { - if (response.error) { - console.error('Error fetching Pokémon details:', response.error); - } else { - displayPokemonDetails(response.data); - } -}); - -function displayPokemonDetails(pokemon) { - const detailsContent = document.getElementById('details-content'); - const pokemonImage = document.getElementById('pokemon-image'); - const pokemonName = document.getElementById('pokemon-name'); - const pokemonPfic = document.getElementById('pokemon-pfic'); - const pokemonNationalDex = document.getElementById('pokemon-national-dex'); - const pokemonGeneration = document.getElementById('pokemon-generation'); - const storableCheckbox = document.getElementById('storable-checkbox'); - const evolutionChainContent = document.getElementById('details-evolution-chain-content'); - - pokemonImage.src = `../images-new/${pokemon.PFIC}.png`; - pokemonImage.onerror = () => { pokemonImage.src = 'placeholder.png'; }; - - pokemonName.textContent = `${pokemon.name} ${pokemon.form_name ? `(${pokemon.form_name})` : ''}`; - pokemonPfic.textContent = `PFIC: ${pokemon.PFIC}`; - pokemonNationalDex.textContent = `National Dex: ${pokemon.national_dex.toString().padStart(4, '0')}`; - pokemonGeneration.textContent = `Generation: ${pokemon.generation}`; - - storableCheckbox.checked = pokemon.storable_in_home; - storableCheckbox.addEventListener('change', () => updateStorableInHome(pokemon.PFIC, storableCheckbox.checked)); - - // Load and display evolution chain - loadEvolutionChain(pokemon.PFIC); -} - -function updateStorableInHome(pfic, storable) { - ipcRenderer.send('update-storable-in-home', { pfic, storable }); -} - -function loadEvolutionChain(pfic) { - ipcRenderer.send('get-evolution-chain', pfic); -} - -ipcRenderer.on('evolution-chain-response', (event, response) => { - if (response.error) { - console.error('Error fetching evolution chain:', response.error); - } else { - displayEvolutionChain(response.data); - } -}); - -function displayEvolutionChain(chain) { - const table = document.getElementById('evolution-table'); - table.innerHTML = ''; - - const stages = splitIntoStages(chain); - const maxForms = Math.max(...stages.map(stage => stage.length)); - const rowCount = maxForms % 2 === 0 ? maxForms + 1 : maxForms; - const middleRow = Math.floor(rowCount / 2) - - for (let i = 0; i < rowCount; i++) { - const row = table.insertRow(); - for (let j = 0; j < stages.length; j++) { - const cell = row.insertCell(); - } - } - - stages.forEach((stage, stageIndex) => { - if (stage.length == 1) - { - const pokemon = stage[0]; - table.rows[middleRow].cells[stageIndex].appendChild(createPokemonElement(pokemon)); - } else { - let start = middleRow - Math.floor(stage.length / 2) - - stage.forEach((pokemon, index) => { - let rowIndex = start + index; - - // If the number of elements is even, skip the middle row - if (stage.length % 2 === 0 && rowIndex >= middleRow) { - rowIndex++; - } - - table.rows[rowIndex].cells[stageIndex].appendChild(createPokemonElement(pokemon)); - }); - } - }); -} - -function createPokemonElement(pokemon) { - const element = document.createElement('div'); - element.className = 'pokemon-card'; - - const img = document.createElement('img'); - img.src = `../images-new/${pokemon.pfic}.png`; - img.alt = pokemon.name; - img.onerror = () => { img.src = 'placeholder.png'; }; - - const name = document.createElement('div'); - name.className = 'pokemon-name'; - name.textContent = pokemon.name; - - const form = document.createElement('div'); - form.className = 'pokemon-form'; - form.textContent = pokemon.form_name || ''; - - element.appendChild(img); - element.appendChild(name); - element.appendChild(form); - - return element; -} - -function createEvolutionArrow() { - const arrow = document.createElement('div'); - arrow.className = 'evolution-arrow'; - arrow.textContent = '→'; - return arrow; -} - -function createBranchElement(evolutions) { - const branchElement = document.createElement('div'); - branchElement.className = 'evolution-branch'; - const arrowElement = document.createElement('span'); - arrowElement.className = 'evolution-arrow'; - arrowElement.textContent = '→'; - branchElement.appendChild(arrowElement); - const methodElement = document.createElement('span'); - methodElement.className = 'evolution-method'; - methodElement.textContent = evolutions[0].method || ''; - branchElement.appendChild(methodElement); - return branchElement; -} - -function searchForms() { - const searchTerm = document.getElementById('forms-search').value.toLowerCase(); - const rows = document.querySelectorAll('#forms-table tbody tr'); - - rows.forEach(row => { - const text = row.textContent.toLowerCase(); - row.style.display = text.includes(searchTerm) ? '' : 'none'; - }); -} - -function searchEvolution() { - const searchTerm = document.getElementById('evolution-search').value; - ipcRenderer.send('search-evolution', searchTerm); -} - -ipcRenderer.on('evolution-search-response', (event, response) => { - if (response.error) { - console.error('Error searching evolution:', response.error); - } else if (response.data.length > 0) { - const pfic = response.data[0].PFIC; - ipcRenderer.send('get-evolution-chain', pfic); - } else { - document.getElementById('evolution-chain').innerHTML = 'No Pokémon found.'; - } -}); - -ipcRenderer.on('evolution-chain-response', (event, response) => { - if (response.error) { - console.error('Error fetching evolution chain:', response.error); - } else { - currentEvolutionChain = response.data; // Add this line - displayEvolutionChain(currentEvolutionChain); - } -}); - -function createPokemonElement(pokemon, stageIndex, pokemonIndex) { - const element = document.createElement('div'); - element.className = 'pokemon-card'; - - const img = document.createElement('img'); - img.src = `../images-new/${pokemon.pfic}.png`; - img.alt = pokemon.name; - img.onerror = () => { img.src = 'placeholder.png'; }; - - const name = document.createElement('div'); - name.className = 'pokemon-name'; - name.textContent = pokemon.name; - - const form = document.createElement('div'); - form.className = 'pokemon-form'; - form.textContent = pokemon.form_name || ''; - - const editButton = document.createElement('button'); - editButton.textContent = 'Edit'; - editButton.className = 'edit-pokemon'; - editButton.addEventListener('click', () => editPokemon(stageIndex, pokemonIndex)); - - const editButtons = document.createElement('div'); - editButtons.className = 'edit-buttons'; - editButtons.appendChild(editButton); - - element.appendChild(img); - element.appendChild(name); - element.appendChild(form); - element.appendChild(editButtons); - - return element; -} - -function setupEvolutionControls() { - document.getElementById('add-stage').addEventListener('click', addStage); - document.getElementById('save-evolution-changes').addEventListener('click', saveEvolutionChanges); -} - -function editPokemon(stageIndex, pokemonIndex) { - console.log('Editing Pokemon:', stageIndex, pokemonIndex); - if (!currentEvolutionChain) { - console.error('No evolution chain loaded'); - return; - } - currentEditingStageIndex = stageIndex; - currentEditingPokemonIndex = pokemonIndex; - - const modal = document.getElementById('edit-pokemon-modal'); - console.log('Modal element:', modal); - const pokemonSelect = document.getElementById('pokemon-select'); - const evolutionMethod = document.getElementById('evolution-method'); - - // Set current values - const currentPokemon = getCurrentPokemon(stageIndex, pokemonIndex); - console.log('Current Pokemon:', currentPokemon); - if (currentPokemon) { - pokemonSelect.value = currentPokemon.pfic; - evolutionMethod.value = currentPokemon.method || ''; - - modal.style.display = 'block'; - console.log('Modal display set to block'); - } else { - console.error('Could not find the current Pokémon'); - } -} - -function removePokemon(stageIndex, pokemonIndex) { - // Implement remove functionality - console.log(`Removing Pokémon at stage ${stageIndex}, index ${pokemonIndex}`); - // Remove the Pokémon from the DOM and update the data structure -} - -function addStage() { - // Implement add stage functionality - console.log('Adding new stage'); - // You can open a modal or inline form to add a new stage -} - -function saveEvolutionChanges() { - console.log('Saving evolution changes'); - ipcRenderer.send('save-evolution-changes', currentEvolutionChain); -} - -function splitIntoStages(chain) { - const stages = []; - let currentStage = [chain]; - - while (currentStage.length > 0) { - stages.push(currentStage); - const nextStage = []; - currentStage.forEach(pokemon => { - nextStage.push(...pokemon.evolutions); - }); - currentStage = nextStage; - } - - return stages; -} - -function saveChanges() { - // Implement the logic to save changes - // This will involve collecting the data from the forms table - // and sending it back to the main process to update the database -} - -// Add this function to load all Pokémon -function loadAllPokemon() { - ipcRenderer.send('load-all-pokemon'); -} - -// Add this event listener -ipcRenderer.on('all-pokemon-response', (event, response) => { - if (response.error) { - console.error('Error loading all Pokémon:', response.error); - } else { - allPokemon = response.data; - populatePokemonSelect(); - populatePokemonList(); - } -}); - -// Add this function to populate the Pokémon select dropdown -function populatePokemonSelect() { - const select = document.getElementById('pokemon-select'); - select.innerHTML = ''; - allPokemon.forEach(pokemon => { - const option = document.createElement('option'); - option.value = pokemon.PFIC; - option.textContent = `${pokemon.PFIC} - ${pokemon.name} ${pokemon.form_name ? `(${pokemon.form_name})` : ''}`; - select.appendChild(option); - }); -} - -// Add this function to get the current Pokémon being edited -function getCurrentPokemon(stageIndex, pokemonIndex) { - if (!currentEvolutionChain) { - console.error('No evolution chain loaded'); - return null; - } - const stages = splitIntoStages(currentEvolutionChain); - if (stageIndex < 0 || stageIndex >= stages.length || pokemonIndex < 0 || pokemonIndex >= stages[stageIndex].length) { - console.error('Invalid stage or pokemon index'); - return null; - } - return stages[stageIndex][pokemonIndex]; -} - -// Add this function to update the Pokémon in the chain -function updatePokemonInChain(stageIndex, pokemonIndex, newPfic, newMethod) { - const stages = splitIntoStages(currentEvolutionChain); - const pokemon = stages[stageIndex][pokemonIndex]; - - // Update the Pokémon data - pokemon.pfic = newPfic; - pokemon.name = allPokemon.find(p => p.PFIC === newPfic).name; - pokemon.form_name = allPokemon.find(p => p.PFIC === newPfic).form_name; - - // Update the evolution method if it's not the first stage - if (stageIndex > 0) { - const previousStagePokemon = stages[stageIndex - 1].find(p => p.evolutions.includes(pokemon)); - const evolutionIndex = previousStagePokemon.evolutions.indexOf(pokemon); - previousStagePokemon.evolutions[evolutionIndex].method = newMethod; - } - - // Redisplay the evolution chain - displayEvolutionChain(currentEvolutionChain); -} - -// Add this event listener for the save response -ipcRenderer.on('save-evolution-changes-response', (event, response) => { - if (response.error) { - console.error('Error saving evolution changes:', response.error); - alert('Failed to save changes. Please try again.'); - } else { - alert('Changes saved successfully!'); - } -}); - -// Add this function to populate the Pokémon list -function populatePokemonList() { - const listElement = document.getElementById('pokemon-list-items'); - listElement.innerHTML = ''; - allPokemon.forEach(pokemon => { - const li = document.createElement('li'); - li.textContent = `${pokemon.name} ${pokemon.form_name ? `(${pokemon.form_name})` : ''}`; - li.addEventListener('click', () => loadEvolutionChain(pokemon.PFIC)); - listElement.appendChild(li); - }); -} - -// Add this function to set up the Pokémon filter -function setupPokemonFilter() { - const filterInput = document.getElementById('pokemon-filter'); - filterInput.addEventListener('input', () => { - const filterValue = filterInput.value.toLowerCase(); - const listItems = document.querySelectorAll('#pokemon-list-items li'); - listItems.forEach(item => { - const text = item.textContent.toLowerCase(); - item.style.display = text.includes(filterValue) ? '' : 'none'; - }); - }); -} - -// Modify the loadEvolutionChain function -function loadEvolutionChain(pfic) { - ipcRenderer.send('get-evolution-chain', pfic); -} \ No newline at end of file diff --git a/DBVisualiser/styles.css b/DBVisualiser/styles.css deleted file mode 100644 index 91d3ccf..0000000 --- a/DBVisualiser/styles.css +++ /dev/null @@ -1,338 +0,0 @@ -body { - font-family: Arial, sans-serif; - margin: 0; - padding: 20px; -} - -#tabs { - margin-bottom: 20px; -} - -.tab-button { - padding: 10px 20px; - cursor: pointer; -} - -.tab-button.active { - background-color: #ddd; -} - -.tab-content { - display: none; -} - -.tab-content.active { - display: block; -} - -.search-bar { - margin-bottom: 20px; -} - -table { - width: 100%; - border-collapse: collapse; -} - -th, td { - border: 1px solid #ddd; - padding: 8px; - text-align: left; -} - -th { - background-color: #f2f2f2; -} - -#evolution-chain { - display: flex; - overflow-x: auto; - padding: 20px; - align-items: flex-start; -} - -.evolution-stage { - display: flex; - flex-direction: column; - align-items: center; - margin-right: 40px; -} - -.pokemon-card { - background-color: #f9f9f9; - border: 1px solid #ddd; - border-radius: 10px; - padding: 10px; - text-align: center; - display: flex; - flex-direction: column; - align-items: center; - justify-content: space-between; - cursor: pointer; - width: 120px; /* Fixed width */ - height: 100px; /* Fixed height */ -} - -.pokemon-card img { - width: 64px; - height: 64px; - object-fit: contain; -} - -.pokemon-name { - font-weight: bold; - margin-top: 5px; -} - -.pokemon-form { - font-size: 0.8em; - color: #666; -} - -.evolution-branch { - position: absolute; - top: 50%; - left: 100%; - display: flex; - flex-direction: column; - align-items: center; -} - -.evolution-arrow { - font-size: 24px; - color: #666; - margin: 0 10px; -} - -.evolution-method { - font-size: 0.8em; - color: #666; - max-width: 100px; - text-align: center; -} - -.pokemon-card .edit-buttons { - display: none; - position: absolute; - top: 5px; - right: 5px; -} - -.pokemon-card:hover .edit-buttons { - display: block; -} - -.edit-buttons button { - margin-left: 5px; - padding: 2px 5px; - font-size: 0.8em; -} - -#evolution-controls { - margin-top: 20px; -} - -#evolution-controls button { - margin-right: 10px; -} - -/* Add these styles at the end of the file */ -.modal { - display: none; - position: fixed; - z-index: 1; - left: 0; - top: 0; - width: 100%; - height: 100%; - overflow: auto; - background-color: rgba(0,0,0,0.4); -} - -.modal-content { - background-color: #fefefe; - margin: 15% auto; - padding: 20px; - border: 1px solid #888; - width: 80%; - max-width: 500px; -} - -.close { - color: #aaa; - float: right; - font-size: 28px; - font-weight: bold; - cursor: pointer; -} - -.close:hover, -.close:focus { - color: black; - text-decoration: none; - cursor: pointer; -} - -#edit-pokemon-form { - display: flex; - flex-direction: column; -} - -#edit-pokemon-form label, -#edit-pokemon-form select, -#edit-pokemon-form input, -#edit-pokemon-form button { - margin-top: 10px; -} - -.evolution-container { - display: flex; - height: calc(100vh - 100px); /* Adjust based on your layout */ -} - -#pokemon-list { - width: 250px; - border-right: 1px solid #ccc; - overflow-y: auto; - padding: 10px; -} - -#pokemon-filter { - width: 100%; - margin-bottom: 10px; -} - -#pokemon-list-items { - list-style-type: none; - padding: 0; -} - -#pokemon-list-items li { - cursor: pointer; - padding: 5px; -} - -#pokemon-list-items li:hover { - background-color: #f0f0f0; -} - -#evolution-chain-container { - flex-grow: 1; - padding: 20px; - overflow-y: auto; -} - -.forms-container { - display: flex; - height: calc(100vh - 100px); /* Adjust based on your layout */ -} - -#pokemon-forms-list { - width: 250px; - border-right: 1px solid #ccc; - overflow-y: auto; - padding: 10px; -} - -#forms-filter { - width: 100%; - margin-bottom: 10px; -} - -#forms-list-items { - list-style-type: none; - padding: 0; -} - -#forms-list-items li { - cursor: pointer; - padding: 5px; -} - -#forms-list-items li:hover { - background-color: #f0f0f0; -} - -#pokemon-details { - flex-grow: 1; - padding: 20px; - overflow-y: auto; -} - -#details-content { - margin-top: 20px; -} - -#pokemon-basic-info { - display: flex; - margin-bottom: 20px; -} - -#pokemon-image { - width: 200px; - height: 200px; - object-fit: contain; - margin-right: 20px; -} - -#pokemon-info { - flex-grow: 1; -} - -#pokemon-evolution-chain { - margin-top: 20px; -} - -#details-evolution-chain-content { - overflow-x: auto; - margin-top: 20px; -} - -#evolution-table { - width: auto; - border-collapse: collapse; - border-spacing: 0px; -} - -#evolution-table td { - vertical-align: middle; - text-align: center; - padding: 0%; - border-color: transparent; -} - -#details-evolution-chain-content .evolution-stage { - display: inline-flex; - flex-direction: row; - justify-content: flex-start; - align-items: center; - margin-right: 20px; -} - -#details-evolution-chain-content .pokemon-card { - text-align: center; - margin: 0 10px; - position: relative; - border: 1px solid #ddd; - padding: 10px; - border-radius: 5px; - display: inline-block; -} - -#details-evolution-chain-content .pokemon-card img { - width: 64px; - height: 64px; - object-fit: contain; -} - -#details-evolution-chain-content .evolution-branch { - display: inline-flex; - flex-direction: row; - align-items: center; - margin: 0 10px; -} - -#details-evolution-chain-content .evolution-arrow, -#details-evolution-chain-content .evolution-method { - margin: 0 5px; -} \ No newline at end of file diff --git a/DataGatherers/DatabaseBuilder.py b/DataGatherers/DatabaseBuilder.py deleted file mode 100644 index 1f372ee..0000000 --- a/DataGatherers/DatabaseBuilder.py +++ /dev/null @@ -1,401 +0,0 @@ -import sqlite3 -import csv -import re - -def create_connection(): - conn = sqlite3.connect('pokemon_database.db') - conn.text_factory = str - return conn - -def create_tables(conn): - cursor = conn.cursor() - - # Create games table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS games ( - id INTEGER PRIMARY KEY, - name TEXT NOT NULL, - generation INTEGER NOT NULL - ) - ''') - - # Create marks table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS marks ( - id INTEGER PRIMARY KEY, - name TEXT NOT NULL, - icon_path TEXT NOT NULL - ) - ''') - - # Create mark_game_associations table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS mark_game_associations ( - mark_id INTEGER, - game_id INTEGER, - FOREIGN KEY (mark_id) REFERENCES marks (id), - FOREIGN KEY (game_id) REFERENCES games (id), - PRIMARY KEY (mark_id, game_id) - ) - ''') - - # Create pokemon table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS pokemon ( - national_dex_number INTEGER PRIMARY KEY, - name TEXT NOT NULL, - introduced_in_gen INTEGER - ) - ''') - - # Create pokemon_forms table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS pokemon_forms ( - id INTEGER PRIMARY KEY, - pokemon_id INTEGER NOT NULL, - form_name TEXT NOT NULL, - is_default BOOLEAN NOT NULL, - image_path TEXT NOT NULL, - FOREIGN KEY (pokemon_id) REFERENCES pokemon (national_dex_number), - UNIQUE (pokemon_id, form_name) - ) - ''') - - # Create encounter_methods table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS encounter_methods ( - id INTEGER PRIMARY KEY, - name TEXT UNIQUE NOT NULL - ) - ''') - - # Create locations table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS locations ( - id INTEGER PRIMARY KEY, - name TEXT UNIQUE NOT NULL, - description TEXT - ) - ''') - - # Create form_encounters table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS form_encounters ( - id INTEGER PRIMARY KEY, - form_id INTEGER NOT NULL, - game_id INTEGER NOT NULL, - location_id INTEGER NOT NULL, - encounter_method_id INTEGER NOT NULL, - FOREIGN KEY (form_id) REFERENCES pokemon_forms (id), - FOREIGN KEY (game_id) REFERENCES games (id), - FOREIGN KEY (location_id) REFERENCES locations (id), - FOREIGN KEY (encounter_method_id) REFERENCES encounter_methods (id), - UNIQUE (form_id, game_id, location_id, encounter_method_id) - ) - ''') - - # Create alternate_game_names table - cursor.execute(''' - CREATE TABLE IF NOT EXISTS alternate_game_names ( - id INTEGER PRIMARY KEY, - game_id INTEGER NOT NULL, - alternate_name TEXT NOT NULL, - FOREIGN KEY (game_id) REFERENCES games (id), - UNIQUE (alternate_name COLLATE NOCASE) - ) - ''') - - conn.commit() - -def tidy_location_name(name): - # Replace '-' with spaces - name = name.replace('-', ' ') - - name = name.replace('#', '') - - # Remove 'area' from the end if present - name = re.sub(r'\sarea$', '', name, flags=re.IGNORECASE) - - # Check for cardinal directions at the end - cardinal_directions = ['north', 'south', 'east', 'west', 'northeast', 'northwest', 'southeast', 'southwest'] - for direction in cardinal_directions: - if name.lower().endswith(f' {direction}'): - # Remove the direction from the end and add it in brackets - name = name[:-len(direction)].strip() - name += f' ({direction.capitalize()})' - break - - if name.isdigit(): - name = "Route " + name - - name = name.replace("Routes", "Route") - - # Capitalize the first letter of the first word - name = name.capitalize() - - return name - -def generate_location_description(name): - # Generate a simple description based on the name - description = f"A location in the Pokémon world known as {name}." - return description - -def load_game_data(conn): - cursor = conn.cursor() - - games = [ - ("Red", 1, ["Red Version"]), - ("Blue", 1, ["Blue Version"]), - ("Yellow", 1, ["Yellow Version"]), - ("Gold", 2, ["Gold Version"]), - ("Silver", 2, ["Silver Version"]), - ("Crystal", 2, ["Crystal Version"]), - ("Ruby", 3, ["Ruby Version"]), - ("Sapphire", 3, ["Sapphire Version"]), - ("Emerald", 3, ["Emerald Version"]), - ("FireRed", 3, ["Fire Red", "Fire-Red"]), - ("LeafGreen", 3, ["Leaf Green", "Leaf-Green"]), - ("Diamond", 4, ["Diamond Version"]), - ("Pearl", 4, ["Pearl Version"]), - ("Platinum", 4, ["Platinum Version"]), - ("HeartGold", 4, ["Heart Gold", "Heart-Gold"]), - ("SoulSilver", 4, ["Soul Silver", "Soul-Silver"]), - ("Black", 5, ["Black Version"]), - ("White", 5, ["White Version"]), - ("Black 2", 5, ["Black Version 2", "Black-2"]), - ("White 2", 5, ["White Version 2", "White-2"]), - ("X", 6, ["X Version"]), - ("Y", 6, ["Y Version"]), - ("Omega Ruby", 6, ["Omega Ruby Version", "Omega-Ruby"]), - ("Alpha Sapphire", 6, ["Alpha Sapphire Version", "Alpha-Sapphire"]), - ("Sun", 7, ["Sun Version"]), - ("Moon", 7, ["Moon Version"]), - ("Ultra Sun", 7, ["Ultra Sun Version", "Ultra-Sun"]), - ("Ultra Moon", 7, ["Ultra Moon Version", "Ultra-Moon"]), - ("Let's Go Pikachu", 7, ["Let's Go, Pikachu!", "Lets Go Pikachu"]), - ("Let's Go Eevee", 7, ["Let's Go, Eevee!", "Lets Go Eevee"]), - ("Sword", 8, ["Sword Version"]), - ("Shield", 8, ["Shield Version"]), - ("Expansion Pass", 8, ["Expansion Pass (Sword)", "Expansion Pass (Shield)"]), - ("Brilliant Diamond", 8, ["Brilliant Diamond Version", "Brilliant-Diamond"]), - ("Shining Pearl", 8, ["Shining Pearl Version", "Shining-Pearl"]), - ("Legends Arceus", 8, ["Legends: Arceus", "Legends-Arceus"]), - ("Scarlet", 9, ["Scarlet Version"]), - ("Violet", 9, ["Violet Version"]), - ("The Teal Mask", 9, ["The Teal Mask Version", "The Teal Mask (Scarlet)", "The Teal Mask (Violet)"]), - ("The Hidden Treasure of Area Zero", 9, ["The Hidden Treasure of Area Zero Version", "The Hidden Treasure of Area Zero (Scarlet)", "The Hidden Treasure of Area Zero (Violet)"]), - - ("Pokémon Home", 98, ["Pokémon HOME"]), - ("Pokémon Go", 99, ["Pokémon GO"]), - ] - - for game in games: - cursor.execute(''' - INSERT OR IGNORE INTO games (name, generation) - VALUES (?, ?) - ''', (game[0], game[1])) - - game_id = cursor.lastrowid - - # Insert alternate names - for alt_name in game[2]: - cursor.execute(''' - INSERT OR IGNORE INTO alternate_game_names (game_id, alternate_name) - VALUES (?, ?) - ''', (game_id, alt_name)) - - conn.commit() - -def load_mark_data(conn): - cursor = conn.cursor() - - marks = [ - ("Game Boy", "images/marks/GB_icon_HOME.png", ["Red", "Blue", "Yellow", "Gold", "Silver", "Crystal", "Ruby", "Sapphire", "Emerald", "FireRed", "LeafGreen"]), - ("Kalos", "images/marks/Blue_pentagon_HOME.png", ["X", "Y", "Omega Ruby", "Alpha Sapphire"]), - ("Alola", "images/marks/Black_clover_HOME.png", ["Sun", "Moon", "Ultra Sun", "Ultra Moon"]), - ("Let's Go", "images/marks/Let's_Go_icon_HOME.png", ["Let's Go Pikachu", "Let's Go Eevee"]), - ("Galar", "images/marks/Galar_symbol_HOME.png", ["Sword", "Shield"]), - ("Sinnoh", "images/marks/BDSP_icon_HOME.png", ["Brilliant Diamond", "Shining Pearl"]), - ("Hisui", "images/marks/Arceus_mark_HOME.png", ["Legends Arceus"]), - ("Paldea", "images/marks/Paldea_icon_HOME.png", ["Scarlet", "Violet"]), - ] - - for mark in marks: - cursor.execute(''' - INSERT OR IGNORE INTO marks (name, icon_path) - VALUES (?, ?) - ''', (mark[0], mark[1])) - - mark_id = cursor.lastrowid - - for game_name in mark[2]: - cursor.execute(''' - INSERT OR IGNORE INTO mark_game_associations (mark_id, game_id) - SELECT ?, id FROM games WHERE name = ? - ''', (mark_id, game_name)) - - conn.commit() - -def load_pokemon_data(conn): - cursor = conn.cursor() - - with open('pokemon_home_list.csv', 'r', encoding='utf-8') as f: - reader = csv.reader(f) - next(reader) # Skip header row if it exists - for row in reader: - national_dex_number = int(row[0]) - full_name = row[1] - - # Extract the base name and form name - match = re.match(r'([^(]+)(?:\s*\(([^)]+)\))?', full_name) - if match: - base_name = match.group(1).strip() - form_name = match.group(2).strip() if match.group(2) else "Default" - else: - base_name = full_name - form_name = "Default" - - # Insert or update the pokemon entry - cursor.execute(''' - INSERT OR IGNORE INTO pokemon (national_dex_number, name) - VALUES (?, ?) - ''', (national_dex_number, base_name)) - - # Create the image path - padded_dex = f"{national_dex_number:04d}" - if form_name == "Default": - image_path = f"images/pokemon/{padded_dex}_{base_name}.png" - else: - image_path = f"images/pokemon/{padded_dex}_{base_name}_({form_name}).png".replace(" ", "_") - - # Insert the form entry - cursor.execute(''' - INSERT OR IGNORE INTO pokemon_forms (pokemon_id, form_name, is_default, image_path) - VALUES (?, ?, ?, ?) - ''', (national_dex_number, form_name, form_name == "Default", image_path)) - - conn.commit() - -def load_encounter_data(conn): - cursor = conn.cursor() - - with open('pokemon_earliest_games.csv', 'r', encoding='utf-8') as f: - reader = csv.DictReader(f) - for row in reader: - national_dex_number = int(row['number']) - full_name = row['name'] - earliest_game = row['earliest_game'] - obtain_method = row['obtain_method'] - encounter_locations = row['encounter_locations'] - introduced_in_gen = row['introduced_in_gen'] - # Extract the base name and form name - match = re.match(r'([^(]+)(?:\s*\(([^)]+)\))?', full_name) - if match: - base_name = match.group(1).strip() - form_name = match.group(2).strip() if match.group(2) else "Default" - if form_name == "None": - form_name = "Default" - else: - base_name = full_name - form_name = "Default" - - # Update the Pokémon entry with introduced_in_gen - cursor.execute(''' - INSERT OR REPLACE INTO pokemon (national_dex_number, name, introduced_in_gen) - VALUES (?, ?, ?) - ''', (national_dex_number, base_name, introduced_in_gen)) - - cursor.execute(''' - INSERT OR IGNORE INTO pokemon_forms (pokemon_id, form_name, is_default, image_path) - VALUES (?, ?, ?, ?) - ''', (national_dex_number, form_name, form_name == "Default", f"images/pokemon/{national_dex_number:04d}_{base_name}.png")) - - # Skip encounter data if it's unknown or N/A - if earliest_game == "Unknown" or obtain_method == "Unknown": - continue - - # Get the form_id - cursor.execute(''' - SELECT id FROM pokemon_forms - WHERE pokemon_id = ? AND form_name = ? - ''', (national_dex_number, form_name)) - form_id = cursor.fetchone()[0] - - # Get the game_id (now case-insensitive and including alternate names) - cursor.execute(''' - SELECT g.id FROM games g - LEFT JOIN alternate_game_names agn ON g.id = agn.game_id - WHERE g.name = ? COLLATE NOCASE OR agn.alternate_name = ? COLLATE NOCASE - ''', (earliest_game, earliest_game)) - result = cursor.fetchone() - if result: - game_id = result[0] - else: - print(f"Warning: Game '{earliest_game}' not found for {full_name}") - continue - - # Handle gift Pokémon - if obtain_method.lower() == "gift" and (encounter_locations == "N/A" or not encounter_locations): - # Insert or get the "Gift" location - cursor.execute(''' - INSERT OR IGNORE INTO locations (name, description) - VALUES (?, ?) - ''', ("Gift", "Pokémon received as a gift")) - cursor.execute('SELECT id FROM locations WHERE name = ?', ("Gift",)) - location_id = cursor.fetchone()[0] - - # Insert or get the "gift" encounter method - cursor.execute('INSERT OR IGNORE INTO encounter_methods (name) VALUES (?)', ("gift",)) - cursor.execute('SELECT id FROM encounter_methods WHERE name = ?', ("gift",)) - method_id = cursor.fetchone()[0] - - # Insert form_encounter for gift Pokémon - cursor.execute(''' - INSERT OR IGNORE INTO form_encounters - (form_id, game_id, location_id, encounter_method_id) - VALUES (?, ?, ?, ?) - ''', (form_id, game_id, location_id, method_id)) - elif encounter_locations != "N/A" and encounter_locations: - # Process each encounter location - for location_info in encounter_locations.split('|'): - location = location_info.strip() - - location = tidy_location_name(location) - - # Tidy up the location name and generate a description - description = tidy_location_name(location) - - # Insert or get location_id - cursor.execute(''' - INSERT OR IGNORE INTO locations (name, description) - VALUES (?, ?) - ''', (location, description)) - cursor.execute('SELECT id FROM locations WHERE name = ?', (location,)) - location_id = cursor.fetchone()[0] - - # Insert or get encounter_method_id - cursor.execute('INSERT OR IGNORE INTO encounter_methods (name) VALUES (?)', (obtain_method,)) - cursor.execute('SELECT id FROM encounter_methods WHERE name = ?', (obtain_method,)) - method_id = cursor.fetchone()[0] - - # Insert form_encounter - cursor.execute(''' - INSERT OR IGNORE INTO form_encounters - (form_id, game_id, location_id, encounter_method_id) - VALUES (?, ?, ?, ?) - ''', (form_id, game_id, location_id, method_id)) - - conn.commit() - -def main(): - conn = create_connection() - create_tables(conn) - load_game_data(conn) - load_mark_data(conn) - load_pokemon_data(conn) - load_encounter_data(conn) - conn.close() - print("All data has been successfully added to the database.") - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/DataGatherers/DefaultForms.json b/DataGatherers/DefaultForms.json index 75c7354..36898ce 100644 --- a/DataGatherers/DefaultForms.json +++ b/DataGatherers/DefaultForms.json @@ -48,5 +48,6 @@ "Unremarkable Form", "Antique Form", "Phony Form", - "Masterpiece Form" + "Masterpiece Form", + "Chest Form" ] \ No newline at end of file diff --git a/DataGatherers/DetermineOriginGame.py b/DataGatherers/DetermineOriginGame.py index 9ed8033..feab6aa 100644 --- a/DataGatherers/DetermineOriginGame.py +++ b/DataGatherers/DetermineOriginGame.py @@ -18,7 +18,6 @@ import sys sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - from DataGatherers.cache_manager import CacheManager # List of all main series Pokémon games in chronological order, with special games first in each generation @@ -439,6 +438,10 @@ def parse_form_information(html_content): headings = soup.find_all('b') if len(headings) > 0: for heading in headings: + if heading.parent.name == 'sup': + continue + if "form" not in heading.get_text(strip=True).lower(): + continue main_form = heading.get_text(strip=True) info = { "main_form": main_form, @@ -721,7 +724,7 @@ def get_locations_from_bulbapedia(pokemon_name, form, cache: CacheManager, defau games_string = entries[0].find('a').get('title') for game in all_games: if game in games_string: - record_location_info(game, game_locations, None, "Event") + record_location_info(game, game_locations, "Event", "Event") return game_locations diff --git a/DataGatherers/ExtractPokemonData.py b/DataGatherers/ExtractPokemonData.py deleted file mode 100644 index de0f8b4..0000000 --- a/DataGatherers/ExtractPokemonData.py +++ /dev/null @@ -1,136 +0,0 @@ -import sqlite3 -import csv -from typing import List, Dict, Optional -from bs4 import BeautifulSoup -import requests -import re -from fuzzywuzzy import fuzz - -# Import necessary functions from DetermineOriginGame.py -from DetermineOriginGame import ( - create_pokemon_index, - get_intro_generation, - get_locations_from_bulbapedia, - get_evolution_data_from_bulbapedia, - split_td_contents, - parse_form_information, - get_cached_data, - all_games, - pokemon_index, - cache, - read_pokemon_list -) - -class Pokemon: - def __init__(self, number: int, name: str, form: Optional[str] = None): - self.number = number - self.name = name - self.form = form - self.introduced_in_gen: Optional[int] = None - self.encounters: Dict[str, List[str]] = {} - self.evolution_chain: List[Dict] = [] - self.stage: Optional[str] = None - -def create_database(): - conn = sqlite3.connect('unprocessed_pokemon_database.db') - cursor = conn.cursor() - - # Create tables - cursor.execute(''' - CREATE TABLE IF NOT EXISTS pokemon ( - id INTEGER PRIMARY KEY, - national_dex_number INTEGER, - name TEXT, - form TEXT, - introduced_in_gen INTEGER - ) - ''') - - cursor.execute(''' - CREATE TABLE IF NOT EXISTS encounters ( - id INTEGER PRIMARY KEY, - pokemon_id INTEGER, - game TEXT, - location TEXT, - FOREIGN KEY (pokemon_id) REFERENCES pokemon (id) - ) - ''') - - cursor.execute(''' - CREATE TABLE IF NOT EXISTS evolution_chain ( - id INTEGER PRIMARY KEY, - pokemon_id INTEGER, - stage INTEGER, - evolves_from TEXT, - evolution_method TEXT, - FOREIGN KEY (pokemon_id) REFERENCES pokemon (id) - ) - ''') - - conn.commit() - return conn - -def extract_pokemon_data(pokemon_list: List[Pokemon], conn: sqlite3.Connection): - cursor = conn.cursor() - - for pokemon in pokemon_list: - print(f"Processing {pokemon.name} ({pokemon.form})") - - # Get introduction generation - pokemon.introduced_in_gen = get_intro_generation(pokemon.name, pokemon.form, cache) - - # Get encounter data - encounter_data = get_locations_from_bulbapedia(pokemon.name, pokemon.form, cache) - for game, locations in encounter_data.items(): - pokemon.encounters[game] = locations - - # Get evolution data - pokemon.evolution_chain = get_evolution_data_from_bulbapedia(pokemon.name, pokemon.form, cache) - - # Insert data into database - cursor.execute(''' - INSERT INTO pokemon (national_dex_number, name, form, introduced_in_gen) - VALUES (?, ?, ?, ?) - ''', (pokemon.number, pokemon.name, pokemon.form, pokemon.introduced_in_gen)) - pokemon_id = cursor.lastrowid - - for game, locations in pokemon.encounters.items(): - for location in locations: - cursor.execute(''' - INSERT INTO encounters (pokemon_id, game, location) - VALUES (?, ?, ?) - ''', (pokemon_id, game, location)) - - if pokemon.evolution_chain: - for i, stage in enumerate(pokemon.evolution_chain): - previous_stage = None - if stage.previous_stage: - previous_stage = stage.previous_stage.pokemon - cursor.execute(''' - INSERT INTO evolution_chain (pokemon_id, stage, evolves_from, evolution_method) - VALUES (?, ?, ?, ?) - ''', (pokemon_id, i, previous_stage, stage.method)) - - conn.commit() - -def read_and_convert_pokemon_list(filename: str) -> List[Pokemon]: - pokemon_list = read_pokemon_list(filename, 3000) - local_list = [] - for entry in pokemon_list: - number = entry.number - name = entry.name - form = entry.form - local_list.append(Pokemon(number, name, form)) - return local_list - -def main(): - get_cached_data() - conn = create_database() - pokemon_list = read_and_convert_pokemon_list('pokemon_home_list.csv') - create_pokemon_index(pokemon_list) - extract_pokemon_data(pokemon_list, conn) - conn.close() - print("Data extraction complete and stored in the database.") - -if __name__ == "__main__": - main() diff --git a/DataGatherers/Update_evolution_information.py b/DataGatherers/Update_evolution_information.py index 2bd763a..c8838d7 100644 --- a/DataGatherers/Update_evolution_information.py +++ b/DataGatherers/Update_evolution_information.py @@ -3,8 +3,17 @@ from typing import List, Optional from dataclasses import dataclass from fuzzywuzzy import fuzz import re -from cache_manager import CacheManager -from DetermineOriginGame import get_evolution_data_from_bulbapedia + +import sys +import os +import logging + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from DataGatherers.cache_manager import CacheManager +from DataGatherers.DetermineOriginGame import get_evolution_data_from_bulbapedia + +logger = logging.getLogger('ui_feedback') @dataclass class EvolutionInfo: @@ -91,7 +100,7 @@ def process_evolution_chain(conn, evolution_chain, cache, gender: Optional[str] for stage in evolution_chain: from_pfic = get_pokemon_form_by_name(conn, stage.pokemon, stage.form, gender=gender) if not from_pfic: - print(f"Warning: Could not find PFIC for {stage.pokemon} {stage.form}") + logger.warning(f"Could not find PFIC for {stage.pokemon} {stage.form}") continue if stage.next_stage: @@ -121,8 +130,7 @@ def update_pokemon_baby_status(conn, from_pfic, is_baby_form): ''', (is_baby_form, from_pfic)) conn.commit() -def update_evolution_chains(): - cache = CacheManager() +def update_evolution_chains(cache, progress_callback=None): conn = create_evolution_table() cursor = conn.cursor() @@ -130,7 +138,8 @@ def update_evolution_chains(): pokemon_forms = cursor.fetchall() for name, form in pokemon_forms: - print(f"Processing {name} {form if form else ''}") + if progress_callback: + progress_callback(f"Processing {name} {form if form else ''}") if form and name in form: form = form.replace(name, "").strip() @@ -151,4 +160,5 @@ def update_evolution_chains(): conn.close() if __name__ == "__main__": - update_evolution_chains() + cache = CacheManager() + update_evolution_chains(cache) diff --git a/DataGatherers/pokemondb_scraper.py b/DataGatherers/pokemondb_scraper.py index 8a0445a..f946f21 100644 --- a/DataGatherers/pokemondb_scraper.py +++ b/DataGatherers/pokemondb_scraper.py @@ -4,7 +4,14 @@ from typing import Dict, List, Optional from dataclasses import dataclass, asdict import os import sqlite3 -from cache_manager import CacheManager +import sys +import logging + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from DataGatherers.cache_manager import CacheManager + +logger = logging.getLogger('ui_feedback') @dataclass class PokemonForm: @@ -121,7 +128,7 @@ def download_image(url, filename): with open(filename, 'wb') as f: f.write(response.content) -def thingy(cache: CacheManager): +def retrieve_all_pokemon_forms(cache: CacheManager, progress_callback=None): db = PokemonDatabase() pokemon_db_conn = create_pokemon_db() create_pokemon_storage_db() @@ -155,7 +162,9 @@ def thingy(cache: CacheManager): break pokemon_name = mon.get_text(strip=True) - print(pokemon_name) + logger.info(pokemon_name) + if progress_callback: + progress_callback(f"Processing {pokemon_name}") pokemon_url_name = pokemon_name.replace("♀", "-f").replace("♂", "-m").replace("'", "").replace(".", "").replace('é', 'e').replace(':', '') pokemon_url_name = pokemon_url_name.replace(" ", "-") @@ -197,7 +206,7 @@ def thingy(cache: CacheManager): form_name = "None" if sprite.find('small'): form_name = sprite.find('small').get_text(strip=True) - print(sprite_url, form_name) + logger.info(f'{sprite_url}, {form_name}') if form_name != "None": form += 1 gender = 0 @@ -232,8 +241,8 @@ def thingy(cache: CacheManager): national_dex_index += 1 - print(f"Total Pokémon forms: {sum(len(forms) for forms in db.pokemon.values())}") - print(f"Pokémon with multiple forms: {sum(1 for forms in db.pokemon.values() if len(forms) > 1)}") + logger.info(f"Total Pokémon forms: {sum(len(forms) for forms in db.pokemon.values())}") + logger.info(f"Pokémon with multiple forms: {sum(1 for forms in db.pokemon.values() if len(forms) > 1)}") if not os.path.exists('images-new'): os.makedirs('images-new') @@ -242,14 +251,14 @@ def thingy(cache: CacheManager): for form in pokemon: filename = f"images-new/{form.id}.png" if os.path.exists(filename): - print(f"Image for {form.id} already exists, skipping download") + logger.info(f"Image for {form.id} already exists, skipping download") else: download_image(form.sprite_url, filename) - print(f"Downloaded image for {form.id}") + logger.info(f"Downloaded image for {form.id}") pokemon_db_conn.close() if __name__ == "__main__": cache = CacheManager() - thingy(cache) + retrieve_all_pokemon_forms(cache) cache.close() \ No newline at end of file diff --git a/DataGatherers/update_location_information.py b/DataGatherers/update_location_information.py index efebf70..3b0dd5d 100644 --- a/DataGatherers/update_location_information.py +++ b/DataGatherers/update_location_information.py @@ -7,11 +7,15 @@ import json import sqlite3 from DataGatherers.cache_manager import CacheManager from DataGatherers.DetermineOriginGame import get_locations_from_bulbapedia +from event_system import event_system from bs4 import BeautifulSoup, Tag import re import time import unicodedata +import logging +logger = logging.getLogger('ui_feedback') + def create_encounters_table(): conn = sqlite3.connect('pokemon_forms.db') cursor = conn.cursor() @@ -101,11 +105,11 @@ def extract_bracketed_text(string, timeout=1): results.append(string[start_index + 1:i]) start_index = -1 else: - print(f"Warning: Unmatched closing parenthesis at position {i}") + logger.warning(f"Warning: Unmatched closing parenthesis at position {i}") # Handle any remaining unclosed brackets if stack: - print(f"Warning: {len(stack)} unmatched opening parentheses") + logger.warning(f"Warning: {len(stack)} unmatched opening parentheses") for unmatched_start in stack: results.append(string[unmatched_start + 1:]) @@ -230,15 +234,17 @@ def save_encounter(conn, pfic, game, location, days, times, dual_slot, static_en stars_str = ','.join(sorted(stars)) if stars else None rods_str = ','.join(sorted(rods)) if rods else None + game_id = event_system.call_sync('get_game_id_for_name', game) + insert_query = ''' INSERT INTO encounters - (pfic, game, location, day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, rods, fishing, starter) + (pfic, game_id, location, day, time, dual_slot, static_encounter_count, static_encounter, extra_text, stars, rods, fishing, starter) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''' criteria = { "pfic": pfic, - "game": game, + "game_id": game_id, "location": location, "day": None, "time": None, @@ -263,11 +269,11 @@ def save_encounter(conn, pfic, game, location, days, times, dual_slot, static_en encounter = cursor.fetchone() if encounter == None or encounter[0] == 0: - cursor.execute(insert_query, (pfic, game, location, day, None, dual_slot, static_encounter_count, + cursor.execute(insert_query, (pfic, game_id, location, day, None, dual_slot, static_encounter_count, static_encounter, extra_text_str, stars_str, rods_str, fishing, starter)) - print(f"New encounter added for {pfic} in {game} at {location} on {day}") + logger.info(f"New encounter added for {pfic} in {game} at {location} on {day}") else: - print(f"Identical encounter already exists for {pfic} in {game} at {location} on {day}") + logger.info(f"Identical encounter already exists for {pfic} in {game} at {location} on {day}") elif len(times) > 0: for time in times: @@ -280,11 +286,11 @@ def save_encounter(conn, pfic, game, location, days, times, dual_slot, static_en encounter = cursor.fetchone() if encounter == None or encounter[0] == 0: - cursor.execute(insert_query, (pfic, game, location, None, time, dual_slot, static_encounter_count, + cursor.execute(insert_query, (pfic, game_id, location, None, time, dual_slot, static_encounter_count, static_encounter, extra_text_str, stars_str, rods_str, fishing, starter)) - print(f"New encounter added for {pfic} in {game} at {location} at {time}") + logger.info(f"New encounter added for {pfic} in {game} at {location} at {time}") else: - print(f"Identical encounter already exists for {pfic} in {game} at {location} at {time}") + logger.info(f"Identical encounter already exists for {pfic} in {game} at {location} at {time}") else: criteria["day"] = None @@ -296,11 +302,11 @@ def save_encounter(conn, pfic, game, location, days, times, dual_slot, static_en encounter = cursor.fetchone() if encounter == None or encounter[0] == 0: - cursor.execute(insert_query, (pfic, game, location, None, None, dual_slot, static_encounter_count, + cursor.execute(insert_query, (pfic, game_id, location, None, None, dual_slot, static_encounter_count, static_encounter, extra_text_str, stars_str, rods_str, fishing, starter)) - print(f"New encounter added for {pfic} in {game} at {location}") + logger.info(f"New encounter added for {pfic} in {game} at {location}") else: - print(f"Identical encounter already exists for {pfic} in {game} at {location}") + logger.info(f"Identical encounter already exists for {pfic} in {game} at {location}") conn.commit() @@ -320,7 +326,7 @@ def compare_forms(a, b): return False def process_pokemon_for_location_data(pfic, name, form, national_dex, default_forms, cache, conn): - print(f"Processing {name} {form if form else ''}") + logger.info(f"Processing {name} {form if form else ''}") if form and name in form: form = form.replace(name, "").strip() @@ -348,7 +354,24 @@ def process_pokemon_for_location_data(pfic, name, form, national_dex, default_fo search_form = form - encounters_to_ignore = ["trade", "time capsule", "unobtainable", "evolve", "tradeversion", "poké transfer", "friend safari", "unavailable", "pokémon home"] + encounters_to_ignore = [ + "trade", + "time capsule", + "unobtainable", + "evolve", + "tradeversion", + "poké transfer", + "friend safari", + "unavailable", + "pokémon home", + "union circle", + "pokémon bank", + "pal park", + "transfer from dream radar", + "global link event", + "pokémon channel", + "pokémon colosseum bonus disc" + ] encounter_data = get_locations_from_bulbapedia(name, search_form, cache, default_forms) if encounter_data == None: @@ -375,17 +398,17 @@ def process_pokemon_for_location_data(pfic, name, form, national_dex, default_fo continue if print_encounter: - print(f"Found in {encounter}:") + logger.info(f"Found in {encounter}:") print_encounter = False remaining, details = extract_additional_information(location["tag"]) routes, remaining = extract_routes(remaining) - print(f"Routes: {routes}") - print(f"Remaining: {remaining.strip()}") - print(f"Details: {details}") + logger.info(f"Routes: {routes}") + logger.info(f"Remaining: {remaining.strip()}") + logger.info(f"Details: {details}") if len(details["times"]) > 0: - print("Stupid Data") + logger.info("Stupid Data") for route in routes: route_name = f"Route {route}" @@ -399,9 +422,7 @@ def process_pokemon_for_location_data(pfic, name, form, national_dex, default_fo save_encounter(conn, pfic, encounter, remaining_location.strip(), details["days"], details["times"], details["dual_slot"], details["static_encounter"], details["static_encounter_count"], details["extra_text"], details["stars"], details["Rods"], details["Fishing"], details["starter"] ) -if __name__ == "__main__": - cache = CacheManager() - +def update_location_information(cache, progress_callback=None): conn = create_encounters_table() cursor = conn.cursor() cursor.execute(''' @@ -418,6 +439,13 @@ if __name__ == "__main__": default_forms = [] for pfic, name, form, national_dex in pokemon_forms: + if progress_callback: + progress_callback(f"Processing {name} {form if form else ''}") process_pokemon_for_location_data(pfic, name, form, national_dex, default_forms, cache, conn) - conn.close() + conn.close() + +if __name__ == "__main__": + cache = CacheManager() + update_location_information(cache) + diff --git a/DataGatherers/update_storable_in_home.py b/DataGatherers/update_storable_in_home.py index 7322a17..f9d547a 100644 --- a/DataGatherers/update_storable_in_home.py +++ b/DataGatherers/update_storable_in_home.py @@ -1,8 +1,17 @@ import json import sqlite3 -from cache_manager import CacheManager from bs4 import BeautifulSoup, Tag +import sys +import os +import logging + +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from DataGatherers.cache_manager import CacheManager + +logger = logging.getLogger('ui_feedback') + def create_pokemon_storage_db(): conn = sqlite3.connect('pokemon_forms.db') cursor = conn.cursor() @@ -69,7 +78,7 @@ def scrape_all_regions(cache): url = f"{base_url}{region}pokemon.shtml" region_pokemon = scrape_serebii_region_pokemon(url, cache) all_pokemon.extend(region_pokemon) - print(f"Scraped {len(region_pokemon)} Pokémon from {region.capitalize()} region") + logger.info(f"Scraped {len(region_pokemon)} Pokémon from {region.capitalize()} region") return all_pokemon @@ -93,11 +102,11 @@ def extract_bracketed_text(string): results.append(string[start_index + 1:i]) start_index = -1 else: - print(f"Warning: Unmatched closing parenthesis at position {i}") + logger.warning(f"Warning: Unmatched closing parenthesis at position {i}") # Handle any remaining unclosed brackets if stack: - print(f"Warning: {len(stack)} unmatched opening parentheses") + logger.warning(f"Warning: {len(stack)} unmatched opening parentheses") for unmatched_start in stack: results.append(string[unmatched_start + 1:]) @@ -118,9 +127,7 @@ def compare_forms(a, b): return False -if __name__ == "__main__": - cache = CacheManager() - +def update_storable_in_home(cache, progress_callback=None): conn = create_pokemon_storage_db() cursor = conn.cursor() cursor.execute(''' @@ -139,9 +146,12 @@ if __name__ == "__main__": default_forms = [] for pfic, name, form, national_dex in pokemon_forms: - print(f"Processing {name} {form if form else ''}") + + if progress_callback: + progress_callback(f"Processing {name} {form if form else ''}") storable_in_home = False + default_form = form if form and name in form: form = form.replace(name, "").strip() @@ -150,9 +160,6 @@ if __name__ == "__main__": if form and ("male" in form.lower() or "female" in form.lower()): form = None - if form and form in default_forms: - form = None - if name == "Unown" and (form != "!" and form != "?"): form = None @@ -164,23 +171,31 @@ if __name__ == "__main__": pokemon = get_objects_by_number(all_depositable_pokemon, f"{national_dex:04d}") for p in pokemon: + if form: + parts = p['name'].split(" ") + if len(parts) > 1 and parts[0] == form: + storable_in_home = True + + brackets = extract_bracketed_text(p['name']) + if brackets: + for bracket in brackets: + if name in bracket: + bracket = bracket.replace(name, "").strip() + if compare_forms(form, bracket): + storable_in_home = True + break + if storable_in_home == False and form and form in default_forms: + form = None + if form == None and name.lower() in p['name'].lower(): storable_in_home = True break - parts = p['name'].split(" ") - if len(parts) > 1 and parts[0] == form: - storable_in_home = True - - brackets = extract_bracketed_text(p['name']) - if brackets: - for bracket in brackets: - if name in bracket: - bracket = bracket.replace(name, "").strip() - if compare_forms(form, bracket): - storable_in_home = True - break - - print(f"{name} {form if form else ''} is storable in home: {storable_in_home}") + logger.info(f"{name} {form if form else ''} is storable in home: {storable_in_home}") insert_pokemon_storage(conn, pfic, storable_in_home) + +if __name__ == "__main__": + cache = CacheManager() + update_storable_in_home(cache) + \ No newline at end of file diff --git a/Utilities/DBVisualiser.py b/Utilities/DBVisualiser.py deleted file mode 100644 index 7e07180..0000000 --- a/Utilities/DBVisualiser.py +++ /dev/null @@ -1,609 +0,0 @@ -import sys -import sqlite3 -import json -import os -from datetime import datetime -from PyQt6.QtWidgets import (QApplication, QMainWindow, QListWidget, QLabel, - QVBoxLayout, QHBoxLayout, QWidget, QPushButton, - QTableWidget, QTableWidgetItem, QHeaderView, - QLineEdit, QCheckBox, QFormLayout, QMessageBox, - QDialog, QComboBox, QFileDialog, QTabWidget) -from PyQt6.QtGui import QPixmap -from PyQt6.QtCore import Qt - -class PokemonDatabaseApp(QMainWindow): - def __init__(self): - super().__init__() - self.setWindowTitle("Pokémon Database Viewer") - self.setGeometry(100, 100, 1200, 600) - - # Create an in-memory database - self.conn = sqlite3.connect(':memory:') - self.cursor = self.conn.cursor() - - # Load the database from disk into memory - self.load_database() - - # Apply all existing patches - self.apply_all_patches() - - self.current_pokemon_id = None - self.current_pokemon_name = None - self.current_form_id = None - self.all_pokemon = [] - self.patches = {} - self.init_ui() - self.load_locations_list() - - def init_ui(self): - main_layout = QVBoxLayout() - - # Create tab widget - self.tab_widget = QTabWidget() - - # Create and add Pokemon tab - pokemon_tab = self.create_pokemon_tab() - self.tab_widget.addTab(pokemon_tab, "Pokémon") - - # Create and add Locations tab - locations_tab = self.create_locations_tab() - self.tab_widget.addTab(locations_tab, "Locations") - - main_layout.addWidget(self.tab_widget) - - # Add export button - self.export_button = QPushButton("Export Production Database") - self.export_button.clicked.connect(self.export_production_database) - main_layout.addWidget(self.export_button) - - container = QWidget() - container.setLayout(main_layout) - self.setCentralWidget(container) - - self.load_pokemon_list() - - def create_pokemon_tab(self): - pokemon_tab = QWidget() - tab_layout = QHBoxLayout() - - # Pokémon list section - pokemon_list_layout = QVBoxLayout() - - # Search box - self.search_box = QLineEdit() - self.search_box.setPlaceholderText("Search Pokémon...") - self.search_box.textChanged.connect(self.filter_pokemon_list) - pokemon_list_layout.addWidget(self.search_box) - - # Pokémon list - self.pokemon_list = QListWidget() - self.pokemon_list.itemClicked.connect(self.load_pokemon_data) - pokemon_list_layout.addWidget(self.pokemon_list) - - tab_layout.addLayout(pokemon_list_layout, 1) - - # Pokémon details - details_layout = QVBoxLayout() - - image_and_form_layout = QHBoxLayout() - - # Image - self.image_label = QLabel() - self.image_label.setFixedSize(200, 200) - self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter) - image_and_form_layout.addWidget(self.image_label) - - # Form details - form_details_layout = QFormLayout() - self.form_name_edit = QLineEdit() - self.is_default_checkbox = QCheckBox() - self.image_path_edit = QLineEdit() - form_details_layout.addRow("Form Name:", self.form_name_edit) - form_details_layout.addRow("Default Form:", self.is_default_checkbox) - form_details_layout.addRow("Image Path:", self.image_path_edit) - - # Save button - self.save_button = QPushButton("Save Form Changes") - self.save_button.clicked.connect(self.save_form_changes) - form_details_layout.addRow(self.save_button) - - image_and_form_layout.addLayout(form_details_layout) - details_layout.addLayout(image_and_form_layout) - - # Forms list and add new form button - forms_layout = QHBoxLayout() - self.forms_list = QListWidget() - self.forms_list.itemClicked.connect(self.load_form_data) - forms_layout.addWidget(self.forms_list) - - add_form_button = QPushButton("Add New Form") - add_form_button.clicked.connect(self.add_new_form) - details_layout.addWidget(add_form_button) - - details_layout.addWidget(QLabel("Forms:")) - details_layout.addLayout(forms_layout) - - # Encounters table and add new encounter button - self.encounters_table = QTableWidget() - self.encounters_table.setColumnCount(3) - self.encounters_table.setHorizontalHeaderLabels(['Game', 'Location', 'Method']) - self.encounters_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) - details_layout.addWidget(QLabel("Encounters:")) - details_layout.addWidget(self.encounters_table) - - add_encounter_button = QPushButton("Add New Encounter") - add_encounter_button.clicked.connect(self.add_new_encounter) - details_layout.addWidget(add_encounter_button) - - tab_layout.addLayout(details_layout, 2) - - pokemon_tab.setLayout(tab_layout) - return pokemon_tab - - def create_locations_tab(self): - locations_tab = QWidget() - tab_layout = QHBoxLayout() - - # Locations list - locations_list_layout = QVBoxLayout() - - # Search box for locations - self.locations_search_box = QLineEdit() - self.locations_search_box.setPlaceholderText("Search Locations...") - self.locations_search_box.textChanged.connect(self.filter_locations_list) - locations_list_layout.addWidget(self.locations_search_box) - - # Locations list - self.locations_list = QListWidget() - self.locations_list.itemClicked.connect(self.load_location_data) - locations_list_layout.addWidget(self.locations_list) - - # Add new location button - add_location_button = QPushButton("Add New Location") - add_location_button.clicked.connect(self.add_new_location) - locations_list_layout.addWidget(add_location_button) - - tab_layout.addLayout(locations_list_layout, 1) - - # Location details - location_details_layout = QFormLayout() - - self.location_name_edit = QLineEdit() - self.location_description_edit = QLineEdit() - - location_details_layout.addRow("Name:", self.location_name_edit) - location_details_layout.addRow("description:", self.location_description_edit) - - # Save location changes button - save_location_button = QPushButton("Save Location Changes") - save_location_button.clicked.connect(self.save_location_changes) - location_details_layout.addRow(save_location_button) - - tab_layout.addLayout(location_details_layout, 2) - - locations_tab.setLayout(tab_layout) - return locations_tab - - def load_database(self): - disk_conn = sqlite3.connect('pokemon_database.db') - disk_conn.backup(self.conn) - disk_conn.close() - - def apply_all_patches(self): - patches_dir = "patches" - if not os.path.exists(patches_dir): - return - - patch_files = sorted([f for f in os.listdir(patches_dir) if f.endswith('.json')]) - for patch_file in patch_files: - with open(os.path.join(patches_dir, patch_file), 'r') as f: - patches = json.load(f) - self.apply_patches(patches) - - def apply_patches(self, patches): - try: - for timestamp, patch in patches.items(): - if patch["type"] == "form_update": - self.cursor.execute(""" - UPDATE pokemon_forms - SET form_name = ?, is_default = ?, image_path = ? - WHERE id = ? - """, (patch["form_name"], patch["is_default"], patch["image_path"], patch["form_id"])) - elif patch["type"] == "new_form": - self.cursor.execute(""" - INSERT INTO pokemon_forms (pokemon_id, form_name, is_default, image_path) - VALUES (?, ?, ?, ?) - """, (patch["pokemon_id"], patch["form_name"], patch["is_default"], patch["image_path"])) - elif patch["type"] == "new_encounter": - self.cursor.execute(""" - INSERT INTO form_encounters (form_id, game_id, location_id, encounter_method_id) - VALUES (?, - (SELECT id FROM games WHERE name = ?), - (SELECT id FROM locations WHERE name = ?), - (SELECT id FROM encounter_methods WHERE name = ?)) - """, (patch["form_id"], patch["game"], patch["location"], patch["method"])) - elif patch["type"] == "location_update": - self.cursor.execute(""" - UPDATE locations - SET name = ?, description = ? - WHERE name = ? - """, (patch["new_name"], patch["description"], patch["old_name"])) - elif patch["type"] == "new_location": - self.cursor.execute(""" - INSERT INTO locations (name, description) - VALUES (?, ?) - """, (patch["name"], patch["description"])) - - self.conn.commit() - except sqlite3.Error as e: - print(f"An error occurred while applying patches: {e}") - - def load_pokemon_list(self): - self.cursor.execute("SELECT national_dex_number, name FROM pokemon ORDER BY national_dex_number") - self.all_pokemon = [f"{row[0]:03d} - {row[1]}" for row in self.cursor.fetchall()] - self.pokemon_list.addItems(self.all_pokemon) - - def filter_pokemon_list(self): - search_text = self.search_box.text().lower() - self.pokemon_list.clear() - for pokemon in self.all_pokemon: - if search_text in pokemon.lower(): - self.pokemon_list.addItem(pokemon) - - def load_pokemon_data(self, item): - self.current_pokemon_id = int(item.text().split('-')[0]) - self.current_pokemon_name = item.text().split('-')[1] - # Load forms - self.forms_list.clear() - self.cursor.execute(""" - SELECT form_name FROM pokemon_forms - WHERE pokemon_id = ? - ORDER BY is_default DESC, form_name - """, (self.current_pokemon_id,)) - for row in self.cursor.fetchall(): - self.forms_list.addItem(row[0]) - - # Load default form data - self.forms_list.setCurrentRow(0) - self.load_form_data(self.forms_list.item(0)) - - def load_form_data(self, item): - if not item: - return - - form_name = item.text() - - # Load form data - self.cursor.execute(""" - SELECT id, form_name, is_default, image_path FROM pokemon_forms - WHERE pokemon_id = ? AND form_name = ? - """, (self.current_pokemon_id, form_name)) - form_data = self.cursor.fetchone() - if form_data: - self.current_form_id, form_name, is_default, image_path = form_data - - # Update form details - self.form_name_edit.setText(form_name) - self.is_default_checkbox.setChecked(bool(is_default)) - self.image_path_edit.setText(image_path) - - # Load image - pixmap = QPixmap(image_path) - self.image_label.setPixmap(pixmap.scaled(200, 200, Qt.AspectRatioMode.KeepAspectRatio)) - - # Load encounters - self.encounters_table.setRowCount(0) - self.cursor.execute(""" - SELECT g.name, l.name, em.name - FROM form_encounters fe - JOIN games g ON fe.game_id = g.id - JOIN locations l ON fe.location_id = l.id - JOIN encounter_methods em ON fe.encounter_method_id = em.id - WHERE fe.form_id = ? - ORDER BY g.name, l.name - """, (self.current_form_id,)) - for row in self.cursor.fetchall(): - current_row = self.encounters_table.rowCount() - self.encounters_table.insertRow(current_row) - for col, value in enumerate(row): - self.encounters_table.setItem(current_row, col, QTableWidgetItem(str(value))) - - def save_form_changes(self): - if not self.current_form_id: - return - - new_form_name = self.form_name_edit.text() - new_is_default = self.is_default_checkbox.isChecked() - new_image_path = self.image_path_edit.text() - - # Add changes to patches - patch = { - "type": "form_update", - "form_id": self.current_form_id, - "form_name": new_form_name, - "is_default": new_is_default, - "image_path": new_image_path - } - self.add_to_patches(patch) - - try: - self.cursor.execute(""" - UPDATE pokemon_forms - SET form_name = ?, is_default = ?, image_path = ? - WHERE id = ? - """, (new_form_name, new_is_default, new_image_path, self.current_form_id)) - self.conn.commit() - QMessageBox.information(self, "Success", "Form data updated successfully!") - - # Refresh the forms list and current form data - self.load_pokemon_data(self.pokemon_list.currentItem()) - except sqlite3.Error as e: - QMessageBox.warning(self, "Error", f"An error occurred: {e}") - - def add_new_form(self): - if not self.current_pokemon_id: - QMessageBox.warning(self, "Error", "Please select a Pokémon first.") - return - - dialog = QDialog(self) - dialog.setWindowTitle("Add New Form") - layout = QFormLayout(dialog) - - form_name_edit = QLineEdit() - layout.addRow("Form Name:", form_name_edit) - - buttons = QHBoxLayout() - save_button = QPushButton("Save") - save_button.clicked.connect(dialog.accept) - cancel_button = QPushButton("Cancel") - cancel_button.clicked.connect(dialog.reject) - buttons.addWidget(save_button) - buttons.addWidget(cancel_button) - layout.addRow(buttons) - - if dialog.exec() == QDialog.DialogCode.Accepted: - form_name = form_name_edit.text() - - try: - self.cursor.execute(""" - INSERT INTO pokemon_forms (pokemon_id, form_name, is_default, image_path) - VALUES (?, ?, ?, ?) - """, (self.current_pokemon_id, form_name, False, f"images/pokemon/{self.current_pokemon_id:04d}_{self.current_pokemon_name}_({form_name}).png".replace(" ", "_"))) - self.conn.commit() - new_form_id = self.cursor.lastrowid - - # Add new form to patches - patch = { - "type": "new_form", - "form_id": new_form_id, - "pokemon_id": self.current_pokemon_id, - "form_name": form_name, - "is_default": False, - "image_path": f"images/pokemon/{self.current_pokemon_id:04d}_{self.current_pokemon_name}_({form_name}).png".replace(" ", "_") - } - self.add_to_patches(patch) - - QMessageBox.information(self, "Success", "New form added successfully!") - self.load_pokemon_data(self.pokemon_list.currentItem()) - except sqlite3.Error as e: - QMessageBox.warning(self, "Error", f"An error occurred: {e}") - - def add_new_encounter(self): - if not self.current_form_id: - QMessageBox.warning(self, "Error", "Please select a form first.") - return - - dialog = QDialog(self) - dialog.setWindowTitle("Add New Encounter") - layout = QFormLayout(dialog) - - game_combo = QComboBox() - self.cursor.execute("SELECT name FROM games ORDER BY name") - games = [row[0] for row in self.cursor.fetchall()] - game_combo.addItems(games) - layout.addRow("Game:", game_combo) - - location_combo = QComboBox() - self.cursor.execute("SELECT name FROM locations ORDER BY name") - locations = [row[0] for row in self.cursor.fetchall()] - location_combo.addItems(locations) - layout.addRow("Location:", location_combo) - - method_combo = QComboBox() - self.cursor.execute("SELECT name FROM encounter_methods ORDER BY name") - methods = [row[0] for row in self.cursor.fetchall()] - method_combo.addItems(methods) - layout.addRow("Method:", method_combo) - - buttons = QHBoxLayout() - save_button = QPushButton("Save") - save_button.clicked.connect(dialog.accept) - cancel_button = QPushButton("Cancel") - cancel_button.clicked.connect(dialog.reject) - buttons.addWidget(save_button) - buttons.addWidget(cancel_button) - layout.addRow(buttons) - - if dialog.exec() == QDialog.DialogCode.Accepted: - game = game_combo.currentText() - location = location_combo.currentText() - method = method_combo.currentText() - - try: - self.cursor.execute(""" - INSERT INTO form_encounters (form_id, game_id, location_id, encounter_method_id) - VALUES (?, - (SELECT id FROM games WHERE name = ?), - (SELECT id FROM locations WHERE name = ?), - (SELECT id FROM encounter_methods WHERE name = ?)) - """, (self.current_form_id, game, location, method)) - self.conn.commit() - new_encounter_id = self.cursor.lastrowid - - # Add new encounter to patches - patch = { - "type": "new_encounter", - "encounter_id": new_encounter_id, - "form_id": self.current_form_id, - "game": game, - "location": location, - "method": method - } - self.add_to_patches(patch) - - QMessageBox.information(self, "Success", "New encounter added successfully!") - self.load_form_data(self.forms_list.currentItem()) - except sqlite3.Error as e: - QMessageBox.warning(self, "Error", f"An error occurred: {e}") - - def add_to_patches(self, patch): - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - self.patches[f"{timestamp}_{len(self.patches)}"] = patch - self.auto_save_patches() - - def auto_save_patches(self): - patches_dir = "patches" - if not os.path.exists(patches_dir): - os.makedirs(patches_dir) - - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - file_name = f"{patches_dir}/patch_{timestamp}.json" - - with open(file_name, 'w') as f: - json.dump(self.patches, f, indent=2) - - print(f"Patches auto-saved to {file_name}") - - def closeEvent(self, event): - reply = QMessageBox.question(self, 'Save Changes', - "Do you want to save changes to the disk database?", - QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, - QMessageBox.StandardButton.No) - - if reply == QMessageBox.StandardButton.Yes: - # Save changes to disk - disk_conn = sqlite3.connect('pokemon_database.db') - self.conn.backup(disk_conn) - disk_conn.close() - QMessageBox.information(self, "Success", "Changes saved to disk database.") - - self.conn.close() - event.accept() - - def filter_locations_list(self): - search_text = self.locations_search_box.text().lower() - for i in range(self.locations_list.count()): - item = self.locations_list.item(i) - if search_text in item.text().lower(): - item.setHidden(False) - else: - item.setHidden(True) - - def load_location_data(self, item): - location_name = item.text() - self.cursor.execute("SELECT name, description FROM locations WHERE name = ?", (location_name,)) - location_data = self.cursor.fetchone() - if location_data: - self.location_name_edit.setText(location_data[0]) - self.location_description_edit.setText(location_data[1]) - - def save_location_changes(self): - old_name = self.locations_list.currentItem().text() - new_name = self.location_name_edit.text() - new_description = self.location_description_edit.text() - - try: - self.cursor.execute(""" - UPDATE locations - SET name = ?, description = ? - WHERE name = ? - """, (new_name, new_description, old_name)) - self.conn.commit() - - # Add changes to patches - patch = { - "type": "location_update", - "old_name": old_name, - "new_name": new_name, - "description": new_description - } - self.add_to_patches(patch) - - QMessageBox.information(self, "Success", "Location data updated successfully!") - self.load_locations_list() - except sqlite3.Error as e: - QMessageBox.warning(self, "Error", f"An error occurred: {e}") - - def add_new_location(self): - dialog = QDialog(self) - dialog.setWindowTitle("Add New Location") - layout = QFormLayout(dialog) - - name_edit = QLineEdit() - description_edit = QLineEdit() - layout.addRow("Name:", name_edit) - layout.addRow("description:", description_edit) - - buttons = QHBoxLayout() - save_button = QPushButton("Save") - save_button.clicked.connect(dialog.accept) - cancel_button = QPushButton("Cancel") - cancel_button.clicked.connect(dialog.reject) - buttons.addWidget(save_button) - buttons.addWidget(cancel_button) - layout.addRow(buttons) - - if dialog.exec() == QDialog.DialogCode.Accepted: - name = name_edit.text() - description = description_edit.text() - - try: - self.cursor.execute(""" - INSERT INTO locations (name, description) - VALUES (?, ?) - """, (name, description)) - self.conn.commit() - - # Add new location to patches - patch = { - "type": "new_location", - "name": name, - "description": description - } - self.add_to_patches(patch) - - QMessageBox.information(self, "Success", "New location added successfully!") - self.load_locations_list() - except sqlite3.Error as e: - QMessageBox.warning(self, "Error", f"An error occurred: {e}") - - def load_locations_list(self): - self.locations_list.clear() - self.cursor.execute("SELECT name FROM locations ORDER BY name") - locations = [row[0] for row in self.cursor.fetchall()] - self.locations_list.addItems(locations) - - def export_production_database(self): - try: - # Create a new connection for the production database - production_db_path = QFileDialog.getSaveFileName(self, "Save Production Database", "", "SQLite Database (*.db)")[0] - if not production_db_path: - return # User cancelled the file dialog - - production_conn = sqlite3.connect(production_db_path) - - # Copy the current in-memory database to the production database - self.conn.backup(production_conn) - - # Close the production database connection - production_conn.close() - - QMessageBox.information(self, "Success", f"Production database exported successfully to {production_db_path}") - except sqlite3.Error as e: - QMessageBox.warning(self, "Error", f"An error occurred while exporting the production database: {e}") - -if __name__ == '__main__': - app = QApplication(sys.argv) - window = PokemonDatabaseApp() - window.show() - sys.exit(app.exec()) \ No newline at end of file diff --git a/Utilities/NewDBVisualiser.py b/Utilities/NewDBVisualiser.py deleted file mode 100644 index e033216..0000000 --- a/Utilities/NewDBVisualiser.py +++ /dev/null @@ -1,296 +0,0 @@ -import sys -import os -import sqlite3 -from PyQt5.QtWidgets import (QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QPushButton, QVBoxLayout, - QHBoxLayout, QWidget, QLineEdit, QLabel, QMessageBox, QTabWidget, QScrollArea, QFrame, QGridLayout) -from PyQt5.QtCore import Qt -from PyQt5.QtGui import QPixmap - -class PokemonEvolutionWidget(QWidget): - def __init__(self, conn, pfic): - super().__init__() - self.conn = conn - self.pfic = pfic - self.layout = QVBoxLayout() - self.setLayout(self.layout) - self.stage_width = 200 # Fixed width for each evolution stage - self.stage_height = 250 # Fixed height for each evolution stage - self.build_evolution_chain() - - def build_evolution_chain(self): - chain = self.get_full_evolution_chain(self.pfic) - self.display_evolution_chain(chain) - - def get_full_evolution_chain(self, pfic): - cursor = self.conn.cursor() - chain = [] - visited = set() - - def build_chain(current_pfic): - if current_pfic in visited: - return None - visited.add(current_pfic) - - cursor.execute('SELECT name, form_name FROM pokemon_forms WHERE PFIC = ?', (current_pfic,)) - pokemon = cursor.fetchone() - if not pokemon: - return None - - name, form_name = pokemon - node = {"pfic": current_pfic, "name": name, "form_name": form_name, "evolutions": []} - - cursor.execute(''' - SELECT ec.to_pfic, pf.name, pf.form_name, ec.method - FROM evolution_chains ec - JOIN pokemon_forms pf ON ec.to_pfic = pf.PFIC - WHERE ec.from_pfic = ? - ''', (current_pfic,)) - evolutions = cursor.fetchall() - - for evo_pfic, evo_name, evo_form, method in evolutions: - evo_node = build_chain(evo_pfic) - if evo_node: - node["evolutions"].append({"node": evo_node, "method": method}) - - return node - - chain = build_chain(pfic) - return chain - - def display_evolution_chain(self, chain): - if not chain: - return - - main_layout = QHBoxLayout() - self.layout.addLayout(main_layout) - - stages = self.split_into_stages(chain) - for stage_index, stage in enumerate(stages): - stage_widget = QWidget() - stage_layout = QGridLayout() - stage_widget.setLayout(stage_layout) - stage_widget.setFixedSize(self.stage_width, self.stage_height * len(stage)) - - for row, pokemon in enumerate(stage): - pokemon_widget = self.create_pokemon_widget(pokemon["pfic"], pokemon["name"], pokemon["form_name"]) - stage_layout.addWidget(pokemon_widget, row, 0, Qt.AlignCenter) - - if stage_index < len(stages) - 1 and pokemon.get("method"): - arrow_label = QLabel("→") - arrow_label.setStyleSheet("font-size: 24px;") - stage_layout.addWidget(arrow_label, row, 1, Qt.AlignCenter) - - method_label = QLabel(pokemon["method"]) - method_label.setWordWrap(True) - method_label.setFixedWidth(80) - stage_layout.addWidget(method_label, row, 2, Qt.AlignCenter) - - main_layout.addWidget(stage_widget) - - def split_into_stages(self, chain): - stages = [] - current_stage = [{"pfic": chain["pfic"], "name": chain["name"], "form_name": chain["form_name"]}] - stages.append(current_stage) - - while current_stage: - next_stage = [] - for pokemon in current_stage: - evolutions = self.get_evolutions(pokemon["pfic"]) - for evolution in evolutions: - next_stage.append({ - "pfic": evolution["to_pfic"], - "name": evolution["name"], - "form_name": evolution["form_name"], - "method": evolution["method"] - }) - if next_stage: - stages.append(next_stage) - current_stage = next_stage - - return stages - - def get_evolutions(self, pfic): - cursor = self.conn.cursor() - cursor.execute(''' - SELECT ec.to_pfic, pf.name, pf.form_name, ec.method - FROM evolution_chains ec - JOIN pokemon_forms pf ON ec.to_pfic = pf.PFIC - WHERE ec.from_pfic = ? - ''', (pfic,)) - evolutions = cursor.fetchall() - return [{"to_pfic": to_pfic, "name": name, "form_name": form_name, "method": method} for to_pfic, name, form_name, method in evolutions] - - def create_pokemon_widget(self, pfic, name, form_name): - widget = QWidget() - layout = QVBoxLayout() - widget.setLayout(layout) - - image_path = f"images-new/{pfic}.png" - if os.path.exists(image_path): - pixmap = QPixmap(image_path) - image_label = QLabel() - image_label.setPixmap(pixmap.scaled(96, 96, Qt.KeepAspectRatio, Qt.SmoothTransformation)) - layout.addWidget(image_label, alignment=Qt.AlignCenter) - - name_label = QLabel(name) - name_label.setAlignment(Qt.AlignCenter) - layout.addWidget(name_label) - - if form_name: - form_label = QLabel(form_name) - form_label.setAlignment(Qt.AlignCenter) - layout.addWidget(form_label) - - return widget - -class DatabaseVisualizer(QMainWindow): - def __init__(self): - super().__init__() - self.setWindowTitle("Pokémon Database Visualizer") - self.setGeometry(100, 100, 1200, 800) - - self.conn = sqlite3.connect('pokemon_forms.db') - self.cursor = self.conn.cursor() - - self.central_widget = QWidget() - self.setCentralWidget(self.central_widget) - - self.layout = QVBoxLayout() - self.central_widget.setLayout(self.layout) - - self.tab_widget = QTabWidget() - self.layout.addWidget(self.tab_widget) - - self.forms_tab = QWidget() - self.evolutions_tab = QWidget() - self.tab_widget.addTab(self.forms_tab, "Pokémon Forms") - self.tab_widget.addTab(self.evolutions_tab, "Evolution Chains") - - self.setup_forms_tab() - self.setup_evolutions_tab() - - def setup_forms_tab(self): - layout = QVBoxLayout() - self.forms_tab.setLayout(layout) - - self.search_layout = QHBoxLayout() - self.search_label = QLabel("Search:") - self.search_input = QLineEdit() - self.search_button = QPushButton("Search") - self.search_button.clicked.connect(self.search_pokemon) - self.search_layout.addWidget(self.search_label) - self.search_layout.addWidget(self.search_input) - self.search_layout.addWidget(self.search_button) - layout.addLayout(self.search_layout) - - self.table = QTableWidget() - layout.addWidget(self.table) - - self.save_button = QPushButton("Save Changes") - self.save_button.clicked.connect(self.save_changes) - layout.addWidget(self.save_button) - - self.load_forms_data() - - def setup_evolutions_tab(self): - layout = QVBoxLayout() - self.evolutions_tab.setLayout(layout) - - self.evolution_search_layout = QHBoxLayout() - self.evolution_search_label = QLabel("Search Pokémon:") - self.evolution_search_input = QLineEdit() - self.evolution_search_button = QPushButton("Search") - self.evolution_search_button.clicked.connect(self.search_evolution) - self.evolution_search_layout.addWidget(self.evolution_search_label) - self.evolution_search_layout.addWidget(self.evolution_search_input) - self.evolution_search_layout.addWidget(self.evolution_search_button) - layout.addLayout(self.evolution_search_layout) - - self.evolution_scroll_area = QScrollArea() - self.evolution_scroll_area.setWidgetResizable(True) - layout.addWidget(self.evolution_scroll_area) - - def load_forms_data(self): - self.cursor.execute(''' - SELECT pf.PFIC, pf.name, pf.form_name, pf.national_dex, pf.generation, ps.storable_in_home - FROM pokemon_forms pf - LEFT JOIN pokemon_storage ps ON pf.PFIC = ps.PFIC - ''') - data = self.cursor.fetchall() - - self.table.setColumnCount(6) - self.table.setHorizontalHeaderLabels(["PFIC", "Name", "Form Name", "National Dex", "Generation", "Storable in Home"]) - self.table.setRowCount(len(data)) - - for row, record in enumerate(data): - for col, value in enumerate(record): - item = QTableWidgetItem(str(value)) - if col == 0: # PFIC column - item.setFlags(item.flags() & ~Qt.ItemIsEditable) # Make PFIC non-editable - self.table.setItem(row, col, item) - - self.table.resizeColumnsToContents() - - def search_pokemon(self): - search_term = self.search_input.text().lower() - for row in range(self.table.rowCount()): - match = False - for col in range(self.table.columnCount()): - item = self.table.item(row, col) - if item and search_term in item.text().lower(): - match = True - break - self.table.setRowHidden(row, not match) - - def save_changes(self): - try: - for row in range(self.table.rowCount()): - pfic = self.table.item(row, 0).text() - name = self.table.item(row, 1).text() - form_name = self.table.item(row, 2).text() or None - national_dex = int(self.table.item(row, 3).text()) - generation = int(self.table.item(row, 4).text()) - storable_in_home = self.table.item(row, 5).text().lower() == 'true' - - self.cursor.execute(''' - UPDATE pokemon_forms - SET name = ?, form_name = ?, national_dex = ?, generation = ? - WHERE PFIC = ? - ''', (name, form_name, national_dex, generation, pfic)) - - self.cursor.execute(''' - INSERT OR REPLACE INTO pokemon_storage (PFIC, storable_in_home) - VALUES (?, ?) - ''', (pfic, storable_in_home)) - - self.conn.commit() - QMessageBox.information(self, "Success", "Changes saved successfully!") - except Exception as e: - QMessageBox.critical(self, "Error", f"An error occurred while saving changes: {str(e)}") - - def search_evolution(self): - search_term = self.evolution_search_input.text().lower() - - self.cursor.execute(''' - SELECT DISTINCT name, PFIC - FROM pokemon_forms - WHERE LOWER(name) LIKE ? - ''', (f'%{search_term}%',)) - - matching_pokemon = self.cursor.fetchall() - - if matching_pokemon: - pokemon_name, pfic = matching_pokemon[0] - evolution_widget = PokemonEvolutionWidget(self.conn, pfic) - self.evolution_scroll_area.setWidget(evolution_widget) - else: - QMessageBox.information(self, "No Results", "No Pokémon found matching the search term.") - - def closeEvent(self, event): - self.conn.close() - -if __name__ == "__main__": - app = QApplication(sys.argv) - window = DatabaseVisualizer() - window.show() - sys.exit(app.exec_()) \ No newline at end of file diff --git a/efficiency_plan.txt b/efficiency_plan.txt new file mode 100644 index 0000000..b71247b --- /dev/null +++ b/efficiency_plan.txt @@ -0,0 +1,1460 @@ +Play Crystal: + Catch: + - Caterpie: 4 time(s) + - Weedle: 3 time(s) + - Pidgey: 3 time(s) + - Rattata (Female): 2 time(s) + - Rattata (Male): 2 time(s) + - Spearow: 2 time(s) + - Ekans: 2 time(s) + - Pikachu (Female): 2 time(s) + - Pikachu (Male): 2 time(s) + - Sandshrew: 2 time(s) + - Nidoran♀: 3 time(s) + - Nidoran♂: 3 time(s) + - Clefairy: 2 time(s) + - Jigglypuff: 2 time(s) + - Zubat (Female): 3 time(s) + - Zubat (Male): 2 time(s) + - Oddish: 6 time(s) + - Paras: 2 time(s) + - Venonat: 2 time(s) + - Diglett: 2 time(s) + - Meowth: 2 time(s) + - Psyduck: 2 time(s) + - Growlithe: 2 time(s) + - Poliwag: 5 time(s) + - Abra: 5 time(s) + - Machop: 3 time(s) + - Bellsprout: 3 time(s) + - Tentacool: 2 time(s) + - Geodude: 3 time(s) + - Ponyta: 2 time(s) + - Slowpoke: 3 time(s) + - Magnemite: 2 time(s) + - Farfetch'd: 1 time(s) + - Doduo (Female): 2 time(s) + - Doduo (Male): 2 time(s) + - Seel: 2 time(s) + - Grimer: 2 time(s) + - Shellder: 2 time(s) + - Gastly: 3 time(s) + - Onix: 3 time(s) + - Drowzee: 3 time(s) + - Krabby: 2 time(s) + - Voltorb: 2 time(s) + - Exeggcute: 2 time(s) + - Cubone: 2 time(s) + - Lickitung: 1 time(s) + - Koffing: 2 time(s) + - Rhyhorn (Female): 2 time(s) + - Rhyhorn (Male): 2 time(s) + - Chansey: 2 time(s) + - Tangela: 1 time(s) + - Kangaskhan: 1 time(s) + - Horsea: 3 time(s) + - Goldeen (Female): 2 time(s) + - Goldeen (Male): 2 time(s) + - Staryu: 2 time(s) + - Mr. Mime: 1 time(s) + - Scyther (Female): 2 time(s) + - Scyther (Male): 2 time(s) + - Jynx: 1 time(s) + - Electabuzz: 1 time(s) + - Magmar: 1 time(s) + - Pinsir: 1 time(s) + - Tauros: 1 time(s) + - Magikarp (Female): 2 time(s) + - Magikarp (Male): 2 time(s) + - Lapras: 1 time(s) + - Ditto: 1 time(s) + - Eevee (Female): 6 time(s) + - Eevee (Male): 1 time(s) + - Porygon: 2 time(s) + - Snorlax: 1 time(s) + - Dratini: 3 time(s) + - Mew: 1 time(s) + - Chikorita: 4 time(s) + - Cyndaquil: 3 time(s) + - Totodile: 3 time(s) + - Sentret: 2 time(s) + - Hoothoot: 2 time(s) + - Ledyba (Female): 2 time(s) + - Ledyba (Male): 2 time(s) + - Spinarak: 2 time(s) + - Chinchou: 2 time(s) + - Pichu: -1 time(s) + - Cleffa: 0 time(s) + - Igglybuff: 0 time(s) + - Togepi: 1 time(s) + - Natu: 3 time(s) + - Marill: 2 time(s) + - Sudowoodo (Female): 1 time(s) + - Sudowoodo (Male): 1 time(s) + - Hoppip: 3 time(s) + - Aipom (Female): 1 time(s) + - Aipom (Male): 1 time(s) + - Sunkern: 2 time(s) + - Yanma: 1 time(s) + - Wooper (Female): 2 time(s) + - Wooper (Male): 2 time(s) + - Murkrow (Female): 1 time(s) + - Murkrow (Male): 1 time(s) + - Misdreavus: 1 time(s) + - Unown (A): 1 time(s) + - Unown (B): 1 time(s) + - Unown (C): 1 time(s) + - Unown (D): 1 time(s) + - Unown (E): 1 time(s) + - Unown (F): 1 time(s) + - Unown (G): 1 time(s) + - Unown (H): 1 time(s) + - Unown (I): 1 time(s) + - Unown (J): 1 time(s) + - Unown (K): 1 time(s) + - Unown (L): 1 time(s) + - Unown (M): 1 time(s) + - Unown (N): 1 time(s) + - Unown (O): 1 time(s) + - Unown (P): 1 time(s) + - Unown (Q): 1 time(s) + - Unown (R): 1 time(s) + - Unown (S): 1 time(s) + - Unown (T): 1 time(s) + - Unown (U): 1 time(s) + - Unown (V): 1 time(s) + - Unown (W): 1 time(s) + - Unown (X): 1 time(s) + - Unown (Y): 1 time(s) + - Unown (Z): 1 time(s) + - Wobbuffet (Female): 1 time(s) + - Wobbuffet (Male): 1 time(s) + - Pineco: 2 time(s) + - Dunsparce: 1 time(s) + - Gligar (Female): 1 time(s) + - Gligar (Male): 1 time(s) + - Snubbull: 2 time(s) + - Qwilfish: 1 time(s) + - Shuckle: 1 time(s) + - Heracross (Female): 1 time(s) + - Heracross (Male): 1 time(s) + - Sneasel (Female): 1 time(s) + - Sneasel (Male): 1 time(s) + - Teddiursa: 3 time(s) + - Slugma: 2 time(s) + - Swinub: 3 time(s) + - Corsola: 1 time(s) + - Delibird: 1 time(s) + - Mantine: 1 time(s) + - Skarmory: 1 time(s) + - Houndour: 3 time(s) + - Phanpy: 3 time(s) + - Stantler: 1 time(s) + - Smeargle: 1 time(s) + - Tyrogue: 1 time(s) + - Smoochum: 1 time(s) + - Elekid: 1 time(s) + - Magby: 1 time(s) + - Miltank: 1 time(s) + - Raikou: 1 time(s) + - Entei: 1 time(s) + - Suicune: 1 time(s) + - Larvitar: 3 time(s) + - Lugia: 1 time(s) + - Ho-oh: 1 time(s) + - Celebi: 1 time(s) + Evolve: + - Caterpie into Metapod + - Caterpie into Metapod + - Caterpie into Metapod + - Metapod into Butterfree (Male) + - Metapod into Butterfree (Female) + - Weedle into Kakuna + - Weedle into Kakuna + - Kakuna into Beedrill + - Pidgey into Pidgeotto + - Pidgey into Pidgeotto + - Pidgeotto into Pidgeot + - Rattata (Female) into Raticate (Female) + - Rattata (Male) into Raticate (Male) + - Spearow into Fearow + - Ekans into Arbok + - Pikachu (Female) into Raichu (Female) + - Pikachu (Male) into Raichu (Male) + - Sandshrew into Sandslash + - Nidoran♀ into Nidorina + - Nidoran♀ into Nidorina + - Nidorina into Nidoqueen + - Nidoran♂ into Nidorino + - Nidoran♂ into Nidorino + - Nidorino into Nidoking + - Clefairy into Clefable + - Jigglypuff into Wigglytuff + - Zubat (Female) into Golbat (Female) + - Zubat (Female) into Golbat (Female) + - Golbat (Female) into Crobat + - Zubat (Male) into Golbat (Male) + - Zubat (Male) into Golbat (Male) + - Oddish into Gloom (Male) + - Oddish into Gloom (Male) + - Oddish into Gloom (Female) + - Oddish into Gloom (Male) + - Oddish into Gloom (Female) + - Gloom (Male) into Bellossom + - Gloom (Male) into Vileplume (Male) + - Gloom (Female) into Vileplume (Female) + - Paras into Parasect + - Venonat into Venomoth + - Diglett into Dugtrio + - Meowth into Persian + - Psyduck into Golduck + - Growlithe into Arcanine + - Poliwag into Poliwhirl + - Poliwag into Poliwhirl + - Poliwag into Poliwhirl + - Poliwag into Poliwhirl + - Poliwhirl into Politoed (Female) + - Poliwhirl into Poliwrath + - Poliwhirl into Politoed (Male) + - Abra into Kadabra (Female) + - Abra into Kadabra (Male) + - Abra into Kadabra (Female) + - Abra into Kadabra (Male) + - Kadabra (Male) into Alakazam (Male) + - Kadabra (Female) into Alakazam (Female) + - Machop into Machoke + - Machop into Machoke + - Machoke into Machamp + - Bellsprout into Weepinbell + - Bellsprout into Weepinbell + - Weepinbell into Victreebel + - Tentacool into Tentacruel + - Geodude into Graveler + - Geodude into Graveler + - Graveler into Golem + - Ponyta into Rapidash + - Slowpoke into Slowking + - Slowpoke into Slowbro + - Magnemite into Magneton + - Doduo (Female) into Dodrio (Female) + - Doduo (Male) into Dodrio (Male) + - Seel into Dewgong + - Grimer into Muk + - Shellder into Cloyster + - Gastly into Haunter + - Gastly into Haunter + - Haunter into Gengar + - Onix into Steelix (Female) + - Onix into Steelix (Male) + - Drowzee into Hypno (Female) + - Drowzee into Hypno (Male) + - Krabby into Kingler + - Voltorb into Electrode + - Exeggcute into Exeggutor + - Cubone into Marowak + - Koffing into Weezing + - Rhyhorn (Female) into Rhydon (Female) + - Rhyhorn (Male) into Rhydon (Male) + - Chansey into Blissey + - Horsea into Seadra + - Horsea into Seadra + - Seadra into Kingdra + - Goldeen (Female) into Seaking (Female) + - Goldeen (Male) into Seaking (Male) + - Staryu into Starmie + - Scyther (Female) into Scizor (Female) + - Scyther (Male) into Scizor (Male) + - Magikarp (Female) into Gyarados (Female) + - Magikarp (Male) into Gyarados (Male) + - Eevee (Female) into Vaporeon + - Eevee (Female) into Jolteon + - Eevee (Female) into Umbreon + - Eevee (Female) into Flareon + - Eevee (Female) into Espeon + - Porygon into Porygon2 + - Dratini into Dragonair + - Dratini into Dragonair + - Dragonair into Dragonite + - Chikorita into Bayleef + - Chikorita into Bayleef + - Chikorita into Bayleef + - Bayleef into Meganium (Female) + - Bayleef into Meganium (Male) + - Cyndaquil into Quilava + - Cyndaquil into Quilava + - Quilava into Typhlosion + - Totodile into Croconaw + - Totodile into Croconaw + - Croconaw into Feraligatr + - Sentret into Furret + - Hoothoot into Noctowl + - Ledyba (Female) into Ledian (Female) + - Ledyba (Male) into Ledian (Male) + - Spinarak into Ariados + - Chinchou into Lanturn + - Natu into Xatu (Female) + - Natu into Xatu (Male) + - Marill into Azumarill + - Hoppip into Skiploom + - Hoppip into Skiploom + - Skiploom into Jumpluff + - Sunkern into Sunflora + - Wooper (Female) into Quagsire (Female) + - Wooper (Male) into Quagsire (Male) + - Pineco into Forretress + - Snubbull into Granbull + - Teddiursa into Ursaring (Female) + - Teddiursa into Ursaring (Male) + - Slugma into Magcargo + - Swinub into Piloswine (Female) + - Swinub into Piloswine (Male) + - Houndour into Houndoom (Male) + - Houndour into Houndoom (Female) + - Phanpy into Donphan (Male) + - Phanpy into Donphan (Female) + - Larvitar into Pupitar + - Larvitar into Pupitar + - Pupitar into Tyranitar + Breed: + - Pikachu (Male) to get Pichu + - Pikachu (Female) to get Pichu + - Clefairy to get Cleffa + - Jigglypuff to get Igglybuff + - Togetic to get Togepi + - Hitmontop to get Tyrogue + - Hitmonchan to get Tyrogue + - Hitmonlee to get Tyrogue + - Jynx to get Smoochum + - Electabuzz to get Elekid + - Magmar to get Magby +Play Gold: + Catch: + - Mankey: 2 time(s) + - Articuno: 1 time(s) + - Zapdos: 1 time(s) + - Moltres: 1 time(s) + - Mareep: 3 time(s) + - Girafarig (Female): 1 time(s) + - Girafarig (Male): 1 time(s) + - Remoraid: 3 time(s) + Evolve: + - Mankey into Primeape + - Mareep into Flaaffy + - Mareep into Flaaffy + - Flaaffy into Ampharos + - Remoraid into Octillery (Male) + - Remoraid into Octillery (Female) +Play Silver: + Catch: + - Vulpix: 2 time(s) + Evolve: + - Vulpix into Ninetales +Play Red: + Catch: + - Bulbasaur: 4 time(s) + - Charmander: 3 time(s) + - Squirtle: 3 time(s) + - Omanyte: 2 time(s) + - Kabuto: 2 time(s) + - Aerodactyl: 1 time(s) + - Mewtwo: 1 time(s) + Evolve: + - Bulbasaur into Ivysaur + - Bulbasaur into Ivysaur + - Bulbasaur into Ivysaur + - Ivysaur into Venusaur (Male) + - Ivysaur into Venusaur (Female) + - Charmander into Charmeleon + - Charmander into Charmeleon + - Charmeleon into Charizard + - Squirtle into Wartortle + - Squirtle into Wartortle + - Wartortle into Blastoise + - Omanyte into Omastar + - Kabuto into Kabutops +Play Black 2: + Catch: + - Eevee (Female): 3 time(s) + - Murkrow (Male): 1 time(s) + - Sneasel (Female): 1 time(s) + - Piloswine (Female): 1 time(s) + - Lickitung: 1 time(s) + - Aipom (Male): 1 time(s) + - Piloswine (Male): 1 time(s) + - Tangela: 2 time(s) + - Magneton: 1 time(s) + - Sneasel (Male): 1 time(s) + - Yanma: 1 time(s) + - Gligar (Female): 1 time(s) + - Aipom (Female): 1 time(s) + - Lotad: 4 time(s) + - Seedot: 5 time(s) + - Taillow: 2 time(s) + - Wingull: 2 time(s) + - Surskit: 2 time(s) + - Shroomish: 2 time(s) + - Slakoth: 3 time(s) + - Makuhita: 2 time(s) + - Azurill: 1 time(s) + - Nosepass: 2 time(s) + - Aron: 3 time(s) + - Meditite (Female): 2 time(s) + - Meditite (Male): 2 time(s) + - Electrike: 2 time(s) + - Plusle: 1 time(s) + - Volbeat: 1 time(s) + - Illumise: 1 time(s) + - Roselia (Female): 2 time(s) + - Roselia (Male): 2 time(s) + - Gulpin (Female): 2 time(s) + - Gulpin (Male): 2 time(s) + - Carvanha: 2 time(s) + - Wailmer: 2 time(s) + - Spoink: 2 time(s) + - Trapinch: 3 time(s) + - Cacnea: 3 time(s) + - Swablu: 2 time(s) + - Zangoose: 1 time(s) + - Seviper: 1 time(s) + - Lunatone: 1 time(s) + - Solrock: 1 time(s) + - Barboach: 2 time(s) + - Corphish: 2 time(s) + - Baltoy: 2 time(s) + - Lileep: 2 time(s) + - Anorith: 2 time(s) + - Feebas: 3 time(s) + - Castform: 1 time(s) + - Kecleon: 1 time(s) + - Shuppet: 2 time(s) + - Tropius: 1 time(s) + - Absol: 1 time(s) + - Wynaut: 1 time(s) + - Spheal: 3 time(s) + - Clamperl: 3 time(s) + - Relicanth (Female): 1 time(s) + - Relicanth (Male): 1 time(s) + - Luvdisc: 1 time(s) + - Bagon: 3 time(s) + - Beldum: 3 time(s) + - Regirock: 1 time(s) + - Regice: 1 time(s) + - Registeel: 1 time(s) + - Latios: 1 time(s) + - Turtwig: 3 time(s) + - Chimchar: 3 time(s) + - Piplup: 3 time(s) + - Bidoof (Female): 2 time(s) + - Bidoof (Male): 2 time(s) + - Budew: -1 time(s) + - Cranidos: 2 time(s) + - Shieldon: 2 time(s) + - Combee (Female): 2 time(s) + - Combee (Male): 1 time(s) + - Pachirisu (Female): 1 time(s) + - Pachirisu (Male): 1 time(s) + - Buizel (Female): 2 time(s) + - Buizel (Male): 2 time(s) + - Drifloon: 2 time(s) + - Buneary: 2 time(s) + - Stunky: 2 time(s) + - Bronzor: 2 time(s) + - Bonsly: 1 time(s) + - Happiny: 1 time(s) + - Chatot: 1 time(s) + - Gible (Female): 3 time(s) + - Gible (Male): 3 time(s) + - Munchlax: 1 time(s) + - Riolu: 1 time(s) + - Hippopotas (Female): 2 time(s) + - Hippopotas (Male): 2 time(s) + - Skorupi: 2 time(s) + - Croagunk (Female): 2 time(s) + - Croagunk (Male): 2 time(s) + - Carnivine: 1 time(s) + - Finneon (Female): 2 time(s) + - Finneon (Male): 2 time(s) + - Mantyke: 1 time(s) + - Uxie: 1 time(s) + - Mesprit: 1 time(s) + - Azelf: 1 time(s) + - Heatran: 1 time(s) + - Regigigas: 1 time(s) + - Cresselia: 1 time(s) + - Snivy: 3 time(s) + - Tepig: 3 time(s) + - Oshawott: 3 time(s) + - Patrat: 2 time(s) + - Lillipup: 3 time(s) + - Purrloin: 2 time(s) + - Pansage: 2 time(s) + - Pansear: 2 time(s) + - Panpour: 2 time(s) + - Munna: 2 time(s) + - Pidove: 4 time(s) + - Blitzle: 2 time(s) + - Roggenrola: 3 time(s) + - Woobat: 2 time(s) + - Drilbur: 2 time(s) + - Audino: 1 time(s) + - Timburr: 3 time(s) + - Tympole: 3 time(s) + - Throh: 1 time(s) + - Sawk: 1 time(s) + - Sewaddle: 3 time(s) + - Venipede: 3 time(s) + - Cottonee: 2 time(s) + - Basculin (Blue-Striped Form): 1 time(s) + - Basculin (Red-Striped Form): 1 time(s) + - Basculin (White-striped Form): 1 time(s) + - Sandile: 3 time(s) + - Darumaka: 2 time(s) + - Darmanitan (Galarian Standard Mode): 1 time(s) + - Maractus: 1 time(s) + - Dwebble: 2 time(s) + - Scraggy: 2 time(s) + - Sigilyph: 1 time(s) + - Yamask: 2 time(s) + - Tirtouga: 2 time(s) + - Archen: 2 time(s) + - Trubbish: 2 time(s) + - Zorua: 2 time(s) + - Minccino: 2 time(s) + - Gothita: 3 time(s) + - Ducklett: 2 time(s) + - Vanillite: 3 time(s) + - Deerling (Spring Form): 2 time(s) + - Emolga: 1 time(s) + - Karrablast: 2 time(s) + - Foongus: 2 time(s) + - Frillish (Female): 2 time(s) + - Frillish (Male): 2 time(s) + - Alomomola: 1 time(s) + - Joltik: 2 time(s) + - Ferroseed: 2 time(s) + - Klink: 3 time(s) + - Tynamo: 3 time(s) + - Elgyem: 2 time(s) + - Litwick: 3 time(s) + - Axew: 3 time(s) + - Cubchoo: 2 time(s) + - Cryogonal: 1 time(s) + - Shelmet: 2 time(s) + - Stunfisk: 1 time(s) + - Mienfoo: 2 time(s) + - Druddigon: 1 time(s) + - Golett: 2 time(s) + - Pawniard: 2 time(s) + - Bouffalant: 1 time(s) + - Vullaby: 2 time(s) + - Heatmor: 1 time(s) + - Durant: 1 time(s) + - Deino: 3 time(s) + - Larvesta: 2 time(s) + - Cobalion: 1 time(s) + - Terrakion: 1 time(s) + - Virizion: 1 time(s) + - Zekrom: 1 time(s) + - Kyurem: 1 time(s) + - Keldeo (Ordinary Forme): 1 time(s) + - Meloetta (Aria Forme): 1 time(s) + - Genesect: 1 time(s) + Evolve: + - Eevee (Female) into Sylveon + - Eevee (Female) into Leafeon + - Eevee (Female) into Glaceon + - Murkrow (Male) into Honchkrow + - Sneasel (Female) into Weavile (Female) + - Piloswine (Female) into Mamoswine (Female) + - Lickitung into Lickilicky + - Aipom (Male) into Ambipom (Male) + - Piloswine (Male) into Mamoswine (Male) + - Tangela into Tangrowth (Female) + - Tangela into Tangrowth (Male) + - Magneton into Magnezone + - Sneasel (Male) into Weavile (Male) + - Yanma into Yanmega + - Gligar (Female) into Gliscor + - Aipom (Female) into Ambipom (Female) + - Lotad into Lombre + - Lotad into Lombre + - Lotad into Lombre + - Lombre into Ludicolo (Female) + - Lombre into Ludicolo (Male) + - Seedot into Nuzleaf (Female) + - Seedot into Nuzleaf (Male) + - Seedot into Nuzleaf (Female) + - Seedot into Nuzleaf (Male) + - Nuzleaf (Female) into Shiftry (Female) + - Nuzleaf (Male) into Shiftry (Male) + - Taillow into Swellow + - Wingull into Pelipper + - Surskit into Masquerain + - Shroomish into Breloom + - Slakoth into Vigoroth + - Slakoth into Vigoroth + - Vigoroth into Slaking + - Makuhita into Hariyama + - Nosepass into Probopass + - Aron into Lairon + - Aron into Lairon + - Lairon into Aggron + - Meditite (Female) into Medicham (Female) + - Meditite (Male) into Medicham (Male) + - Electrike into Manectric + - Roselia (Female) into Roserade (Female) + - Roselia (Male) into Roserade (Male) + - Gulpin (Female) into Swalot (Female) + - Gulpin (Male) into Swalot (Male) + - Carvanha into Sharpedo + - Wailmer into Wailord + - Spoink into Grumpig + - Trapinch into Vibrava + - Trapinch into Vibrava + - Vibrava into Flygon + - Cacnea into Cacturne (Male) + - Cacnea into Cacturne (Female) + - Swablu into Altaria + - Barboach into Whiscash + - Corphish into Crawdaunt + - Baltoy into Claydol + - Lileep into Cradily + - Anorith into Armaldo + - Feebas into Milotic (Male) + - Feebas into Milotic (Female) + - Shuppet into Banette + - Spheal into Sealeo + - Spheal into Sealeo + - Sealeo into Walrein + - Clamperl into Gorebyss + - Clamperl into Huntail + - Bagon into Shelgon + - Bagon into Shelgon + - Shelgon into Salamence + - Beldum into Metang + - Beldum into Metang + - Metang into Metagross + - Turtwig into Grotle + - Turtwig into Grotle + - Grotle into Torterra + - Chimchar into Monferno + - Chimchar into Monferno + - Monferno into Infernape + - Piplup into Prinplup + - Piplup into Prinplup + - Prinplup into Empoleon + - Bidoof (Female) into Bibarel (Female) + - Bidoof (Male) into Bibarel (Male) + - Cranidos into Rampardos + - Shieldon into Bastiodon + - Combee (Female) into Vespiquen + - Buizel (Female) into Floatzel (Female) + - Buizel (Male) into Floatzel (Male) + - Drifloon into Drifblim + - Buneary into Lopunny + - Stunky into Skuntank + - Bronzor into Bronzong + - Gible (Female) into Gabite (Female) + - Gible (Female) into Gabite (Female) + - Gabite (Female) into Garchomp (Female) + - Gible (Male) into Gabite (Male) + - Gible (Male) into Gabite (Male) + - Gabite (Male) into Garchomp (Male) + - Hippopotas (Female) into Hippowdon (Female) + - Hippopotas (Male) into Hippowdon (Male) + - Skorupi into Drapion + - Croagunk (Female) into Toxicroak (Female) + - Croagunk (Male) into Toxicroak (Male) + - Finneon (Female) into Lumineon (Female) + - Finneon (Male) into Lumineon (Male) + - Snivy into Servine + - Snivy into Servine + - Servine into Serperior + - Tepig into Pignite + - Tepig into Pignite + - Pignite into Emboar + - Oshawott into Dewott + - Oshawott into Dewott + - Dewott into Samurott + - Patrat into Watchog + - Lillipup into Herdier + - Lillipup into Herdier + - Herdier into Stoutland + - Purrloin into Liepard + - Pansage into Simisage + - Pansear into Simisear + - Panpour into Simipour + - Munna into Musharna + - Pidove into Tranquill + - Pidove into Tranquill + - Pidove into Tranquill + - Tranquill into Unfezant (Female) + - Tranquill into Unfezant (Male) + - Blitzle into Zebstrika + - Roggenrola into Boldore + - Roggenrola into Boldore + - Boldore into Gigalith + - Woobat into Swoobat + - Drilbur into Excadrill + - Timburr into Gurdurr + - Timburr into Gurdurr + - Gurdurr into Conkeldurr + - Tympole into Palpitoad + - Tympole into Palpitoad + - Palpitoad into Seismitoad + - Sewaddle into Swadloon + - Sewaddle into Swadloon + - Swadloon into Leavanny + - Venipede into Whirlipede + - Venipede into Whirlipede + - Whirlipede into Scolipede + - Cottonee into Whimsicott + - Sandile into Krokorok + - Sandile into Krokorok + - Krokorok into Krookodile + - Darumaka into Darmanitan (Standard Mode) + - Dwebble into Crustle + - Scraggy into Scrafty + - Yamask into Cofagrigus + - Tirtouga into Carracosta + - Archen into Archeops + - Trubbish into Garbodor + - Zorua into Zoroark + - Minccino into Cinccino + - Gothita into Gothorita + - Gothita into Gothorita + - Gothorita into Gothitelle + - Ducklett into Swanna + - Vanillite into Vanillish + - Vanillite into Vanillish + - Vanillish into Vanilluxe + - Deerling (Spring Form) into Sawsbuck (Spring Form) + - Karrablast into Escavalier + - Foongus into Amoonguss + - Frillish (Female) into Jellicent (Female) + - Frillish (Male) into Jellicent (Male) + - Joltik into Galvantula + - Ferroseed into Ferrothorn + - Klink into Klang + - Klink into Klang + - Klang into Klinklang + - Tynamo into Eelektrik + - Tynamo into Eelektrik + - Eelektrik into Eelektross + - Elgyem into Beheeyem + - Litwick into Lampent + - Litwick into Lampent + - Lampent into Chandelure + - Axew into Fraxure + - Axew into Fraxure + - Fraxure into Haxorus + - Cubchoo into Beartic + - Shelmet into Accelgor + - Mienfoo into Mienshao + - Golett into Golurk + - Pawniard into Bisharp + - Vullaby into Mandibuzz + - Deino into Zweilous + - Deino into Zweilous + - Zweilous into Hydreigon + - Larvesta into Volcarona + Breed: + - Roselia (Male) to get Budew + - Roselia (Female) to get Budew + - Lucario to get Riolu +Play White 2: + Catch: + - Skitty: 2 time(s) + - Minun: 1 time(s) + - Numel (Female): 2 time(s) + - Numel (Male): 2 time(s) + - Latias: 1 time(s) + - Glameow: 2 time(s) + - Mime Jr.: 1 time(s) + - Petilil: 2 time(s) + - Solosis: 3 time(s) + - Rufflet: 2 time(s) + - Reshiram: 1 time(s) + Evolve: + - Skitty into Delcatty + - Numel (Female) into Camerupt (Female) + - Numel (Male) into Camerupt (Male) + - Glameow into Purugly + - Petilil into Lilligant + - Solosis into Duosion + - Solosis into Duosion + - Duosion into Reuniclus + - Rufflet into Braviary +Play Diamond: + Catch: + - Rhydon (Female): 1 time(s) + - Rhydon (Male): 1 time(s) + - Poochyena: 2 time(s) + - Zigzagoon: 2 time(s) + - Wurmple: 7 time(s) + - Ralts: 4 time(s) + - Nincada: 2 time(s) + - Whismur: 3 time(s) + - Sableye: 1 time(s) + - Mawile: 1 time(s) + - Torkoal: 1 time(s) + - Spinda: 1 time(s) + - Duskull: 3 time(s) + - Chimecho: 1 time(s) + - Snorunt: 3 time(s) + - Starly (Female): 3 time(s) + - Starly (Male): 3 time(s) + - Kricketot (Female): 2 time(s) + - Kricketot (Male): 2 time(s) + - Shinx (Female): 3 time(s) + - Shinx (Male): 3 time(s) + - Burmy (Plant Cloak): 3 time(s) + - Cherubi: 2 time(s) + - Shellos (East Sea): 1 time(s) + - Shellos (West Sea): 2 time(s) + - Gastrodon (East Sea): 1 time(s) + - Chingling: 1 time(s) + - Spiritomb: 1 time(s) + - Snover (Female): 2 time(s) + - Snover (Male): 2 time(s) + - Rotom: 1 time(s) + - Dialga: 1 time(s) + - Giratina (Altered Forme): 1 time(s) + - Phione: 1 time(s) + - Darkrai: 1 time(s) + - Shaymin (Land Forme): 1 time(s) + - Arceus (Normal): 1 time(s) + Evolve: + - Rhydon (Female) into Rhyperior (Female) + - Rhydon (Male) into Rhyperior (Male) + - Poochyena into Mightyena + - Zigzagoon into Linoone + - Wurmple into Silcoon + - Wurmple into Silcoon + - Wurmple into Silcoon + - Wurmple into Cascoon + - Wurmple into Cascoon + - Wurmple into Cascoon + - Silcoon into Beautifly (Male) + - Silcoon into Beautifly (Female) + - Cascoon into Dustox (Male) + - Cascoon into Dustox (Female) + - Ralts into Kirlia + - Ralts into Kirlia + - Ralts into Kirlia + - Kirlia into Gardevoir + - Kirlia into Gallade + - Nincada into Ninjask + - Whismur into Loudred + - Whismur into Loudred + - Loudred into Exploud + - Duskull into Dusclops + - Duskull into Dusclops + - Dusclops into Dusknoir + - Snorunt into Froslass + - Snorunt into Glalie + - Starly (Female) into Staravia (Female) + - Starly (Female) into Staravia (Female) + - Staravia (Female) into Staraptor (Female) + - Starly (Male) into Staravia (Male) + - Starly (Male) into Staravia (Male) + - Staravia (Male) into Staraptor (Male) + - Kricketot (Female) into Kricketune (Female) + - Kricketot (Male) into Kricketune (Male) + - Shinx (Female) into Luxio (Female) + - Shinx (Female) into Luxio (Female) + - Luxio (Female) into Luxray (Female) + - Shinx (Male) into Luxio (Male) + - Shinx (Male) into Luxio (Male) + - Luxio (Male) into Luxray (Male) + - Burmy (Plant Cloak) into Wormadam (Plant Cloak) + - Burmy (Plant Cloak) into Mothim + - Cherubi into Cherrim (Overcast Form) + - Shellos (West Sea) into Gastrodon (West Sea) + - Snover (Female) into Abomasnow (Female) + - Snover (Male) into Abomasnow (Male) + Breed: + - Chimecho to get Chingling + - Manaphy to get Phione +Play Pearl: + Catch: + - Misdreavus: 1 time(s) + - Palkia: 1 time(s) + Evolve: + - Misdreavus into Mismagius +Play Platinum: + Catch: + - Magmar: 1 time(s) + - Electabuzz: 1 time(s) + - Giratina (Origin Forme): 1 time(s) + Evolve: + - Magmar into Magmortar + - Electabuzz into Electivire +Play HeartGold: + Catch: + - Treecko: 3 time(s) + - Torchic (Female): 3 time(s) + - Torchic (Male): 3 time(s) + - Mudkip: 3 time(s) + - Kyogre: 1 time(s) + - Rayquaza: 1 time(s) + Evolve: + - Treecko into Grovyle + - Treecko into Grovyle + - Grovyle into Sceptile + - Torchic (Female) into Combusken (Female) + - Torchic (Female) into Combusken (Female) + - Combusken (Female) into Blaziken (Female) + - Torchic (Male) into Combusken (Male) + - Torchic (Male) into Combusken (Male) + - Combusken (Male) into Blaziken (Male) + - Mudkip into Marshtomp + - Mudkip into Marshtomp + - Marshtomp into Swampert +Play SoulSilver: + Catch: + - Groudon: 1 time(s) +Play Omega Ruby: + Catch: + - Jirachi: 1 time(s) + - Deoxys (Normal Forme): 1 time(s) + - Victini: 1 time(s) + - Tornadus (Incarnate Forme): 1 time(s) + - Landorus (Incarnate Forme): 1 time(s) + - Greninja: 1 time(s) + - Binacle: 2 time(s) + - Skrelp: 2 time(s) + - Tyrunt: 2 time(s) + - Amaura: 2 time(s) + - Klefki: 1 time(s) + - Phantump: 2 time(s) + - Diancie: 1 time(s) + - Hoopa (Hoopa Confined): 1 time(s) + - Volcanion: 1 time(s) + Evolve: + - Binacle into Barbaracle + - Skrelp into Dragalge + - Tyrunt into Tyrantrum + - Amaura into Aurorus + - Phantump into Trevenant +Play Alpha Sapphire: + Catch: + - Thundurus (Incarnate Forme): 1 time(s) + - Clauncher: 2 time(s) + Evolve: + - Clauncher into Clawitzer +Play X: + Catch: + - Rotom (Fan Rotom): 1 time(s) + - Rotom (Frost Rotom): 1 time(s) + - Rotom (Heat Rotom): 1 time(s) + - Rotom (Mow Rotom): 1 time(s) + - Rotom (Wash Rotom): 1 time(s) + - Chespin: 3 time(s) + - Fennekin: 3 time(s) + - Froakie: 3 time(s) + - Bunnelby: 2 time(s) + - Fletchling: 3 time(s) + - Scatterbug: 3 time(s) + - Vivillon (Fancy Pattern): 1 time(s) + - Litleo: 3 time(s) + - Flabébé (Blue Flower): 1 time(s) + - Flabébé (Orange Flower): 1 time(s) + - Flabébé (White Flower): 1 time(s) + - Flabébé (Yellow Flower): 1 time(s) + - Skiddo: 2 time(s) + - Furfrou (Natural Form): 1 time(s) + - Honedge: 3 time(s) + - Carbink: 1 time(s) + - Goomy: 3 time(s) + - Pumpkaboo (Average Size): 2 time(s) + - Pumpkaboo (Large Size): 1 time(s) + - Pumpkaboo (Small Size): 2 time(s) + - Pumpkaboo (Super Size): 2 time(s) + - Xerneas (Neutral Mode): 1 time(s) + - Zygarde (10% Forme): 1 time(s) + - Zygarde (50% Forme): 1 time(s) + Evolve: + - Chespin into Quilladin + - Chespin into Quilladin + - Quilladin into Chesnaught + - Fennekin into Braixen + - Fennekin into Braixen + - Braixen into Delphox + - Froakie into Frogadier + - Froakie into Frogadier + - Frogadier into Greninja + - Bunnelby into Diggersby + - Fletchling into Fletchinder + - Fletchling into Fletchinder + - Fletchinder into Talonflame + - Scatterbug into Spewpa + - Scatterbug into Spewpa + - Spewpa into Vivillon (Meadow Pattern) + - Litleo into Pyroar (Male) + - Litleo into Pyroar (Female) + - Skiddo into Gogoat + - Honedge into Doublade + - Honedge into Doublade + - Doublade into Aegislash (Shield Forme) + - Goomy into Sliggoo + - Goomy into Sliggoo + - Sliggoo into Goodra + - Pumpkaboo (Average Size) into Gourgeist (Average Size) + - Pumpkaboo (Small Size) into Gourgeist (Small Size) + - Pumpkaboo (Super Size) into Gourgeist (Super Size) +Play Y: + Catch: + - Yveltal: 1 time(s) +Play Ultra Sun: + Catch: + - Rowlet: 3 time(s) + - Litten: 3 time(s) + - Popplio: 3 time(s) + - Pikipek: 3 time(s) + - Yungoos: 2 time(s) + - Grubbin: 3 time(s) + - Crabrawler: 2 time(s) + - Oricorio (Baile Style): 1 time(s) + - Oricorio (Pa'u Style): 1 time(s) + - Oricorio (Pom-Pom Style): 1 time(s) + - Oricorio (Sensu Style): 1 time(s) + - Cutiefly: 2 time(s) + - Rockruff: 2 time(s) + - Lycanroc (Midnight Form): 1 time(s) + - Wishiwashi (Solo Form): 1 time(s) + - Mareanie: 2 time(s) + - Mudbray: 2 time(s) + - Dewpider: 2 time(s) + - Fomantis: 2 time(s) + - Morelull: 2 time(s) + - Salandit: 2 time(s) + - Stufful: 2 time(s) + - Bounsweet: 3 time(s) + - Comfey: 1 time(s) + - Passimian: 1 time(s) + - Wimpod: 2 time(s) + - Sandygast: 2 time(s) + - Pyukumuku: 1 time(s) + - Type: Null: 2 time(s) + - Minior (Blue Core): 1 time(s) + - Minior (Green Core): 1 time(s) + - Minior (Indigo Core): 1 time(s) + - Minior (Meteor Form): 1 time(s) + - Minior (Orange Core): 1 time(s) + - Minior (Red Core): 1 time(s) + - Minior (Violet Core): 1 time(s) + - Minior (Yellow Core): 1 time(s) + - Komala: 1 time(s) + - Turtonator: 1 time(s) + - Togedemaru: 1 time(s) + - Mimikyu: 1 time(s) + - Bruxish: 1 time(s) + - Dhelmise: 1 time(s) + - Jangmo-o: 3 time(s) + - Tapu Koko: 1 time(s) + - Tapu Lele: 1 time(s) + - Tapu Bulu: 1 time(s) + - Tapu Fini: 1 time(s) + - Cosmog: 4 time(s) + - Nihilego: 1 time(s) + - Buzzwole: 1 time(s) + - Xurkitree: 1 time(s) + - Kartana: 1 time(s) + - Guzzlord: 1 time(s) + - Necrozma: 1 time(s) + - Magearna: 1 time(s) + - Poipole: 2 time(s) + - Blacephalon: 1 time(s) + - Zeraora: 1 time(s) + Evolve: + - Rowlet into Dartrix + - Rowlet into Dartrix + - Dartrix into Decidueye + - Litten into Torracat + - Litten into Torracat + - Torracat into Incineroar + - Popplio into Brionne + - Popplio into Brionne + - Brionne into Primarina + - Pikipek into Trumbeak + - Pikipek into Trumbeak + - Trumbeak into Toucannon + - Yungoos into Gumshoos + - Grubbin into Charjabug + - Grubbin into Charjabug + - Charjabug into Vikavolt + - Crabrawler into Crabominable + - Cutiefly into Ribombee + - Rockruff into Lycanroc (Midday Form) + - Mareanie into Toxapex + - Mudbray into Mudsdale + - Dewpider into Araquanid + - Fomantis into Lurantis + - Morelull into Shiinotic + - Salandit into Salazzle + - Stufful into Bewear + - Bounsweet into Steenee + - Bounsweet into Steenee + - Steenee into Tsareena + - Wimpod into Golisopod + - Sandygast into Palossand + - Type: Null into Silvally (Type: Normal) + - Jangmo-o into Hakamo-o + - Jangmo-o into Hakamo-o + - Hakamo-o into Kommo-o + - Cosmog into Cosmoem + - Cosmog into Cosmoem + - Cosmog into Cosmoem + - Cosmoem into Lunala + - Cosmoem into Solgaleo + - Poipole into Naganadel +Play Ultra Moon: + Catch: + - Oranguru: 1 time(s) + - Drampa: 1 time(s) + - Pheromosa: 1 time(s) + - Celesteela: 1 time(s) + - Stakataka: 1 time(s) +Play Sun: + Catch: + - Marshadow: 1 time(s) +Play Sword: + Catch: + - Sneasel (Female): 1 time(s) + - Basculin (Red-Striped Form): 2 time(s) + - Grookey: 3 time(s) + - Scorbunny: 3 time(s) + - Sobble: 3 time(s) + - Skwovet: 2 time(s) + - Rookidee: 3 time(s) + - Blipbug: 3 time(s) + - Nickit: 2 time(s) + - Gossifleur: 2 time(s) + - Wooloo: 2 time(s) + - Chewtle: 2 time(s) + - Yamper: 2 time(s) + - Rolycoly: 3 time(s) + - Applin: 3 time(s) + - Silicobra: 2 time(s) + - Cramorant: 1 time(s) + - Arrokuda: 2 time(s) + - Toxel: 2 time(s) + - Sizzlipede: 2 time(s) + - Clobbopus: 2 time(s) + - Sinistea: 2 time(s) + - Hatenna: 3 time(s) + - Impidimp: 3 time(s) + - Obstagoon: 1 time(s) + - Perrserker: 1 time(s) + - Sirfetch'd: 1 time(s) + - Mr. Rime: 1 time(s) + - Runerigus: 1 time(s) + - Milcery: 2 time(s) + - Alcremie (Caramel SwirlClover Sweet): 1 time(s) + - Alcremie (Caramel SwirlFlower Sweet): 1 time(s) + - Alcremie (Caramel SwirlLove Sweet): 1 time(s) + - Alcremie (Caramel SwirlRibbon Sweet): 1 time(s) + - Alcremie (Caramel SwirlStar Sweet): 1 time(s) + - Alcremie (Caramel SwirlStrawberry Sweet): 1 time(s) + - Alcremie (Gigantamax): 1 time(s) + - Alcremie (Lemon CreamBerry Sweet): 1 time(s) + - Alcremie (Lemon CreamClover Sweet): 1 time(s) + - Alcremie (Lemon CreamFlower Sweet): 1 time(s) + - Alcremie (Lemon CreamLove Sweet): 1 time(s) + - Alcremie (Lemon CreamRibbon Sweet): 1 time(s) + - Alcremie (Lemon CreamStar Sweet): 1 time(s) + - Alcremie (Lemon CreamStrawberry Sweet): 1 time(s) + - Alcremie (Matcha CreamBerry Sweet): 1 time(s) + - Alcremie (Matcha CreamClover Sweet): 1 time(s) + - Alcremie (Matcha CreamFlower Sweet): 1 time(s) + - Alcremie (Matcha CreamLove Sweet): 1 time(s) + - Alcremie (Matcha CreamRibbon Sweet): 1 time(s) + - Alcremie (Matcha CreamStar Sweet): 1 time(s) + - Alcremie (Matcha CreamStrawberry Sweet): 1 time(s) + - Alcremie (Mint CreamBerry Sweet): 1 time(s) + - Alcremie (Mint CreamClover Sweet): 1 time(s) + - Alcremie (Mint CreamFlower Sweet): 1 time(s) + - Alcremie (Mint CreamLove Sweet): 1 time(s) + - Alcremie (Mint CreamRibbon Sweet): 1 time(s) + - Alcremie (Mint CreamStar Sweet): 1 time(s) + - Alcremie (Mint CreamStrawberry Sweet): 1 time(s) + - Alcremie (Rainbow SwirlBerry Sweet): 1 time(s) + - Alcremie (Rainbow SwirlClover Sweet): 1 time(s) + - Alcremie (Rainbow SwirlFlower Sweet): 1 time(s) + - Alcremie (Rainbow SwirlLove Sweet): 1 time(s) + - Alcremie (Rainbow SwirlRibbon Sweet): 1 time(s) + - Alcremie (Rainbow SwirlStar Sweet): 1 time(s) + - Alcremie (Rainbow SwirlStrawberry Sweet): 1 time(s) + - Alcremie (Ruby CreamBerry Sweet): 1 time(s) + - Alcremie (Ruby CreamClover Sweet): 1 time(s) + - Alcremie (Ruby CreamFlower Sweet): 1 time(s) + - Alcremie (Ruby CreamLove Sweet): 1 time(s) + - Alcremie (Ruby CreamRibbon Sweet): 1 time(s) + - Alcremie (Ruby CreamStar Sweet): 1 time(s) + - Alcremie (Ruby CreamStrawberry Sweet): 1 time(s) + - Alcremie (Ruby SwirlBerry Sweet): 1 time(s) + - Alcremie (Ruby SwirlClover Sweet): 1 time(s) + - Alcremie (Ruby SwirlFlower Sweet): 1 time(s) + - Alcremie (Ruby SwirlLove Sweet): 1 time(s) + - Alcremie (Ruby SwirlRibbon Sweet): 1 time(s) + - Alcremie (Ruby SwirlStar Sweet): 1 time(s) + - Alcremie (Ruby SwirlStrawberry Sweet): 1 time(s) + - Alcremie (Salted CreamBerry Sweet): 1 time(s) + - Alcremie (Salted CreamClover Sweet): 1 time(s) + - Alcremie (Salted CreamFlower Sweet): 1 time(s) + - Alcremie (Salted CreamLove Sweet): 1 time(s) + - Alcremie (Salted CreamRibbon Sweet): 1 time(s) + - Alcremie (Salted CreamStar Sweet): 1 time(s) + - Alcremie (Salted CreamStrawberry Sweet): 1 time(s) + - Alcremie (Vanilla CreamBerry Sweet): 1 time(s) + - Alcremie (Vanilla CreamClover Sweet): 1 time(s) + - Alcremie (Vanilla CreamFlower Sweet): 1 time(s) + - Alcremie (Vanilla CreamLove Sweet): 1 time(s) + - Alcremie (Vanilla CreamRibbon Sweet): 1 time(s) + - Alcremie (Vanilla CreamStar Sweet): 1 time(s) + - Alcremie (Vanilla CreamStrawberry Sweet): 1 time(s) + - Falinks: 1 time(s) + - Pincurchin: 1 time(s) + - Snom: 2 time(s) + - Stonjourner: 1 time(s) + - Eiscue (Ice Face): 1 time(s) + - Indeedee (Female): 1 time(s) + - Indeedee (Male): 1 time(s) + - Morpeko (Full Belly Mode): 1 time(s) + - Cufant: 2 time(s) + - Dracozolt: 1 time(s) + - Arctozolt: 1 time(s) + - Dracovish: 1 time(s) + - Arctovish: 1 time(s) + - Duraludon: 1 time(s) + - Dreepy: 3 time(s) + - Zacian (Hero of Many Battles): 1 time(s) + - Eternatus: 1 time(s) + - Zarude: 1 time(s) + - Zarude (Dada): 1 time(s) + Evolve: + - Sneasel (Female) into Sneasler + - Basculin (Red-Striped Form) into Basculegion (Male) + - Basculin (Red-Striped Form) into Basculegion (Female) + - Grookey into Thwackey + - Grookey into Thwackey + - Thwackey into Rillaboom + - Scorbunny into Raboot + - Scorbunny into Raboot + - Raboot into Cinderace + - Sobble into Drizzile + - Sobble into Drizzile + - Drizzile into Inteleon + - Skwovet into Greedent + - Rookidee into Corvisquire + - Rookidee into Corvisquire + - Corvisquire into Corviknight + - Blipbug into Dottler + - Blipbug into Dottler + - Dottler into Orbeetle + - Nickit into Thievul + - Gossifleur into Eldegoss + - Wooloo into Dubwool + - Chewtle into Drednaw + - Yamper into Boltund + - Rolycoly into Carkol + - Rolycoly into Carkol + - Carkol into Coalossal + - Applin into Flapple + - Applin into Appletun + - Silicobra into Sandaconda + - Arrokuda into Barraskewda + - Toxel into Toxtricity (Amped Form) + - Sizzlipede into Centiskorch + - Clobbopus into Grapploct + - Sinistea into Polteageist + - Hatenna into Hattrem + - Hatenna into Hattrem + - Hattrem into Hatterene + - Impidimp into Morgrem + - Impidimp into Morgrem + - Morgrem into Grimmsnarl + - Milcery into Alcremie (Caramel SwirlBerry Sweet) + - Snom into Frosmoth + - Cufant into Copperajah + - Dreepy into Drakloak + - Dreepy into Drakloak + - Drakloak into Dragapult +Play Shield: + Catch: + - Cursola: 1 time(s) + - Zamazenta (Hero of Many Battles): 1 time(s) +Play Expansion Pass: + Catch: + - Scyther (Male): 1 time(s) + - Kubfu: 2 time(s) + - Regieleki: 1 time(s) + - Regidrago: 1 time(s) + - Glastrier: 1 time(s) + - Spectrier: 1 time(s) + - Calyrex: 1 time(s) + Evolve: + - Scyther (Male) into Kleavor + - Kubfu into Urshifu (Single Strike Style) +Play Legends Arceus: + Catch: + - Ursaring (Female): 1 time(s) + - Stantler: 1 time(s) + - Overqwil: 1 time(s) + - Enamorus (Incarnate Forme): 1 time(s) + Evolve: + - Ursaring (Female) into Ursaluna + - Stantler into Wyrdeer +Play Scarlet: + Catch: + - Dunsparce: 1 time(s) + - Applin: 3 time(s) + - Girafarig (Male): 1 time(s) + - Bisharp: 1 time(s) + - Primeape: 1 time(s) + - Sprigatito: 3 time(s) + - Fuecoco: 3 time(s) + - Quaxly: 3 time(s) + - Lechonk: 3 time(s) + - Tarountula: 2 time(s) + - Nymble: 2 time(s) + - Pawmi: 3 time(s) + - Tandemaus: 2 time(s) + - Maushold (Family of Three): 1 time(s) + - Fidough: 2 time(s) + - Smoliv: 3 time(s) + - Squawkabilly (Blue Plumage): 1 time(s) + - Squawkabilly (Green Plumage): 1 time(s) + - Squawkabilly (White Plumage): 1 time(s) + - Squawkabilly (Yellow Plumage): 1 time(s) + - Nacli: 3 time(s) + - Charcadet: 3 time(s) + - Tadbulb: 2 time(s) + - Wattrel: 2 time(s) + - Maschiff: 2 time(s) + - Shroodle: 2 time(s) + - Bramblin: 2 time(s) + - Toedscool: 2 time(s) + - Klawf: 1 time(s) + - Capsakid: 2 time(s) + - Rellor: 2 time(s) + - Flittle: 2 time(s) + - Tinkatink: 3 time(s) + - Wiglett: 2 time(s) + - Bombirdier: 1 time(s) + - Finizen: 2 time(s) + - Palafin (Zero Form): 1 time(s) + - Varoom: 2 time(s) + - Cyclizar: 1 time(s) + - Orthworm: 1 time(s) + - Glimmet: 2 time(s) + - Greavard: 2 time(s) + - Flamigo: 1 time(s) + - Cetoddle: 2 time(s) + - Veluza: 1 time(s) + - Dondozo: 1 time(s) + - Tatsugiri (Curly Form): 1 time(s) + - Tatsugiri (Droopy Form): 1 time(s) + - Tatsugiri (Stretchy Form): 1 time(s) + - Clodsire: 1 time(s) + - Dudunsparce (Three-Segment Form): 1 time(s) + - Great Tusk: 1 time(s) + - Scream Tail: 1 time(s) + - Brute Bonnet: 1 time(s) + - Flutter Mane: 1 time(s) + - Slither Wing: 1 time(s) + - Sandy Shocks: 1 time(s) + - Frigibax: 3 time(s) + - Gimmighoul (Chest Form): 2 time(s) + - Gimmighoul (Roaming Form): 1 time(s) + - Wo-Chien: 1 time(s) + - Chien-Pao: 1 time(s) + - Ting-Lu: 1 time(s) + - Chi-Yu: 1 time(s) + - Roaring Moon: 1 time(s) + - Koraidon: 1 time(s) + - Walking Wake: 1 time(s) + - Iron Leaves: 1 time(s) + Evolve: + - Dunsparce into Dudunsparce (Two-Segment Form) + - Applin into Dipplin + - Dipplin into Hydrapple + - Girafarig (Male) into Farigiraf + - Bisharp into Kingambit + - Primeape into Annihilape + - Sprigatito into Floragato + - Sprigatito into Floragato + - Floragato into Meowscarada + - Fuecoco into Crocalor + - Fuecoco into Crocalor + - Crocalor into Skeledirge + - Quaxly into Quaxwell + - Quaxly into Quaxwell + - Quaxwell into Quaquaval + - Lechonk into Oinkologne (Male) + - Lechonk into Oinkologne (Female) + - Tarountula into Spidops + - Nymble into Lokix + - Pawmi into Pawmo + - Pawmi into Pawmo + - Pawmo into Pawmot + - Tandemaus into Maushold (Family of Four) + - Fidough into Dachsbun + - Smoliv into Dolliv + - Smoliv into Dolliv + - Dolliv into Arboliva + - Nacli into Naclstack + - Nacli into Naclstack + - Naclstack into Garganacl + - Charcadet into Ceruledge + - Charcadet into Armarouge + - Tadbulb into Bellibolt + - Wattrel into Kilowattrel + - Maschiff into Mabosstiff + - Shroodle into Grafaiai + - Bramblin into Brambleghast + - Toedscool into Toedscruel + - Capsakid into Scovillain + - Rellor into Rabsca + - Flittle into Espathra + - Tinkatink into Tinkatuff + - Tinkatink into Tinkatuff + - Tinkatuff into Tinkaton + - Wiglett into Wugtrio + - Finizen into Palafin (Hero Form) + - Varoom into Revavroom + - Glimmet into Glimmora + - Greavard into Houndstone + - Cetoddle into Cetitan + - Frigibax into Arctibax + - Frigibax into Arctibax + - Arctibax into Baxcalibur + - Gimmighoul (Chest Form) into Gholdengo +Play Violet: + Catch: + - Iron Treads: 1 time(s) + - Iron Bundle: 1 time(s) + - Iron Hands: 1 time(s) + - Iron Jugulis: 1 time(s) + - Iron Moth: 1 time(s) + - Iron Thorns: 1 time(s) + - Iron Valiant: 1 time(s) + - Miraidon: 1 time(s) +Play The Hidden Treasure of Area Zero: + Catch: + - Duraludon: 1 time(s) + - Poltchageist: 1 time(s) + - Sinistcha: 1 time(s) + - Okidogi: 1 time(s) + - Munkidori: 1 time(s) + - Fezandipiti: 1 time(s) + - Ogerpon (Teal Mask): 1 time(s) + - Gouging Fire: 1 time(s) + - Raging Bolt: 1 time(s) + - Iron Boulder: 1 time(s) + - Iron Crown: 1 time(s) + - Terapagos (Normal Form): 1 time(s) + - Pecharunt: 1 time(s) + Evolve: + - Duraludon into Archaludon