diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0cb742b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,188 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
+# Godot
+.godot/
+*.x86_64
+*.pck
+
+# Godot-specific ignores
+.import/
+export.cfg
+export_presets.cfg
+
+# Imported translations (automatically generated from CSV files)
+*.translation
+
+# Mono-specific ignores
+.mono/
+data_*/
+mono_crash.*.json
+.vs/
+*.import
+
+# Mac bs
+.DS_Store
+
+# Random stuff
+__pycache__/
+chkpts/
+figures/
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bb9b409
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Peter DV
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/addons/Todo_Manager/CONTRIBUTING.md b/addons/Todo_Manager/CONTRIBUTING.md
new file mode 100644
index 0000000..5969b61
--- /dev/null
+++ b/addons/Todo_Manager/CONTRIBUTING.md
@@ -0,0 +1,23 @@
+## Contributing to TODO Manager
+Firstly, thank you for being interested in contributing to the Godot TODO Manager plugin!
+TODO Manager has benefitted greatly from enthusiastic users who have suggested new features, noticed bugs, and contributed code to the plugin.
+
+### Code Style Guide
+For the sake of clarity, TODO Manager takes advantage of GDScripts optional static typing in most circumstances.
+In particular, when declaring variables use colons to infer the type where possible:
+
+`todo := "#TODO"`
+
+If the type is not obvious then explicit typing is desirable:
+
+`items : PoolStringArray = todo.split()`
+
+Typed arguments and return values for functions are required:
+```
+func example(name: String, amount: int) -> Array:
+ # code
+ return array_of_names
+```
+
+For more info on static typing in Godot please refer to the documentation.
+https://docs.godotengine.org/en/stable/getting_started/scripting/gdscript/static_typing.html
diff --git a/addons/Todo_Manager/ColourPicker.gd b/addons/Todo_Manager/ColourPicker.gd
new file mode 100644
index 0000000..39a3f9a
--- /dev/null
+++ b/addons/Todo_Manager/ColourPicker.gd
@@ -0,0 +1,17 @@
+@tool
+extends HBoxContainer
+
+var colour : Color
+var title : String:
+ set = set_title
+var index : int
+
+@onready var colour_picker := $TODOColourPickerButton
+
+func _ready() -> void:
+ $TODOColourPickerButton.color = colour
+ $Label.text = title
+
+func set_title(value: String) -> void:
+ title = value
+ $Label.text = value
diff --git a/addons/Todo_Manager/Current.gd b/addons/Todo_Manager/Current.gd
new file mode 100644
index 0000000..d3961c9
--- /dev/null
+++ b/addons/Todo_Manager/Current.gd
@@ -0,0 +1,44 @@
+@tool
+extends Panel
+
+signal tree_built # used for debugging
+
+const Todo := preload("res://addons/Todo_Manager/todo_class.gd")
+const TodoItem := preload("res://addons/Todo_Manager/todoItem_class.gd")
+
+var _sort_alphabetical := true
+
+@onready var tree := $Tree as Tree
+
+func build_tree(todo_item : TodoItem, patterns : Array, cased_patterns : Array[String]) -> void:
+ tree.clear()
+ var root := tree.create_item()
+ root.set_text(0, "Scripts")
+ var script := tree.create_item(root)
+ script.set_text(0, todo_item.get_short_path() + " -------")
+ script.set_metadata(0, todo_item)
+ for todo in todo_item.todos:
+ var item := tree.create_item(script)
+ var content_header : String = todo.content
+ if "\n" in todo.content:
+ content_header = content_header.split("\n")[0] + "..."
+ item.set_text(0, "(%0) - %1".format([todo.line_number, content_header], "%_"))
+ item.set_tooltip_text(0, todo.content)
+ item.set_metadata(0, todo)
+ for i in range(0, len(cased_patterns)):
+ if cased_patterns[i] == todo.pattern:
+ item.set_custom_color(0, patterns[i][1])
+ emit_signal("tree_built")
+
+
+func sort_alphabetical(a, b) -> bool:
+ if a.script_path > b.script_path:
+ return true
+ else:
+ return false
+
+func sort_backwards(a, b) -> bool:
+ if a.script_path < b.script_path:
+ return true
+ else:
+ return false
diff --git a/addons/Todo_Manager/Dock.gd b/addons/Todo_Manager/Dock.gd
new file mode 100644
index 0000000..c71b6b2
--- /dev/null
+++ b/addons/Todo_Manager/Dock.gd
@@ -0,0 +1,297 @@
+@tool
+extends Control
+
+#signal tree_built # used for debugging
+enum { CASE_INSENSITIVE, CASE_SENSITIVE }
+
+const Project := preload("res://addons/Todo_Manager/Project.gd")
+const Current := preload("res://addons/Todo_Manager/Current.gd")
+
+const Todo := preload("res://addons/Todo_Manager/todo_class.gd")
+const TodoItem := preload("res://addons/Todo_Manager/todoItem_class.gd")
+const ColourPicker := preload("res://addons/Todo_Manager/UI/ColourPicker.tscn")
+const Pattern := preload("res://addons/Todo_Manager/UI/Pattern.tscn")
+const DEFAULT_PATTERNS := [["\\bTODO\\b", Color("96f1ad"), CASE_INSENSITIVE], ["\\bHACK\\b", Color("d5bc70"), CASE_INSENSITIVE], ["\\bFIXME\\b", Color("d57070"), CASE_INSENSITIVE]]
+const DEFAULT_SCRIPT_COLOUR := Color("ccced3")
+const DEFAULT_SCRIPT_NAME := false
+const DEFAULT_SORT := true
+
+var plugin : EditorPlugin
+
+var todo_items : Array
+
+var script_colour := Color("ccced3")
+var ignore_paths : Array[String] = []
+var full_path := false
+var auto_refresh := true
+var builtin_enabled := false
+var _sort_alphabetical := true
+
+var patterns := [["\\bTODO\\b", Color("96f1ad"), CASE_INSENSITIVE], ["\\bHACK\\b", Color("d5bc70"), CASE_INSENSITIVE], ["\\bFIXME\\b", Color("d57070"), CASE_INSENSITIVE]]
+
+
+@onready var tabs := $VBoxContainer/TabContainer as TabContainer
+@onready var project := $VBoxContainer/TabContainer/Project as Project
+@onready var current := $VBoxContainer/TabContainer/Current as Current
+@onready var project_tree := $VBoxContainer/TabContainer/Project/Tree as Tree
+@onready var current_tree := $VBoxContainer/TabContainer/Current/Tree as Tree
+@onready var settings_panel := $VBoxContainer/TabContainer/Settings as Panel
+@onready var colours_container := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer3/Colours as VBoxContainer
+@onready var pattern_container := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns as VBoxContainer
+@onready var ignore_textbox := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/IgnorePaths/TextEdit as LineEdit
+@onready var auto_refresh_button := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/RefreshCheckButton as CheckButton
+
+func _ready() -> void:
+ load_config()
+ populate_settings()
+
+
+func build_tree() -> void:
+ if tabs:
+ match tabs.current_tab:
+ 0:
+ project.build_tree(todo_items, ignore_paths, patterns, plugin.cased_patterns, _sort_alphabetical, full_path)
+ create_config_file()
+ 1:
+ current.build_tree(get_active_script(), patterns, plugin.cased_patterns)
+ create_config_file()
+ 2:
+ pass
+ _:
+ pass
+
+
+func get_active_script() -> TodoItem:
+ var current_script : Script = plugin.get_editor_interface().get_script_editor().get_current_script()
+ if current_script:
+ var script_path = current_script.resource_path
+ for todo_item in todo_items:
+ if todo_item.script_path == script_path:
+ return todo_item
+
+ # nothing found
+ var todo_item := TodoItem.new(script_path, [])
+ return todo_item
+ else:
+ # not a script
+ var todo_item := TodoItem.new("res://Documentation", [])
+ return todo_item
+
+
+func go_to_script(script_path: String, line_number : int = 0) -> void:
+ if plugin.get_editor_interface().get_editor_settings().get_setting("text_editor/external/use_external_editor"):
+ var exec_path = plugin.get_editor_interface().get_editor_settings().get_setting("text_editor/external/exec_path")
+ var args := get_exec_flags(exec_path, script_path, line_number)
+ OS.execute(exec_path, args)
+ else:
+ var script := load(script_path)
+ plugin.get_editor_interface().edit_resource(script)
+ plugin.get_editor_interface().get_script_editor().goto_line(line_number - 1)
+
+func get_exec_flags(editor_path : String, script_path : String, line_number : int) -> PackedStringArray:
+ var args : PackedStringArray
+ var script_global_path = ProjectSettings.globalize_path(script_path)
+
+ if editor_path.ends_with("code.cmd") or editor_path.ends_with("code"): ## VS Code
+ args.append(ProjectSettings.globalize_path("res://"))
+ args.append("--goto")
+ args.append(script_global_path + ":" + str(line_number))
+
+ elif editor_path.ends_with("rider64.exe") or editor_path.ends_with("rider"): ## Rider
+ args.append("--line")
+ args.append(str(line_number))
+ args.append(script_global_path)
+
+ else: ## Atom / Sublime
+ args.append(script_global_path + ":" + str(line_number))
+
+ return args
+
+func sort_alphabetical(a, b) -> bool:
+ if a.script_path > b.script_path:
+ return true
+ else:
+ return false
+
+func sort_backwards(a, b) -> bool:
+ if a.script_path < b.script_path:
+ return true
+ else:
+ return false
+
+
+func populate_settings() -> void:
+ for i in patterns.size():
+ ## Create Colour Pickers
+ var colour_picker: Variant = ColourPicker.instantiate()
+ colour_picker.colour = patterns[i][1]
+ colour_picker.title = patterns[i][0]
+ colour_picker.index = i
+ colours_container.add_child(colour_picker)
+ colour_picker.colour_picker.color_changed.connect(change_colour.bind(i))
+
+ ## Create Patterns
+ var pattern_edit: Variant = Pattern.instantiate()
+ pattern_edit.text = patterns[i][0]
+ pattern_edit.index = i
+ pattern_container.add_child(pattern_edit)
+ pattern_edit.line_edit.text_changed.connect(change_pattern.bind(i,
+ colour_picker))
+ pattern_edit.remove_button.pressed.connect(remove_pattern.bind(i,
+ pattern_edit, colour_picker))
+ pattern_edit.case_checkbox.button_pressed = patterns[i][2]
+ pattern_edit.case_checkbox.toggled.connect(case_sensitive_pattern.bind(i))
+
+ var pattern_button := $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns/AddPatternButton
+ $VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns.move_child(pattern_button, 0)
+
+ # path filtering
+ var ignore_paths_field := ignore_textbox
+ if not ignore_paths_field.is_connected("text_changed", _on_ignore_paths_changed):
+ ignore_paths_field.connect("text_changed", _on_ignore_paths_changed)
+ var ignore_paths_text := ""
+ for path in ignore_paths:
+ ignore_paths_text += path + ", "
+ ignore_paths_text = ignore_paths_text.trim_suffix(", ")
+ ignore_paths_field.text = ignore_paths_text
+
+ auto_refresh_button.button_pressed = auto_refresh
+
+
+func rebuild_settings() -> void:
+ for node in colours_container.get_children():
+ node.queue_free()
+ for node in pattern_container.get_children():
+ if node is Button:
+ continue
+ node.queue_free()
+ populate_settings()
+
+
+#### CONFIG FILE ####
+func create_config_file() -> void:
+ var config = ConfigFile.new()
+ config.set_value("scripts", "full_path", full_path)
+ config.set_value("scripts", "sort_alphabetical", _sort_alphabetical)
+ config.set_value("scripts", "script_colour", script_colour)
+ config.set_value("scripts", "ignore_paths", ignore_paths)
+
+ config.set_value("patterns", "patterns", patterns)
+
+ config.set_value("config", "auto_refresh", auto_refresh)
+ config.set_value("config", "builtin_enabled", builtin_enabled)
+
+ var err = config.save("res://addons/Todo_Manager/todo.cfg")
+
+
+func load_config() -> void:
+ var config := ConfigFile.new()
+ if config.load("res://addons/Todo_Manager/todo.cfg") == OK:
+ full_path = config.get_value("scripts", "full_path", DEFAULT_SCRIPT_NAME)
+ _sort_alphabetical = config.get_value("scripts", "sort_alphabetical", DEFAULT_SORT)
+ script_colour = config.get_value("scripts", "script_colour", DEFAULT_SCRIPT_COLOUR)
+ ignore_paths = config.get_value("scripts", "ignore_paths", [] as Array[String])
+ patterns = config.get_value("patterns", "patterns", DEFAULT_PATTERNS)
+ auto_refresh = config.get_value("config", "auto_refresh", true)
+ builtin_enabled = config.get_value("config", "builtin_enabled", false)
+ else:
+ create_config_file()
+
+
+#### Events ####
+func _on_SettingsButton_toggled(button_pressed: bool) -> void:
+ settings_panel.visible = button_pressed
+ if button_pressed == false:
+ create_config_file()
+# plugin.find_tokens_from_path(plugin.script_cache)
+ if auto_refresh:
+ plugin.rescan_files(true)
+
+func _on_Tree_item_activated() -> void:
+ var item : TreeItem
+ match tabs.current_tab:
+ 0:
+ item = project_tree.get_selected()
+ 1:
+ item = current_tree.get_selected()
+ if item.get_metadata(0) is Todo:
+ var todo : Todo = item.get_metadata(0)
+ call_deferred("go_to_script", todo.script_path, todo.line_number)
+ else:
+ var todo_item = item.get_metadata(0)
+ call_deferred("go_to_script", todo_item.script_path)
+
+func _on_FullPathCheckBox_toggled(button_pressed: bool) -> void:
+ full_path = button_pressed
+
+func _on_ScriptColourPickerButton_color_changed(color: Color) -> void:
+ script_colour = color
+
+func _on_RescanButton_pressed() -> void:
+ plugin.rescan_files(true)
+
+func change_colour(colour: Color, index: int) -> void:
+ patterns[index][1] = colour
+
+func change_pattern(value: String, index: int, this_colour: Node) -> void:
+ patterns[index][0] = value
+ this_colour.title = value
+ plugin.rescan_files(true)
+
+func remove_pattern(index: int, this: Node, this_colour: Node) -> void:
+ patterns.remove_at(index)
+ this.queue_free()
+ this_colour.queue_free()
+ plugin.rescan_files(true)
+
+func case_sensitive_pattern(active: bool, index: int) -> void:
+ if active:
+ patterns[index][2] = CASE_SENSITIVE
+ else:
+ patterns[index][2] = CASE_INSENSITIVE
+ plugin.rescan_files(true)
+
+func _on_DefaultButton_pressed() -> void:
+ patterns = DEFAULT_PATTERNS.duplicate(true)
+ _sort_alphabetical = DEFAULT_SORT
+ script_colour = DEFAULT_SCRIPT_COLOUR
+ full_path = DEFAULT_SCRIPT_NAME
+ rebuild_settings()
+ plugin.rescan_files(true)
+
+func _on_AlphSortCheckBox_toggled(button_pressed: bool) -> void:
+ _sort_alphabetical = button_pressed
+ plugin.rescan_files(true)
+
+func _on_AddPatternButton_pressed() -> void:
+ patterns.append(["\\bplaceholder\\b", Color.WHITE, CASE_INSENSITIVE])
+ rebuild_settings()
+
+func _on_RefreshCheckButton_toggled(button_pressed: bool) -> void:
+ auto_refresh = button_pressed
+
+func _on_Timer_timeout() -> void:
+ plugin.refresh_lock = false
+
+func _on_ignore_paths_changed(new_text: String) -> void:
+ var text = ignore_textbox.text
+ var split: Array = text.split(',')
+ ignore_paths.clear()
+ for elem in split:
+ if elem == " " || elem == "":
+ continue
+ ignore_paths.push_front(elem.lstrip(' ').rstrip(' '))
+ # validate so no empty string slips through (all paths ignored)
+ var i := 0
+ for path in ignore_paths:
+ if (path == "" || path == " "):
+ ignore_paths.remove_at(i)
+ i += 1
+ plugin.rescan_files(true)
+
+func _on_TabContainer_tab_changed(tab: int) -> void:
+ build_tree()
+
+func _on_BuiltInCheckButton_toggled(button_pressed: bool) -> void:
+ builtin_enabled = button_pressed
+ plugin.rescan_files(true)
diff --git a/addons/Todo_Manager/Pattern.gd b/addons/Todo_Manager/Pattern.gd
new file mode 100644
index 0000000..4e610af
--- /dev/null
+++ b/addons/Todo_Manager/Pattern.gd
@@ -0,0 +1,21 @@
+@tool
+extends HBoxContainer
+
+
+var text : String : set = set_text
+var disabled : bool
+var index : int
+
+@onready var line_edit := $LineEdit as LineEdit
+@onready var remove_button := $RemoveButton as Button
+@onready var case_checkbox := %CaseSensativeCheckbox as CheckBox
+
+func _ready() -> void:
+ line_edit.text = text
+ remove_button.disabled = disabled
+
+
+func set_text(value: String) -> void:
+ text = value
+ if line_edit:
+ line_edit.text = value
diff --git a/addons/Todo_Manager/Project.gd b/addons/Todo_Manager/Project.gd
new file mode 100644
index 0000000..4af0847
--- /dev/null
+++ b/addons/Todo_Manager/Project.gd
@@ -0,0 +1,73 @@
+@tool
+extends Panel
+
+signal tree_built # used for debugging
+
+const Todo := preload("res://addons/Todo_Manager/todo_class.gd")
+
+var _sort_alphabetical := true
+var _full_path := false
+
+@onready var tree := $Tree as Tree
+
+func build_tree(todo_items : Array, ignore_paths : Array, patterns : Array, cased_patterns: Array[String], sort_alphabetical : bool, full_path : bool) -> void:
+ _full_path = full_path
+ tree.clear()
+ if sort_alphabetical:
+ todo_items.sort_custom(Callable(self, "sort_alphabetical"))
+ else:
+ todo_items.sort_custom(Callable(self, "sort_backwards"))
+ var root := tree.create_item()
+ root.set_text(0, "Scripts")
+ for todo_item in todo_items:
+ var ignore := false
+ for ignore_path in ignore_paths:
+ var script_path : String = todo_item.script_path
+ if script_path.begins_with(ignore_path) or script_path.begins_with("res://" + ignore_path) or script_path.begins_with("res:///" + ignore_path):
+ ignore = true
+ break
+ if ignore:
+ continue
+ var script := tree.create_item(root)
+ if full_path:
+ script.set_text(0, todo_item.script_path + " -------")
+ else:
+ script.set_text(0, todo_item.get_short_path() + " -------")
+ script.set_metadata(0, todo_item)
+ for todo in todo_item.todos:
+ var item := tree.create_item(script)
+ var content_header : String = todo.content
+ if "\n" in todo.content:
+ content_header = content_header.split("\n")[0] + "..."
+ item.set_text(0, "(%0) - %1".format([todo.line_number, content_header], "%_"))
+ item.set_tooltip_text(0, todo.content)
+ item.set_metadata(0, todo)
+ for i in range(0, len(cased_patterns)):
+ if cased_patterns[i] == todo.pattern:
+ item.set_custom_color(0, patterns[i][1])
+ emit_signal("tree_built")
+
+
+func sort_alphabetical(a, b) -> bool:
+ if _full_path:
+ if a.script_path < b.script_path:
+ return true
+ else:
+ return false
+ else:
+ if a.get_short_path() < b.get_short_path():
+ return true
+ else:
+ return false
+
+func sort_backwards(a, b) -> bool:
+ if _full_path:
+ if a.script_path > b.script_path:
+ return true
+ else:
+ return false
+ else:
+ if a.get_short_path() > b.get_short_path():
+ return true
+ else:
+ return false
diff --git a/addons/Todo_Manager/README.md b/addons/Todo_Manager/README.md
new file mode 100644
index 0000000..b723248
--- /dev/null
+++ b/addons/Todo_Manager/README.md
@@ -0,0 +1,60 @@
+
+### Localised READMEs
+ - [简体中文](READMECN.md) (Simplified Chinese)
+
+
+# TODO Manager
+
+![example_image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/example1.png)
+
+## Simple and flexible
+
+- Supports GDScript, C# and GDNative
+- Seamlessly integrated into the Godot dock
+- Lenient syntax. Write TODOs that suit your style
+- Quickly jump to lines and launch external editors
+
+## Customizable
+
+![settings_example](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/example2.png)
+
+- Add your own RegEx patterns
+- Set colours to your liking
+
+## Installation
+
+### Method 1 (Godot Asset Library)
+
+The most simple way to get started using TODO Manager is to use Godot's inbuilt Asset Library to install the plugin into your project.
+
+#### Step 1
+
+Find TODO Manager in the Godot Asset Library.
+![AssetLib image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct1.png)
+
+#### Step 2
+
+Install the package. You may want to untick the /doc folder at this point as it is not necessary for the functions of the plugin.
+![Filestrcture image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct3.png)
+
+#### Step 4
+
+Enable the plugin in the project settings.
+![Project image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct4.png)
+
+### Method 2 (GitHub)
+
+#### Step 1
+
+Click Download ZIP from the 'Code' dropdown.
+![GitHub image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct5.png)
+
+#### Step 2
+
+- Unzip the file and add it into your project folder. Make sure 'addons' is a subdirectory of res://
+- DO NOT change the name of the 'addons' or 'Todo_Manager' folders as this will break the saving and loading of your settings.
+
+#### Step 3
+
+Enable the plugin in the project settings.
+![Project image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct4.png)
diff --git a/addons/Todo_Manager/READMECN.md b/addons/Todo_Manager/READMECN.md
new file mode 100644
index 0000000..7a248c8
--- /dev/null
+++ b/addons/Todo_Manager/READMECN.md
@@ -0,0 +1,56 @@
+# TODO Manager
+
+ ![example_image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/example1.png)
+
+## 简单而灵活
+
+- 支持 GDScript,C# 和 GDNative。
+- 无缝集成到 Godot dock 栏。
+- 宽松的语法,用适合你自己的风格写TODOs。
+- 快速跳转到某一行并启用外部编辑器。
+
+## 可定制
+
+![settings_example](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/example2.png)
+
+- 添加你自己的正则表达式。
+- 设置你喜欢的颜色。
+
+## 安装
+
+### 方法一 (Godot Asset Library)
+
+最简单的使用 TODO Manager 的方法,使用 Godot 内置的资源商店(Asset Library)来安装这个插件到你的项目。
+
+#### 第一步
+
+在资源商店搜索 TODO Manager。
+![AssetLib image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct1.png)
+
+#### 第二步
+
+安装下载的插件,你可能需要取消勾选 /doc 文件夹,因为插件的功能不需要。
+![Filestrcture image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct3.png)
+
+#### 第三步
+
+在项目设置里启用插件。
+![Project image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct4.png)
+
+### 方法二 (GitHub)
+
+#### 第一步
+
+点击 Download ZIP。
+![GitHub image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct5.png)
+
+#### 第二步
+
+- 解压文件并且放到你的项目文件夹。确保 “addons” 是 res:// 的子文件夹。
+- DO NOT change the name of the 'addons' or 'Todo_Manager' folders as this will break the saving and loading of your settings.
+- 不要更改 “addons” 或 “Todo_Manager” 文件夹的名称,因为这会打破预设的保存和加载。
+
+#### 第三步
+
+在项目设置里启用这个插件。
+![Project image](https://github.com/OrigamiDev-Pete/TODO_Manager/blob/main/addons/Todo_Manager/doc/images/Instruct4.png)
diff --git a/addons/Todo_Manager/UI/ColourPicker.tscn b/addons/Todo_Manager/UI/ColourPicker.tscn
new file mode 100644
index 0000000..650899f
--- /dev/null
+++ b/addons/Todo_Manager/UI/ColourPicker.tscn
@@ -0,0 +1,21 @@
+[gd_scene load_steps=2 format=3 uid="uid://bie1xn8v1kd66"]
+
+[ext_resource type="Script" path="res://addons/Todo_Manager/ColourPicker.gd" id="1"]
+
+[node name="TODOColour" type="HBoxContainer"]
+offset_right = 105.0
+offset_bottom = 31.0
+script = ExtResource("1")
+metadata/_edit_use_custom_anchors = false
+
+[node name="Label" type="Label" parent="."]
+offset_top = 4.0
+offset_right = 1.0
+offset_bottom = 27.0
+
+[node name="TODOColourPickerButton" type="ColorPickerButton" parent="."]
+custom_minimum_size = Vector2(40, 0)
+offset_left = 65.0
+offset_right = 105.0
+offset_bottom = 31.0
+size_flags_horizontal = 10
diff --git a/addons/Todo_Manager/UI/Dock.tscn b/addons/Todo_Manager/UI/Dock.tscn
new file mode 100644
index 0000000..096662a
--- /dev/null
+++ b/addons/Todo_Manager/UI/Dock.tscn
@@ -0,0 +1,315 @@
+[gd_scene load_steps=6 format=3 uid="uid://b6k0dtftankcx"]
+
+[ext_resource type="Script" path="res://addons/Todo_Manager/Dock.gd" id="1"]
+[ext_resource type="Script" path="res://addons/Todo_Manager/Project.gd" id="2"]
+[ext_resource type="Script" path="res://addons/Todo_Manager/Current.gd" id="3"]
+
+[sub_resource type="ButtonGroup" id="ButtonGroup_kqxcu"]
+
+[sub_resource type="ButtonGroup" id="ButtonGroup_kltg3"]
+
+[node name="Dock" type="Control"]
+custom_minimum_size = Vector2(0, 200)
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+size_flags_vertical = 3
+script = ExtResource("1")
+
+[node name="VBoxContainer" type="VBoxContainer" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+offset_top = 4.0
+grow_horizontal = 2
+grow_vertical = 2
+metadata/_edit_layout_mode = 1
+
+[node name="Header" type="HBoxContainer" parent="VBoxContainer"]
+visible = false
+layout_mode = 2
+
+[node name="HeaderLeft" type="HBoxContainer" parent="VBoxContainer/Header"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="Title" type="Label" parent="VBoxContainer/Header/HeaderLeft"]
+layout_mode = 2
+text = "Todo Dock:"
+
+[node name="HeaderRight" type="HBoxContainer" parent="VBoxContainer/Header"]
+layout_mode = 2
+size_flags_horizontal = 3
+alignment = 2
+
+[node name="SettingsButton" type="Button" parent="VBoxContainer/Header/HeaderRight"]
+visible = false
+layout_mode = 2
+toggle_mode = true
+text = "Settings"
+
+[node name="TabContainer" type="TabContainer" parent="VBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 3
+
+[node name="Project" type="Panel" parent="VBoxContainer/TabContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+script = ExtResource("2")
+
+[node name="Tree" type="Tree" parent="VBoxContainer/TabContainer/Project"]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+hide_root = true
+
+[node name="Current" type="Panel" parent="VBoxContainer/TabContainer"]
+visible = false
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+script = ExtResource("3")
+
+[node name="Tree" type="Tree" parent="VBoxContainer/TabContainer/Current"]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+hide_folding = true
+hide_root = true
+
+[node name="Settings" type="Panel" parent="VBoxContainer/TabContainer"]
+visible = false
+layout_mode = 2
+
+[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer/TabContainer/Settings"]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+
+[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+
+[node name="Scripts" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Scripts"]
+layout_mode = 2
+text = "Scripts:"
+
+[node name="HSeparator" type="HSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Scripts"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 5
+
+[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="VSeparator" type="VSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2"]
+layout_mode = 2
+
+[node name="Scripts" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2"]
+layout_mode = 2
+
+[node name="ScriptName" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptName"]
+layout_mode = 2
+text = "Script Name:"
+
+[node name="FullPathCheckBox" type="CheckBox" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptName"]
+layout_mode = 2
+button_group = SubResource("ButtonGroup_kqxcu")
+text = "Full path"
+
+[node name="ShortNameCheckBox" type="CheckBox" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptName"]
+layout_mode = 2
+button_pressed = true
+button_group = SubResource("ButtonGroup_kqxcu")
+text = "Short name"
+
+[node name="ScriptSort" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptSort"]
+layout_mode = 2
+text = "Sort Order:"
+
+[node name="AlphSortCheckBox" type="CheckBox" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptSort"]
+layout_mode = 2
+button_pressed = true
+button_group = SubResource("ButtonGroup_kltg3")
+text = "Alphabetical"
+
+[node name="RAlphSortCheckBox" type="CheckBox" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptSort"]
+layout_mode = 2
+button_group = SubResource("ButtonGroup_kltg3")
+text = "Reverse Alphabetical"
+
+[node name="ScriptColour" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptColour"]
+layout_mode = 2
+text = "Script Colour:"
+
+[node name="ScriptColourPickerButton" type="ColorPickerButton" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptColour"]
+custom_minimum_size = Vector2(40, 0)
+layout_mode = 2
+color = Color(0.8, 0.807843, 0.827451, 1)
+
+[node name="IgnorePaths" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/IgnorePaths"]
+layout_mode = 2
+text = "Ignore Paths:"
+
+[node name="TextEdit" type="LineEdit" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/IgnorePaths"]
+custom_minimum_size = Vector2(100, 0)
+layout_mode = 2
+expand_to_text_length = true
+
+[node name="Label3" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/IgnorePaths"]
+layout_mode = 2
+text = "(Separated by commas)"
+
+[node name="TODOColours" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/TODOColours"]
+layout_mode = 2
+text = "TODO Colours:"
+
+[node name="HSeparator" type="HSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/TODOColours"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="HBoxContainer3" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="VSeparator" type="VSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer3"]
+layout_mode = 2
+
+[node name="Colours" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer3"]
+layout_mode = 2
+
+[node name="Patterns" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Patterns"]
+layout_mode = 2
+text = "Patterns:"
+
+[node name="HSeparator" type="HSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Patterns"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="HBoxContainer4" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="VSeparator" type="VSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4"]
+layout_mode = 2
+
+[node name="Patterns" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="AddPatternButton" type="Button" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns"]
+layout_mode = 2
+size_flags_horizontal = 0
+text = "Add"
+
+[node name="Config" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Config"]
+layout_mode = 2
+text = "Config:"
+
+[node name="HSeparator" type="HSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/Config"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="HBoxContainer5" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer"]
+layout_mode = 2
+
+[node name="VSeparator" type="VSeparator" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5"]
+layout_mode = 2
+
+[node name="Patterns" type="VBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5"]
+layout_mode = 2
+
+[node name="RefreshCheckButton" type="CheckButton" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns"]
+layout_mode = 2
+size_flags_horizontal = 0
+button_pressed = true
+text = "Auto Refresh"
+
+[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns"]
+layout_mode = 2
+
+[node name="BuiltInCheckButton" type="CheckButton" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/HBoxContainer"]
+layout_mode = 2
+text = "Scan Built-in Scripts"
+
+[node name="Label" type="Label" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/HBoxContainer"]
+layout_mode = 2
+
+[node name="DefaultButton" type="Button" parent="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns"]
+layout_mode = 2
+size_flags_horizontal = 0
+text = "Reset to default"
+
+[node name="Timer" type="Timer" parent="."]
+one_shot = true
+
+[node name="RescanButton" type="Button" parent="."]
+layout_mode = 1
+anchors_preset = 1
+anchor_left = 1.0
+anchor_right = 1.0
+offset_left = -102.0
+offset_top = 3.0
+offset_bottom = 34.0
+grow_horizontal = 0
+text = "Rescan Files"
+flat = true
+
+[connection signal="toggled" from="VBoxContainer/Header/HeaderRight/SettingsButton" to="." method="_on_SettingsButton_toggled"]
+[connection signal="tab_changed" from="VBoxContainer/TabContainer" to="." method="_on_TabContainer_tab_changed"]
+[connection signal="item_activated" from="VBoxContainer/TabContainer/Project/Tree" to="." method="_on_Tree_item_activated"]
+[connection signal="item_activated" from="VBoxContainer/TabContainer/Current/Tree" to="." method="_on_Tree_item_activated"]
+[connection signal="toggled" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptName/FullPathCheckBox" to="." method="_on_FullPathCheckBox_toggled"]
+[connection signal="toggled" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptSort/AlphSortCheckBox" to="." method="_on_AlphSortCheckBox_toggled"]
+[connection signal="color_changed" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/VBoxContainer/HBoxContainer2/Scripts/ScriptColour/ScriptColourPickerButton" to="." method="_on_ScriptColourPickerButton_color_changed"]
+[connection signal="pressed" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer4/Patterns/AddPatternButton" to="." method="_on_AddPatternButton_pressed"]
+[connection signal="toggled" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/RefreshCheckButton" to="." method="_on_RefreshCheckButton_toggled"]
+[connection signal="toggled" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/HBoxContainer/BuiltInCheckButton" to="." method="_on_BuiltInCheckButton_toggled"]
+[connection signal="pressed" from="VBoxContainer/TabContainer/Settings/ScrollContainer/MarginContainer/VBoxContainer/HBoxContainer5/Patterns/DefaultButton" to="." method="_on_DefaultButton_pressed"]
+[connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"]
+[connection signal="pressed" from="RescanButton" to="." method="_on_RescanButton_pressed"]
diff --git a/addons/Todo_Manager/UI/Pattern.tscn b/addons/Todo_Manager/UI/Pattern.tscn
new file mode 100644
index 0000000..fb45615
--- /dev/null
+++ b/addons/Todo_Manager/UI/Pattern.tscn
@@ -0,0 +1,26 @@
+[gd_scene load_steps=2 format=3 uid="uid://bx11sel2q5wli"]
+
+[ext_resource type="Script" path="res://addons/Todo_Manager/Pattern.gd" id="1"]
+
+[node name="Pattern" type="HBoxContainer"]
+script = ExtResource("1")
+
+[node name="LineEdit" type="LineEdit" parent="."]
+layout_mode = 2
+size_flags_horizontal = 0
+expand_to_text_length = true
+
+[node name="RemoveButton" type="Button" parent="."]
+layout_mode = 2
+text = "-"
+
+[node name="MarginContainer" type="MarginContainer" parent="."]
+custom_minimum_size = Vector2(20, 0)
+layout_mode = 2
+size_flags_horizontal = 0
+
+[node name="CaseSensativeCheckbox" type="CheckBox" parent="."]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 0
+text = "Case Sensitive"
diff --git a/addons/Todo_Manager/doc/example.gd b/addons/Todo_Manager/doc/example.gd
new file mode 100644
index 0000000..859bbba
--- /dev/null
+++ b/addons/Todo_Manager/doc/example.gd
@@ -0,0 +1,7 @@
+extends Node
+
+# TODO: this is a TODO
+# HACK: this is a HACK
+# FIXME: this is a FIXME
+# TODO this works too
+#Hack any format will do
diff --git a/addons/Todo_Manager/doc/images/Instruct1.png b/addons/Todo_Manager/doc/images/Instruct1.png
new file mode 100644
index 0000000..99a8db0
Binary files /dev/null and b/addons/Todo_Manager/doc/images/Instruct1.png differ
diff --git a/addons/Todo_Manager/doc/images/Instruct2.png b/addons/Todo_Manager/doc/images/Instruct2.png
new file mode 100644
index 0000000..83798f9
Binary files /dev/null and b/addons/Todo_Manager/doc/images/Instruct2.png differ
diff --git a/addons/Todo_Manager/doc/images/Instruct3.png b/addons/Todo_Manager/doc/images/Instruct3.png
new file mode 100644
index 0000000..283c604
Binary files /dev/null and b/addons/Todo_Manager/doc/images/Instruct3.png differ
diff --git a/addons/Todo_Manager/doc/images/Instruct4.png b/addons/Todo_Manager/doc/images/Instruct4.png
new file mode 100644
index 0000000..66ef1c9
Binary files /dev/null and b/addons/Todo_Manager/doc/images/Instruct4.png differ
diff --git a/addons/Todo_Manager/doc/images/Instruct5.png b/addons/Todo_Manager/doc/images/Instruct5.png
new file mode 100644
index 0000000..d418faf
Binary files /dev/null and b/addons/Todo_Manager/doc/images/Instruct5.png differ
diff --git a/addons/Todo_Manager/doc/images/TODO_Manager_Logo.png b/addons/Todo_Manager/doc/images/TODO_Manager_Logo.png
new file mode 100644
index 0000000..6d19fee
Binary files /dev/null and b/addons/Todo_Manager/doc/images/TODO_Manager_Logo.png differ
diff --git a/addons/Todo_Manager/doc/images/TodoExternal.gif b/addons/Todo_Manager/doc/images/TodoExternal.gif
new file mode 100644
index 0000000..25d0850
Binary files /dev/null and b/addons/Todo_Manager/doc/images/TodoExternal.gif differ
diff --git a/addons/Todo_Manager/doc/images/example1.png b/addons/Todo_Manager/doc/images/example1.png
new file mode 100644
index 0000000..786bd15
Binary files /dev/null and b/addons/Todo_Manager/doc/images/example1.png differ
diff --git a/addons/Todo_Manager/doc/images/example2.png b/addons/Todo_Manager/doc/images/example2.png
new file mode 100644
index 0000000..256d754
Binary files /dev/null and b/addons/Todo_Manager/doc/images/example2.png differ
diff --git a/addons/Todo_Manager/plugin.cfg b/addons/Todo_Manager/plugin.cfg
new file mode 100644
index 0000000..256be46
--- /dev/null
+++ b/addons/Todo_Manager/plugin.cfg
@@ -0,0 +1,7 @@
+[plugin]
+
+name="Todo Manager"
+description="Dock for housing TODO messages."
+author="Peter de Vroom"
+version="2.3.1"
+script="plugin.gd"
diff --git a/addons/Todo_Manager/plugin.gd b/addons/Todo_Manager/plugin.gd
new file mode 100644
index 0000000..511458d
--- /dev/null
+++ b/addons/Todo_Manager/plugin.gd
@@ -0,0 +1,286 @@
+@tool
+extends EditorPlugin
+
+const DockScene := preload("res://addons/Todo_Manager/UI/Dock.tscn")
+const Dock := preload("res://addons/Todo_Manager/Dock.gd")
+const Todo := preload("res://addons/Todo_Manager/todo_class.gd")
+const TodoItem := preload("res://addons/Todo_Manager/todoItem_class.gd")
+
+var _dockUI : Dock
+
+class TodoCacheValue:
+ var todos: Array
+ var last_modified_time: int
+
+ func _init(todos: Array, last_modified_time: int):
+ self.todos = todos
+ self.last_modified_time = last_modified_time
+
+var todo_cache : Dictionary # { key: script_path, value: TodoCacheValue }
+var remove_queue : Array
+var combined_pattern : String
+var cased_patterns : Array[String]
+
+var refresh_lock := false # makes sure _on_filesystem_changed only triggers once
+
+
+func _enter_tree() -> void:
+ _dockUI = DockScene.instantiate() as Control
+ add_control_to_bottom_panel(_dockUI, "TODO")
+ get_editor_interface().get_resource_filesystem().connect("filesystem_changed",
+ _on_filesystem_changed)
+ get_editor_interface().get_file_system_dock().connect("file_removed", queue_remove)
+ get_editor_interface().get_script_editor().connect("editor_script_changed",
+ _on_active_script_changed)
+ _dockUI.plugin = self
+
+ combined_pattern = combine_patterns(_dockUI.patterns)
+ find_tokens_from_path(find_scripts())
+ _dockUI.build_tree()
+
+
+func _exit_tree() -> void:
+ _dockUI.create_config_file()
+ remove_control_from_bottom_panel(_dockUI)
+ _dockUI.free()
+
+
+func queue_remove(file: String):
+ for i in _dockUI.todo_items.size() - 1:
+ if _dockUI.todo_items[i].script_path == file:
+ _dockUI.todo_items.remove_at(i)
+
+
+func find_tokens_from_path(scripts: Array[String]) -> void:
+ for script_path in scripts:
+ var file := FileAccess.open(script_path, FileAccess.READ)
+ var contents := file.get_as_text()
+ if script_path.ends_with(".tscn"):
+ handle_built_in_scripts(contents, script_path)
+ else:
+ find_tokens(contents, script_path)
+
+
+func handle_built_in_scripts(contents: String, resource_path: String):
+ var s := contents.split("sub_resource type=\"GDScript\"")
+ if s.size() <= 1:
+ return
+ for i in range(1, s.size()):
+ var script_components := s[i].split("script/source")
+ var script_name = script_components[0].substr(5, 14)
+ find_tokens(script_components[1], resource_path + "::" + script_name)
+
+
+func find_tokens(text: String, script_path: String) -> void:
+ var cached_todos = get_cached_todos(script_path)
+ if cached_todos.size() != 0:
+# var i := 0
+# for todo_item in _dockUI.todo_items:
+# if todo_item.script_path == script_path:
+# _dockUI.todo_items.remove_at(i)
+# i += 1
+ var todo_item := TodoItem.new(script_path, cached_todos)
+ _dockUI.todo_items.append(todo_item)
+ else:
+ var regex = RegEx.new()
+ # if regex.compile("#\\s*\\bTODO\\b.*|#\\s*\\bHACK\\b.*") == OK:
+ if regex.compile(combined_pattern) == OK:
+ var result : Array[RegExMatch] = regex.search_all(text)
+ if result.is_empty():
+ for i in _dockUI.todo_items.size():
+ if _dockUI.todo_items[i].script_path == script_path:
+ _dockUI.todo_items.remove_at(i)
+ return # No tokens found
+ var match_found : bool
+ var i := 0
+ for todo_item in _dockUI.todo_items:
+ if todo_item.script_path == script_path:
+ match_found = true
+ var updated_todo_item := update_todo_item(todo_item, result, text, script_path)
+ _dockUI.todo_items.remove_at(i)
+ _dockUI.todo_items.insert(i, updated_todo_item)
+ break
+ i += 1
+ if !match_found:
+ _dockUI.todo_items.append(create_todo_item(result, text, script_path))
+
+
+func create_todo_item(regex_results: Array[RegExMatch], text: String, script_path: String) -> TodoItem:
+ var todo_item = TodoItem.new(script_path, [])
+ todo_item.script_path = script_path
+ var last_line_number := 0
+ var lines := text.split("\n")
+ for r in regex_results:
+ var new_todo : Todo = create_todo(r.get_string(), script_path)
+ new_todo.line_number = get_line_number(r.get_string(), text, last_line_number)
+ # GD Multiline comment
+ var trailing_line := new_todo.line_number
+ var should_break = false
+ while trailing_line < lines.size() and lines[trailing_line].dedent().begins_with("#"):
+ for other_r in regex_results:
+ if lines[trailing_line] in other_r.get_string():
+ should_break = true
+ break
+ if should_break:
+ break
+
+ new_todo.content += "\n" + lines[trailing_line]
+ trailing_line += 1
+
+ last_line_number = new_todo.line_number
+ todo_item.todos.append(new_todo)
+ cache_todos(todo_item.todos, script_path)
+ return todo_item
+
+
+func update_todo_item(todo_item: TodoItem, regex_results: Array[RegExMatch], text: String, script_path: String) -> TodoItem:
+ todo_item.todos.clear()
+ var lines := text.split("\n")
+ for r in regex_results:
+ var new_todo : Todo = create_todo(r.get_string(), script_path)
+ new_todo.line_number = get_line_number(r.get_string(), text)
+ # GD Multiline comment
+ var trailing_line := new_todo.line_number
+ var should_break = false
+ while trailing_line < lines.size() and lines[trailing_line].dedent().begins_with("#"):
+ for other_r in regex_results:
+ if lines[trailing_line] in other_r.get_string():
+ should_break = true
+ break
+ if should_break:
+ break
+
+ new_todo.content += "\n" + lines[trailing_line]
+ trailing_line += 1
+ todo_item.todos.append(new_todo)
+ return todo_item
+
+
+func get_line_number(what: String, from: String, start := 0) -> int:
+ what = what.split('\n')[0] # Match first line of multiline C# comments
+ var temp_array := from.split('\n')
+ var lines := Array(temp_array)
+ var line_number# = lines.find(what) + 1
+ for i in range(start, lines.size()):
+ if what in lines[i]:
+ line_number = i + 1 # +1 to account of 0-based array vs 1-based line numbers
+ break
+ else:
+ line_number = 0 # This is an error
+ return line_number
+
+
+func _on_filesystem_changed() -> void:
+ if !refresh_lock:
+ if _dockUI.auto_refresh:
+ refresh_lock = true
+ _dockUI.get_node("Timer").start()
+ rescan_files(false)
+
+
+func find_scripts() -> Array[String]:
+ var scripts : Array[String]
+ var directory_queue : Array[String]
+ var dir := DirAccess.open("res://")
+ if dir.get_open_error() == OK:
+ get_dir_contents(dir, scripts, directory_queue)
+ else:
+ printerr("TODO_Manager: There was an error during find_scripts()")
+
+ while not directory_queue.is_empty():
+ if dir.change_dir(directory_queue[0]) == OK:
+ get_dir_contents(dir, scripts, directory_queue)
+ else:
+ printerr("TODO_Manager: There was an error at: " + directory_queue[0])
+ directory_queue.pop_front()
+
+ return scripts
+
+
+func cache_todos(todos: Array, script_path: String) -> void:
+ var last_modified_time = FileAccess.get_modified_time(script_path)
+ todo_cache[script_path] = TodoCacheValue.new(todos, last_modified_time)
+
+
+func get_cached_todos(script_path: String) -> Array:
+ if todo_cache.has(script_path) and !script_path.contains("tscn::"):
+ var cached_value: TodoCacheValue = todo_cache[script_path]
+ if cached_value.last_modified_time == FileAccess.get_modified_time(script_path):
+
+ return cached_value.todos
+ return []
+
+func get_dir_contents(dir: DirAccess, scripts: Array[String], directory_queue: Array[String]) -> void:
+ dir.include_navigational = false
+ dir.include_hidden = false
+ dir.list_dir_begin()
+ var file_name : String = dir.get_next()
+
+ while file_name != "":
+ if dir.current_is_dir():
+ if file_name == ".import" or file_name == ".mono": # Skip .import folder which should never have scripts
+ pass
+ else:
+ directory_queue.append(dir.get_current_dir().path_join(file_name))
+ else:
+ if file_name.ends_with(".gd") or file_name.ends_with(".cs") \
+ or file_name.ends_with(".c") or file_name.ends_with(".cpp") or file_name.ends_with(".h") \
+ or ((file_name.ends_with(".tscn") and _dockUI.builtin_enabled)):
+ scripts.append(dir.get_current_dir().path_join(file_name))
+ file_name = dir.get_next()
+
+
+func rescan_files(clear_cache: bool) -> void:
+ _dockUI.todo_items.clear()
+ if clear_cache:
+ todo_cache.clear()
+ combined_pattern = combine_patterns(_dockUI.patterns)
+ find_tokens_from_path(find_scripts())
+ _dockUI.build_tree()
+
+
+func combine_patterns(patterns: Array) -> String:
+ # Case Sensitivity
+ cased_patterns = []
+ for pattern in patterns:
+ if pattern[2] == _dockUI.CASE_INSENSITIVE:
+ cased_patterns.append(pattern[0].insert(0, "((?i)") + ")")
+ else:
+ cased_patterns.append("(" + pattern[0] + ")")
+
+ if patterns.size() == 1:
+ return cased_patterns[0]
+ else:
+ var pattern_string := "((\\/\\*)|(#|\\/\\/))\\s*("
+ for i in range(patterns.size()):
+ if i == 0:
+ pattern_string += cased_patterns[i]
+ else:
+ pattern_string += "|" + cased_patterns[i]
+ pattern_string += ")(?(2)[\\s\\S]*?\\*\\/|.*)"
+ return pattern_string
+
+
+func create_todo(todo_string: String, script_path: String) -> Todo:
+ var todo := Todo.new()
+ var regex = RegEx.new()
+ for pattern in cased_patterns:
+ if regex.compile(pattern) == OK:
+ var result : RegExMatch = regex.search(todo_string)
+ if result:
+ todo.pattern = pattern
+ todo.title = result.strings[0]
+ else:
+ continue
+ else:
+ printerr("Error compiling " + pattern)
+
+ todo.content = todo_string
+ todo.script_path = script_path
+ return todo
+
+
+func _on_active_script_changed(script) -> void:
+ if _dockUI:
+ if _dockUI.tabs.current_tab == 1:
+ _dockUI.build_tree()
diff --git a/addons/Todo_Manager/todo.cfg b/addons/Todo_Manager/todo.cfg
new file mode 100644
index 0000000..acef3bc
--- /dev/null
+++ b/addons/Todo_Manager/todo.cfg
@@ -0,0 +1,15 @@
+[scripts]
+
+full_path=false
+sort_alphabetical=true
+script_colour=Color(0.8, 0.807843, 0.827451, 1)
+ignore_paths=Array[String]([])
+
+[patterns]
+
+patterns=[["\\bTODO\\b", Color(0.588235, 0.945098, 0.678431, 1), 0], ["\\bHACK\\b", Color(0.835294, 0.737255, 0.439216, 1), 0], ["\\bFIXME\\b", Color(0.835294, 0.439216, 0.439216, 1), 0]]
+
+[config]
+
+auto_refresh=true
+builtin_enabled=false
diff --git a/addons/Todo_Manager/todoItem_class.gd b/addons/Todo_Manager/todoItem_class.gd
new file mode 100644
index 0000000..9bcb000
--- /dev/null
+++ b/addons/Todo_Manager/todoItem_class.gd
@@ -0,0 +1,18 @@
+@tool
+extends RefCounted
+
+var script_path : String
+var todos : Array
+
+func _init(script_path: String, todos: Array):
+ self.script_path = script_path
+ self.todos = todos
+
+func get_short_path() -> String:
+ var temp_array := script_path.rsplit('/', false, 1)
+ var short_path : String
+ if not temp_array.size() > 1:
+ short_path = "(!)" + temp_array[0]
+ else:
+ short_path = temp_array[1]
+ return short_path
diff --git a/addons/Todo_Manager/todo_class.gd b/addons/Todo_Manager/todo_class.gd
new file mode 100644
index 0000000..af6b26b
--- /dev/null
+++ b/addons/Todo_Manager/todo_class.gd
@@ -0,0 +1,9 @@
+@tool
+extends RefCounted
+
+
+var pattern : String
+var title : String
+var content : String
+var script_path : String
+var line_number : int
diff --git a/addons/godot_rl_agents/controller/ai_controller_2d.gd b/addons/godot_rl_agents/controller/ai_controller_2d.gd
new file mode 100644
index 0000000..0a32a64
--- /dev/null
+++ b/addons/godot_rl_agents/controller/ai_controller_2d.gd
@@ -0,0 +1,119 @@
+extends Node2D
+class_name AIController2D
+
+enum ControlModes { INHERIT_FROM_SYNC, HUMAN, TRAINING, ONNX_INFERENCE, RECORD_EXPERT_DEMOS }
+@export var control_mode: ControlModes = ControlModes.INHERIT_FROM_SYNC
+@export var onnx_model_path := ""
+@export var reset_after := 1000
+
+@export_group("Record expert demos mode options")
+## Path where the demos will be saved. The file can later be used for imitation learning.
+@export var expert_demo_save_path: String
+## The action that erases the last recorded episode from the currently recorded data.
+@export var remove_last_episode_key: InputEvent
+## Action will be repeated for n frames. Will introduce control lag if larger than 1.
+## Can be used to ensure that action_repeat on inference and training matches
+## the recorded demonstrations.
+@export var action_repeat: int = 1
+
+@export_group("Multi-policy mode options")
+## Allows you to set certain agents to use different policies.
+## Changing has no effect with default SB3 training. Works with Rllib example.
+## Tutorial: https://github.com/edbeeching/godot_rl_agents/blob/main/docs/TRAINING_MULTIPLE_POLICIES.md
+@export var policy_name: String = "shared_policy"
+
+var onnx_model: ONNXModel
+
+var heuristic := "human"
+var done := false
+var reward := 0.0
+var n_steps := 0
+var needs_reset := false
+
+var _player: Node2D
+
+
+func _ready():
+ add_to_group("AGENT")
+
+
+func init(player: Node2D):
+ _player = player
+
+
+#-- Methods that need implementing using the "extend script" option in Godot --#
+func get_obs() -> Dictionary:
+ assert(false, "the get_obs method is not implemented when extending from ai_controller")
+ return {"obs": []}
+
+
+func get_reward() -> float:
+ assert(false, "the get_reward method is not implemented when extending from ai_controller")
+ return 0.0
+
+
+func get_action_space() -> Dictionary:
+ assert(
+ false,
+ "the get get_action_space method is not implemented when extending from ai_controller"
+ )
+ return {
+ "example_actions_continous": {"size": 2, "action_type": "continuous"},
+ "example_actions_discrete": {"size": 2, "action_type": "discrete"},
+ }
+
+
+func set_action(action) -> void:
+ assert(false, "the set_action method is not implemented when extending from ai_controller")
+
+
+#-----------------------------------------------------------------------------#
+
+
+#-- Methods that sometimes need implementing using the "extend script" option in Godot --#
+# Only needed if you are recording expert demos with this AIController
+func get_action() -> Array:
+ assert(false, "the get_action method is not implemented in extended AIController but demo_recorder is used")
+ return []
+
+# -----------------------------------------------------------------------------#
+
+func _physics_process(delta):
+ n_steps += 1
+ if n_steps > reset_after:
+ needs_reset = true
+
+
+func get_obs_space():
+ # may need overriding if the obs space is complex
+ var obs = get_obs()
+ return {
+ "obs": {"size": [len(obs["obs"])], "space": "box"},
+ }
+
+
+func reset():
+ n_steps = 0
+ needs_reset = false
+
+
+func reset_if_done():
+ if done:
+ reset()
+
+
+func set_heuristic(h):
+ # sets the heuristic from "human" or "model" nothing to change here
+ heuristic = h
+
+
+func get_done():
+ return done
+
+
+func set_done_false():
+ done = false
+
+
+func zero_reward():
+ reward = 0.0
diff --git a/addons/godot_rl_agents/controller/ai_controller_3d.gd b/addons/godot_rl_agents/controller/ai_controller_3d.gd
new file mode 100644
index 0000000..c77d9e0
--- /dev/null
+++ b/addons/godot_rl_agents/controller/ai_controller_3d.gd
@@ -0,0 +1,120 @@
+extends Node3D
+class_name AIController3D
+
+enum ControlModes { INHERIT_FROM_SYNC, HUMAN, TRAINING, ONNX_INFERENCE, RECORD_EXPERT_DEMOS }
+@export var control_mode: ControlModes = ControlModes.INHERIT_FROM_SYNC
+@export var onnx_model_path := ""
+@export var reset_after := 1000
+
+@export_group("Record expert demos mode options")
+## Path where the demos will be saved. The file can later be used for imitation learning.
+@export var expert_demo_save_path: String
+## The action that erases the last recorded episode from the currently recorded data.
+@export var remove_last_episode_key: InputEvent
+## Action will be repeated for n frames. Will introduce control lag if larger than 1.
+## Can be used to ensure that action_repeat on inference and training matches
+## the recorded demonstrations.
+@export var action_repeat: int = 1
+
+@export_group("Multi-policy mode options")
+## Allows you to set certain agents to use different policies.
+## Changing has no effect with default SB3 training. Works with Rllib example.
+## Tutorial: https://github.com/edbeeching/godot_rl_agents/blob/main/docs/TRAINING_MULTIPLE_POLICIES.md
+@export var policy_name: String = "shared_policy"
+
+var onnx_model: ONNXModel
+
+var heuristic := "human"
+var done := false
+var reward := 0.0
+var n_steps := 0
+var needs_reset := false
+
+var _player: Node3D
+
+
+func _ready():
+ add_to_group("AGENT")
+
+
+func init(player: Node3D):
+ _player = player
+
+
+#-- Methods that need implementing using the "extend script" option in Godot --#
+func get_obs() -> Dictionary:
+ assert(false, "the get_obs method is not implemented when extending from ai_controller")
+ return {"obs": []}
+
+
+func get_reward() -> float:
+ assert(false, "the get_reward method is not implemented when extending from ai_controller")
+ return 0.0
+
+
+func get_action_space() -> Dictionary:
+ assert(
+ false,
+ "the get_action_space method is not implemented when extending from ai_controller"
+ )
+ return {
+ "example_actions_continous": {"size": 2, "action_type": "continuous"},
+ "example_actions_discrete": {"size": 2, "action_type": "discrete"},
+ }
+
+
+func set_action(action) -> void:
+ assert(false, "the set_action method is not implemented when extending from ai_controller")
+
+
+#-----------------------------------------------------------------------------#
+
+
+#-- Methods that sometimes need implementing using the "extend script" option in Godot --#
+# Only needed if you are recording expert demos with this AIController
+func get_action() -> Array:
+ assert(false, "the get_action method is not implemented in extended AIController but demo_recorder is used")
+ return []
+
+# -----------------------------------------------------------------------------#
+
+
+func _physics_process(delta):
+ n_steps += 1
+ if n_steps > reset_after:
+ needs_reset = true
+
+
+func get_obs_space():
+ # may need overriding if the obs space is complex
+ var obs = get_obs()
+ return {
+ "obs": {"size": [len(obs["obs"])], "space": "box"},
+ }
+
+
+func reset():
+ n_steps = 0
+ needs_reset = false
+
+
+func reset_if_done():
+ if done:
+ reset()
+
+
+func set_heuristic(h):
+ # sets the heuristic from "human" or "model" nothing to change here
+ heuristic = h
+
+
+func get_done():
+ return done
+
+
+func set_done_false():
+ done = false
+
+
+func zero_reward():
+ reward = 0.0
diff --git a/addons/godot_rl_agents/godot_rl_agents.gd b/addons/godot_rl_agents/godot_rl_agents.gd
new file mode 100644
index 0000000..e4fe136
--- /dev/null
+++ b/addons/godot_rl_agents/godot_rl_agents.gd
@@ -0,0 +1,16 @@
+@tool
+extends EditorPlugin
+
+
+func _enter_tree():
+ # Initialization of the plugin goes here.
+ # Add the new type with a name, a parent type, a script and an icon.
+ add_custom_type("Sync", "Node", preload("sync.gd"), preload("icon.png"))
+ #add_custom_type("RaycastSensor2D2", "Node", preload("raycast_sensor_2d.gd"), preload("icon.png"))
+
+
+func _exit_tree():
+ # Clean-up of the plugin goes here.
+ # Always remember to remove it from the engine when deactivated.
+ remove_custom_type("Sync")
+ #remove_custom_type("RaycastSensor2D2")
diff --git a/addons/godot_rl_agents/icon.png b/addons/godot_rl_agents/icon.png
new file mode 100644
index 0000000..fd8190e
Binary files /dev/null and b/addons/godot_rl_agents/icon.png differ
diff --git a/addons/godot_rl_agents/onnx/csharp/ONNXInference.cs b/addons/godot_rl_agents/onnx/csharp/ONNXInference.cs
new file mode 100644
index 0000000..6dcfa18
--- /dev/null
+++ b/addons/godot_rl_agents/onnx/csharp/ONNXInference.cs
@@ -0,0 +1,109 @@
+using Godot;
+using Microsoft.ML.OnnxRuntime;
+using Microsoft.ML.OnnxRuntime.Tensors;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace GodotONNX
+{
+ ///
+ public partial class ONNXInference : GodotObject
+ {
+
+ private InferenceSession session;
+ ///
+ /// Path to the ONNX model. Use Initialize to change it.
+ ///
+ private string modelPath;
+ private int batchSize;
+
+ private SessionOptions SessionOpt;
+
+ ///
+ /// init function
+ ///
+ ///
+ ///
+ /// Returns the output size of the model
+ public int Initialize(string Path, int BatchSize)
+ {
+ modelPath = Path;
+ batchSize = BatchSize;
+ SessionOpt = SessionConfigurator.MakeConfiguredSessionOptions();
+ session = LoadModel(modelPath);
+ return session.OutputMetadata["output"].Dimensions[1];
+ }
+
+
+ ///
+ public Godot.Collections.Dictionary> RunInference(Godot.Collections.Array obs, int state_ins)
+ {
+ //Current model: Any (Godot Rl Agents)
+ //Expects a tensor of shape [batch_size, input_size] type float named obs and a tensor of shape [batch_size] type float named state_ins
+
+ //Fill the input tensors
+ // create span from inputSize
+ var span = new float[obs.Count]; //There's probably a better way to do this
+ for (int i = 0; i < obs.Count; i++)
+ {
+ span[i] = obs[i];
+ }
+
+ IReadOnlyCollection inputs = new List
+ {
+ NamedOnnxValue.CreateFromTensor("obs", new DenseTensor(span, new int[] { batchSize, obs.Count })),
+ NamedOnnxValue.CreateFromTensor("state_ins", new DenseTensor(new float[] { state_ins }, new int[] { batchSize }))
+ };
+ IReadOnlyCollection outputNames = new List { "output", "state_outs" }; //ONNX is sensible to these names, as well as the input names
+
+ IDisposableReadOnlyCollection results;
+ //We do not use "using" here so we get a better exception explaination later
+ try
+ {
+ results = session.Run(inputs, outputNames);
+ }
+ catch (OnnxRuntimeException e)
+ {
+ //This error usually means that the model is not compatible with the input, beacause of the input shape (size)
+ GD.Print("Error at inference: ", e);
+ return null;
+ }
+ //Can't convert IEnumerable to Variant, so we have to convert it to an array or something
+ Godot.Collections.Dictionary> output = new Godot.Collections.Dictionary>();
+ DisposableNamedOnnxValue output1 = results.First();
+ DisposableNamedOnnxValue output2 = results.Last();
+ Godot.Collections.Array output1Array = new Godot.Collections.Array();
+ Godot.Collections.Array output2Array = new Godot.Collections.Array();
+
+ foreach (float f in output1.AsEnumerable())
+ {
+ output1Array.Add(f);
+ }
+
+ foreach (float f in output2.AsEnumerable())
+ {
+ output2Array.Add(f);
+ }
+
+ output.Add(output1.Name, output1Array);
+ output.Add(output2.Name, output2Array);
+
+ //Output is a dictionary of arrays, ex: { "output" : [0.1, 0.2, 0.3, 0.4, ...], "state_outs" : [0.5, ...]}
+ results.Dispose();
+ return output;
+ }
+ ///
+ public InferenceSession LoadModel(string Path)
+ {
+ using Godot.FileAccess file = FileAccess.Open(Path, Godot.FileAccess.ModeFlags.Read);
+ byte[] model = file.GetBuffer((int)file.GetLength());
+ //file.Close(); file.Dispose(); //Close the file, then dispose the reference.
+ return new InferenceSession(model, SessionOpt); //Load the model
+ }
+ public void FreeDisposables()
+ {
+ session.Dispose();
+ SessionOpt.Dispose();
+ }
+ }
+}
diff --git a/addons/godot_rl_agents/onnx/csharp/SessionConfigurator.cs b/addons/godot_rl_agents/onnx/csharp/SessionConfigurator.cs
new file mode 100644
index 0000000..ad7a41c
--- /dev/null
+++ b/addons/godot_rl_agents/onnx/csharp/SessionConfigurator.cs
@@ -0,0 +1,131 @@
+using Godot;
+using Microsoft.ML.OnnxRuntime;
+
+namespace GodotONNX
+{
+ ///
+
+ public static class SessionConfigurator
+ {
+ public enum ComputeName
+ {
+ CUDA,
+ ROCm,
+ DirectML,
+ CoreML,
+ CPU
+ }
+
+ ///
+ public static SessionOptions MakeConfiguredSessionOptions()
+ {
+ SessionOptions sessionOptions = new();
+ SetOptions(sessionOptions);
+ return sessionOptions;
+ }
+
+ private static void SetOptions(SessionOptions sessionOptions)
+ {
+ sessionOptions.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING;
+ ApplySystemSpecificOptions(sessionOptions);
+ }
+
+ ///
+ static public void ApplySystemSpecificOptions(SessionOptions sessionOptions)
+ {
+ //Most code for this function is verbose only, the only reason it exists is to track
+ //implementation progress of the different compute APIs.
+
+ //December 2022: CUDA is not working.
+
+ string OSName = OS.GetName(); //Get OS Name
+
+ //ComputeName ComputeAPI = ComputeCheck(); //Get Compute API
+ // //TODO: Get CPU architecture
+
+ //Linux can use OpenVINO (C#) on x64 and ROCm on x86 (GDNative/C++)
+ //Windows can use OpenVINO (C#) on x64
+ //TODO: try TensorRT instead of CUDA
+ //TODO: Use OpenVINO for Intel Graphics
+
+ // Temporarily using CPU on all platforms to avoid errors detected with DML
+ ComputeName ComputeAPI = ComputeName.CPU;
+
+ //match OS and Compute API
+ GD.Print($"OS: {OSName} Compute API: {ComputeAPI}");
+
+ // CPU is set by default without appending necessary
+ // sessionOptions.AppendExecutionProvider_CPU(0);
+
+ /*
+ switch (OSName)
+ {
+ case "Windows": //Can use CUDA, DirectML
+ if (ComputeAPI is ComputeName.CUDA)
+ {
+ //CUDA
+ //sessionOptions.AppendExecutionProvider_CUDA(0);
+ //sessionOptions.AppendExecutionProvider_DML(0);
+ }
+ else if (ComputeAPI is ComputeName.DirectML)
+ {
+ //DirectML
+ //sessionOptions.AppendExecutionProvider_DML(0);
+ }
+ break;
+ case "X11": //Can use CUDA, ROCm
+ if (ComputeAPI is ComputeName.CUDA)
+ {
+ //CUDA
+ //sessionOptions.AppendExecutionProvider_CUDA(0);
+ }
+ if (ComputeAPI is ComputeName.ROCm)
+ {
+ //ROCm, only works on x86
+ //Research indicates that this has to be compiled as a GDNative plugin
+ //GD.Print("ROCm not supported yet, using CPU.");
+ //sessionOptions.AppendExecutionProvider_CPU(0);
+ }
+ break;
+ case "macOS": //Can use CoreML
+ if (ComputeAPI is ComputeName.CoreML)
+ { //CoreML
+ //TODO: Needs testing
+ //sessionOptions.AppendExecutionProvider_CoreML(0);
+ //CoreML on ARM64, out of the box, on x64 needs .tar file from GitHub
+ }
+ break;
+ default:
+ GD.Print("OS not Supported.");
+ break;
+ }
+ */
+ }
+
+
+ ///
+ public static ComputeName ComputeCheck()
+ {
+ string adapterName = Godot.RenderingServer.GetVideoAdapterName();
+ //string adapterVendor = Godot.RenderingServer.GetVideoAdapterVendor();
+ adapterName = adapterName.ToUpper(new System.Globalization.CultureInfo(""));
+ //TODO: GPU vendors for MacOS, what do they even use these days?
+
+ if (adapterName.Contains("INTEL"))
+ {
+ return ComputeName.DirectML;
+ }
+ if (adapterName.Contains("AMD") || adapterName.Contains("RADEON"))
+ {
+ return ComputeName.DirectML;
+ }
+ if (adapterName.Contains("NVIDIA"))
+ {
+ return ComputeName.CUDA;
+ }
+
+ GD.Print("Graphics Card not recognized."); //Should use CPU
+ return ComputeName.CPU;
+ }
+ }
+}
diff --git a/addons/godot_rl_agents/onnx/csharp/docs/ONNXInference.xml b/addons/godot_rl_agents/onnx/csharp/docs/ONNXInference.xml
new file mode 100644
index 0000000..91b07d6
--- /dev/null
+++ b/addons/godot_rl_agents/onnx/csharp/docs/ONNXInference.xml
@@ -0,0 +1,31 @@
+
+
+
+
+ The main ONNXInference Class that handles the inference process.
+
+
+
+
+ Starts the inference process.
+
+ Path to the ONNX model, expects a path inside resources.
+ How many observations will the model recieve.
+
+
+
+ Runs the given input through the model and returns the output.
+
+ Dictionary containing all observations.
+ How many different agents are creating these observations.
+ A Dictionary of arrays, containing instructions based on the observations.
+
+
+
+ Loads the given model into the inference process, using the best Execution provider available.
+
+ Path to the ONNX model, expects a path inside resources.
+ InferenceSession ready to run.
+
+
+
\ No newline at end of file
diff --git a/addons/godot_rl_agents/onnx/csharp/docs/SessionConfigurator.xml b/addons/godot_rl_agents/onnx/csharp/docs/SessionConfigurator.xml
new file mode 100644
index 0000000..f160c02
--- /dev/null
+++ b/addons/godot_rl_agents/onnx/csharp/docs/SessionConfigurator.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ The main SessionConfigurator Class that handles the execution options and providers for the inference process.
+
+
+
+
+ Creates a SessionOptions with all available execution providers.
+
+ SessionOptions with all available execution providers.
+
+
+
+ Appends any execution provider available in the current system.
+
+
+ This function is mainly verbose for tracking implementation progress of different compute APIs.
+
+
+
+
+ Checks for available GPUs.
+
+ An integer identifier for each compute platform.
+
+
+
\ No newline at end of file
diff --git a/addons/godot_rl_agents/onnx/wrapper/ONNX_wrapper.gd b/addons/godot_rl_agents/onnx/wrapper/ONNX_wrapper.gd
new file mode 100644
index 0000000..e27f2c3
--- /dev/null
+++ b/addons/godot_rl_agents/onnx/wrapper/ONNX_wrapper.gd
@@ -0,0 +1,51 @@
+extends Resource
+class_name ONNXModel
+var inferencer_script = load("res://addons/godot_rl_agents/onnx/csharp/ONNXInference.cs")
+
+var inferencer = null
+
+## How many action values the model outputs
+var action_output_size: int
+
+## Used to differentiate models
+## that only output continuous action mean (e.g. sb3, cleanrl export)
+## versus models that output mean and logstd (e.g. rllib export)
+var action_means_only: bool
+
+## Whether action_means_value has been set already for this model
+var action_means_only_set: bool
+
+# Must provide the path to the model and the batch size
+func _init(model_path, batch_size):
+ inferencer = inferencer_script.new()
+ action_output_size = inferencer.Initialize(model_path, batch_size)
+
+# This function is the one that will be called from the game,
+# requires the observation as an array and the state_ins as an int
+# returns an Array containing the action the model takes.
+func run_inference(obs: Array, state_ins: int) -> Dictionary:
+ if inferencer == null:
+ printerr("Inferencer not initialized")
+ return {}
+ return inferencer.RunInference(obs, state_ins)
+
+
+func _notification(what):
+ if what == NOTIFICATION_PREDELETE:
+ inferencer.FreeDisposables()
+ inferencer.free()
+
+# Check whether agent uses a continuous actions model with only action means or not
+func set_action_means_only(agent_action_space):
+ action_means_only_set = true
+ var continuous_only: bool = true
+ var continuous_actions: int
+ for action in agent_action_space:
+ if not agent_action_space[action]["action_type"] == "continuous":
+ continuous_only = false
+ break
+ else:
+ continuous_actions += agent_action_space[action]["size"]
+ if continuous_only:
+ if continuous_actions == action_output_size:
+ action_means_only = true
diff --git a/addons/godot_rl_agents/plugin.cfg b/addons/godot_rl_agents/plugin.cfg
new file mode 100644
index 0000000..b1bc988
--- /dev/null
+++ b/addons/godot_rl_agents/plugin.cfg
@@ -0,0 +1,7 @@
+[plugin]
+
+name="GodotRLAgents"
+description="Custom nodes for the godot rl agents toolkit "
+author="Edward Beeching"
+version="0.1"
+script="godot_rl_agents.gd"
diff --git a/addons/godot_rl_agents/sensors/sensors_2d/ExampleRaycastSensor2D.tscn b/addons/godot_rl_agents/sensors/sensors_2d/ExampleRaycastSensor2D.tscn
new file mode 100644
index 0000000..5edb6c7
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_2d/ExampleRaycastSensor2D.tscn
@@ -0,0 +1,48 @@
+[gd_scene load_steps=5 format=3 uid="uid://ddeq7mn1ealyc"]
+
+[ext_resource type="Script" path="res://addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.gd" id="1"]
+
+[sub_resource type="GDScript" id="2"]
+script/source = "extends Node2D
+
+
+
+func _physics_process(delta: float) -> void:
+ print(\"step start\")
+
+"
+
+[sub_resource type="GDScript" id="1"]
+script/source = "extends RayCast2D
+
+var steps = 1
+
+func _physics_process(delta: float) -> void:
+ print(\"processing raycast\")
+ steps += 1
+ if steps % 2:
+ force_raycast_update()
+
+ print(is_colliding())
+"
+
+[sub_resource type="CircleShape2D" id="3"]
+
+[node name="ExampleRaycastSensor2D" type="Node2D"]
+script = SubResource("2")
+
+[node name="ExampleAgent" type="Node2D" parent="."]
+position = Vector2(573, 314)
+rotation = 0.286234
+
+[node name="RaycastSensor2D" type="Node2D" parent="ExampleAgent"]
+script = ExtResource("1")
+
+[node name="TestRayCast2D" type="RayCast2D" parent="."]
+script = SubResource("1")
+
+[node name="StaticBody2D" type="StaticBody2D" parent="."]
+position = Vector2(1, 52)
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="StaticBody2D"]
+shape = SubResource("3")
diff --git a/addons/godot_rl_agents/sensors/sensors_2d/GridSensor2D.gd b/addons/godot_rl_agents/sensors/sensors_2d/GridSensor2D.gd
new file mode 100644
index 0000000..da170ba
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_2d/GridSensor2D.gd
@@ -0,0 +1,235 @@
+@tool
+extends ISensor2D
+class_name GridSensor2D
+
+@export var debug_view := false:
+ get:
+ return debug_view
+ set(value):
+ debug_view = value
+ _update()
+
+@export_flags_2d_physics var detection_mask := 0:
+ get:
+ return detection_mask
+ set(value):
+ detection_mask = value
+ _update()
+
+@export var collide_with_areas := false:
+ get:
+ return collide_with_areas
+ set(value):
+ collide_with_areas = value
+ _update()
+
+@export var collide_with_bodies := true:
+ get:
+ return collide_with_bodies
+ set(value):
+ collide_with_bodies = value
+ _update()
+
+@export_range(1, 200, 0.1) var cell_width := 20.0:
+ get:
+ return cell_width
+ set(value):
+ cell_width = value
+ _update()
+
+@export_range(1, 200, 0.1) var cell_height := 20.0:
+ get:
+ return cell_height
+ set(value):
+ cell_height = value
+ _update()
+
+@export_range(1, 21, 2, "or_greater") var grid_size_x := 3:
+ get:
+ return grid_size_x
+ set(value):
+ grid_size_x = value
+ _update()
+
+@export_range(1, 21, 2, "or_greater") var grid_size_y := 3:
+ get:
+ return grid_size_y
+ set(value):
+ grid_size_y = value
+ _update()
+
+var _obs_buffer: PackedFloat64Array
+var _rectangle_shape: RectangleShape2D
+var _collision_mapping: Dictionary
+var _n_layers_per_cell: int
+
+var _highlighted_cell_color: Color
+var _standard_cell_color: Color
+
+
+func get_observation():
+ return _obs_buffer
+
+
+func _update():
+ if Engine.is_editor_hint():
+ if is_node_ready():
+ _spawn_nodes()
+
+
+func _ready() -> void:
+ _set_colors()
+
+ if Engine.is_editor_hint():
+ if get_child_count() == 0:
+ _spawn_nodes()
+ else:
+ _spawn_nodes()
+
+
+func _set_colors() -> void:
+ _standard_cell_color = Color(100.0 / 255.0, 100.0 / 255.0, 100.0 / 255.0, 100.0 / 255.0)
+ _highlighted_cell_color = Color(255.0 / 255.0, 100.0 / 255.0, 100.0 / 255.0, 100.0 / 255.0)
+
+
+func _get_collision_mapping() -> Dictionary:
+ # defines which layer is mapped to which cell obs index
+ var total_bits = 0
+ var collision_mapping = {}
+ for i in 32:
+ var bit_mask = 2 ** i
+ if (detection_mask & bit_mask) > 0:
+ collision_mapping[i] = total_bits
+ total_bits += 1
+
+ return collision_mapping
+
+
+func _spawn_nodes():
+ for cell in get_children():
+ cell.name = "_%s" % cell.name # Otherwise naming below will fail
+ cell.queue_free()
+
+ _collision_mapping = _get_collision_mapping()
+ #prints("collision_mapping", _collision_mapping, len(_collision_mapping))
+ # allocate memory for the observations
+ _n_layers_per_cell = len(_collision_mapping)
+ _obs_buffer = PackedFloat64Array()
+ _obs_buffer.resize(grid_size_x * grid_size_y * _n_layers_per_cell)
+ _obs_buffer.fill(0)
+ #prints(len(_obs_buffer), _obs_buffer )
+
+ _rectangle_shape = RectangleShape2D.new()
+ _rectangle_shape.set_size(Vector2(cell_width, cell_height))
+
+ var shift := Vector2(
+ -(grid_size_x / 2) * cell_width,
+ -(grid_size_y / 2) * cell_height,
+ )
+
+ for i in grid_size_x:
+ for j in grid_size_y:
+ var cell_position = Vector2(i * cell_width, j * cell_height) + shift
+ _create_cell(i, j, cell_position)
+
+
+func _create_cell(i: int, j: int, position: Vector2):
+ var cell := Area2D.new()
+ cell.position = position
+ cell.name = "GridCell %s %s" % [i, j]
+ cell.modulate = _standard_cell_color
+
+ if collide_with_areas:
+ cell.area_entered.connect(_on_cell_area_entered.bind(i, j))
+ cell.area_exited.connect(_on_cell_area_exited.bind(i, j))
+
+ if collide_with_bodies:
+ cell.body_entered.connect(_on_cell_body_entered.bind(i, j))
+ cell.body_exited.connect(_on_cell_body_exited.bind(i, j))
+
+ cell.collision_layer = 0
+ cell.collision_mask = detection_mask
+ cell.monitorable = true
+ add_child(cell)
+ cell.set_owner(get_tree().edited_scene_root)
+
+ var col_shape := CollisionShape2D.new()
+ col_shape.shape = _rectangle_shape
+ col_shape.name = "CollisionShape2D"
+ cell.add_child(col_shape)
+ col_shape.set_owner(get_tree().edited_scene_root)
+
+ if debug_view:
+ var quad = MeshInstance2D.new()
+ quad.name = "MeshInstance2D"
+ var quad_mesh = QuadMesh.new()
+
+ quad_mesh.set_size(Vector2(cell_width, cell_height))
+
+ quad.mesh = quad_mesh
+ cell.add_child(quad)
+ quad.set_owner(get_tree().edited_scene_root)
+
+
+func _update_obs(cell_i: int, cell_j: int, collision_layer: int, entered: bool):
+ for key in _collision_mapping:
+ var bit_mask = 2 ** key
+ if (collision_layer & bit_mask) > 0:
+ var collison_map_index = _collision_mapping[key]
+
+ var obs_index = (
+ (cell_i * grid_size_x * _n_layers_per_cell)
+ + (cell_j * _n_layers_per_cell)
+ + collison_map_index
+ )
+ #prints(obs_index, cell_i, cell_j)
+ if entered:
+ _obs_buffer[obs_index] += 1
+ else:
+ _obs_buffer[obs_index] -= 1
+
+
+func _toggle_cell(cell_i: int, cell_j: int):
+ var cell = get_node_or_null("GridCell %s %s" % [cell_i, cell_j])
+
+ if cell == null:
+ print("cell not found, returning")
+
+ var n_hits = 0
+ var start_index = (cell_i * grid_size_x * _n_layers_per_cell) + (cell_j * _n_layers_per_cell)
+ for i in _n_layers_per_cell:
+ n_hits += _obs_buffer[start_index + i]
+
+ if n_hits > 0:
+ cell.modulate = _highlighted_cell_color
+ else:
+ cell.modulate = _standard_cell_color
+
+
+func _on_cell_area_entered(area: Area2D, cell_i: int, cell_j: int):
+ #prints("_on_cell_area_entered", cell_i, cell_j)
+ _update_obs(cell_i, cell_j, area.collision_layer, true)
+ if debug_view:
+ _toggle_cell(cell_i, cell_j)
+ #print(_obs_buffer)
+
+
+func _on_cell_area_exited(area: Area2D, cell_i: int, cell_j: int):
+ #prints("_on_cell_area_exited", cell_i, cell_j)
+ _update_obs(cell_i, cell_j, area.collision_layer, false)
+ if debug_view:
+ _toggle_cell(cell_i, cell_j)
+
+
+func _on_cell_body_entered(body: Node2D, cell_i: int, cell_j: int):
+ #prints("_on_cell_body_entered", cell_i, cell_j)
+ _update_obs(cell_i, cell_j, body.collision_layer, true)
+ if debug_view:
+ _toggle_cell(cell_i, cell_j)
+
+
+func _on_cell_body_exited(body: Node2D, cell_i: int, cell_j: int):
+ #prints("_on_cell_body_exited", cell_i, cell_j)
+ _update_obs(cell_i, cell_j, body.collision_layer, false)
+ if debug_view:
+ _toggle_cell(cell_i, cell_j)
diff --git a/addons/godot_rl_agents/sensors/sensors_2d/ISensor2D.gd b/addons/godot_rl_agents/sensors/sensors_2d/ISensor2D.gd
new file mode 100644
index 0000000..67669a1
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_2d/ISensor2D.gd
@@ -0,0 +1,25 @@
+extends Node2D
+class_name ISensor2D
+
+var _obs: Array = []
+var _active := false
+
+
+func get_observation():
+ pass
+
+
+func activate():
+ _active = true
+
+
+func deactivate():
+ _active = false
+
+
+func _update_observation():
+ pass
+
+
+func reset():
+ pass
diff --git a/addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.gd b/addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.gd
new file mode 100644
index 0000000..9bb54ed
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.gd
@@ -0,0 +1,118 @@
+@tool
+extends ISensor2D
+class_name RaycastSensor2D
+
+@export_flags_2d_physics var collision_mask := 1:
+ get:
+ return collision_mask
+ set(value):
+ collision_mask = value
+ _update()
+
+@export var collide_with_areas := false:
+ get:
+ return collide_with_areas
+ set(value):
+ collide_with_areas = value
+ _update()
+
+@export var collide_with_bodies := true:
+ get:
+ return collide_with_bodies
+ set(value):
+ collide_with_bodies = value
+ _update()
+
+@export var n_rays := 16.0:
+ get:
+ return n_rays
+ set(value):
+ n_rays = value
+ _update()
+
+@export_range(5, 3000, 5.0) var ray_length := 200:
+ get:
+ return ray_length
+ set(value):
+ ray_length = value
+ _update()
+@export_range(5, 360, 5.0) var cone_width := 360.0:
+ get:
+ return cone_width
+ set(value):
+ cone_width = value
+ _update()
+
+@export var debug_draw := true:
+ get:
+ return debug_draw
+ set(value):
+ debug_draw = value
+ _update()
+
+var _angles = []
+var rays := []
+
+
+func _update():
+ if Engine.is_editor_hint():
+ if debug_draw:
+ _spawn_nodes()
+ else:
+ for ray in get_children():
+ if ray is RayCast2D:
+ remove_child(ray)
+
+
+func _ready() -> void:
+ _spawn_nodes()
+
+
+func _spawn_nodes():
+ for ray in rays:
+ ray.queue_free()
+ rays = []
+
+ _angles = []
+ var step = cone_width / (n_rays)
+ var start = step / 2 - cone_width / 2
+
+ for i in n_rays:
+ var angle = start + i * step
+ var ray = RayCast2D.new()
+ ray.set_target_position(
+ Vector2(ray_length * cos(deg_to_rad(angle)), ray_length * sin(deg_to_rad(angle)))
+ )
+ ray.set_name("node_" + str(i))
+ ray.enabled = false
+ ray.collide_with_areas = collide_with_areas
+ ray.collide_with_bodies = collide_with_bodies
+ ray.collision_mask = collision_mask
+ add_child(ray)
+ rays.append(ray)
+
+ _angles.append(start + i * step)
+
+
+func get_observation() -> Array:
+ return self.calculate_raycasts()
+
+
+func calculate_raycasts() -> Array:
+ var result = []
+ for ray in rays:
+ ray.enabled = true
+ ray.force_raycast_update()
+ var distance = _get_raycast_distance(ray)
+ result.append(distance)
+ ray.enabled = false
+ return result
+
+
+func _get_raycast_distance(ray: RayCast2D) -> float:
+ if !ray.is_colliding():
+ return 0.0
+
+ var distance = (global_position - ray.get_collision_point()).length()
+ distance = clamp(distance, 0.0, ray_length)
+ return (ray_length - distance) / ray_length
diff --git a/addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.tscn b/addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.tscn
new file mode 100644
index 0000000..5ca402c
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.tscn
@@ -0,0 +1,7 @@
+[gd_scene load_steps=2 format=3 uid="uid://drvfihk5esgmv"]
+
+[ext_resource type="Script" path="res://addons/godot_rl_agents/sensors/sensors_2d/RaycastSensor2D.gd" id="1"]
+
+[node name="RaycastSensor2D" type="Node2D"]
+script = ExtResource("1")
+n_rays = 17.0
diff --git a/addons/godot_rl_agents/sensors/sensors_3d/ExampleRaycastSensor3D.tscn b/addons/godot_rl_agents/sensors/sensors_3d/ExampleRaycastSensor3D.tscn
new file mode 100644
index 0000000..a8057c7
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_3d/ExampleRaycastSensor3D.tscn
@@ -0,0 +1,6 @@
+[gd_scene format=3 uid="uid://biu787qh4woik"]
+
+[node name="ExampleRaycastSensor3D" type="Node3D"]
+
+[node name="Camera3D" type="Camera3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.804183, 0, 2.70146)
diff --git a/addons/godot_rl_agents/sensors/sensors_3d/GridSensor3D.gd b/addons/godot_rl_agents/sensors/sensors_3d/GridSensor3D.gd
new file mode 100644
index 0000000..03593cc
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_3d/GridSensor3D.gd
@@ -0,0 +1,258 @@
+@tool
+extends ISensor3D
+class_name GridSensor3D
+
+@export var debug_view := false:
+ get:
+ return debug_view
+ set(value):
+ debug_view = value
+ _update()
+
+@export_flags_3d_physics var detection_mask := 0:
+ get:
+ return detection_mask
+ set(value):
+ detection_mask = value
+ _update()
+
+@export var collide_with_areas := false:
+ get:
+ return collide_with_areas
+ set(value):
+ collide_with_areas = value
+ _update()
+
+@export var collide_with_bodies := false:
+ # NOTE! The sensor will not detect StaticBody3D, add an area to static bodies to detect them
+ get:
+ return collide_with_bodies
+ set(value):
+ collide_with_bodies = value
+ _update()
+
+@export_range(0.1, 2, 0.1) var cell_width := 1.0:
+ get:
+ return cell_width
+ set(value):
+ cell_width = value
+ _update()
+
+@export_range(0.1, 2, 0.1) var cell_height := 1.0:
+ get:
+ return cell_height
+ set(value):
+ cell_height = value
+ _update()
+
+@export_range(1, 21, 2, "or_greater") var grid_size_x := 3:
+ get:
+ return grid_size_x
+ set(value):
+ grid_size_x = value
+ _update()
+
+@export_range(1, 21, 2, "or_greater") var grid_size_z := 3:
+ get:
+ return grid_size_z
+ set(value):
+ grid_size_z = value
+ _update()
+
+var _obs_buffer: PackedFloat64Array
+var _box_shape: BoxShape3D
+var _collision_mapping: Dictionary
+var _n_layers_per_cell: int
+
+var _highlighted_box_material: StandardMaterial3D
+var _standard_box_material: StandardMaterial3D
+
+
+func get_observation():
+ return _obs_buffer
+
+
+func reset():
+ _obs_buffer.fill(0)
+
+
+func _update():
+ if Engine.is_editor_hint():
+ if is_node_ready():
+ _spawn_nodes()
+
+
+func _ready() -> void:
+ _make_materials()
+
+ if Engine.is_editor_hint():
+ if get_child_count() == 0:
+ _spawn_nodes()
+ else:
+ _spawn_nodes()
+
+
+func _make_materials() -> void:
+ if _highlighted_box_material != null and _standard_box_material != null:
+ return
+
+ _standard_box_material = StandardMaterial3D.new()
+ _standard_box_material.set_transparency(1) # ALPHA
+ _standard_box_material.albedo_color = Color(
+ 100.0 / 255.0, 100.0 / 255.0, 100.0 / 255.0, 100.0 / 255.0
+ )
+
+ _highlighted_box_material = StandardMaterial3D.new()
+ _highlighted_box_material.set_transparency(1) # ALPHA
+ _highlighted_box_material.albedo_color = Color(
+ 255.0 / 255.0, 100.0 / 255.0, 100.0 / 255.0, 100.0 / 255.0
+ )
+
+
+func _get_collision_mapping() -> Dictionary:
+ # defines which layer is mapped to which cell obs index
+ var total_bits = 0
+ var collision_mapping = {}
+ for i in 32:
+ var bit_mask = 2 ** i
+ if (detection_mask & bit_mask) > 0:
+ collision_mapping[i] = total_bits
+ total_bits += 1
+
+ return collision_mapping
+
+
+func _spawn_nodes():
+ for cell in get_children():
+ cell.name = "_%s" % cell.name # Otherwise naming below will fail
+ cell.queue_free()
+
+ _collision_mapping = _get_collision_mapping()
+ #prints("collision_mapping", _collision_mapping, len(_collision_mapping))
+ # allocate memory for the observations
+ _n_layers_per_cell = len(_collision_mapping)
+ _obs_buffer = PackedFloat64Array()
+ _obs_buffer.resize(grid_size_x * grid_size_z * _n_layers_per_cell)
+ _obs_buffer.fill(0)
+ #prints(len(_obs_buffer), _obs_buffer )
+
+ _box_shape = BoxShape3D.new()
+ _box_shape.set_size(Vector3(cell_width, cell_height, cell_width))
+
+ var shift := Vector3(
+ -(grid_size_x / 2) * cell_width,
+ 0,
+ -(grid_size_z / 2) * cell_width,
+ )
+
+ for i in grid_size_x:
+ for j in grid_size_z:
+ var cell_position = Vector3(i * cell_width, 0.0, j * cell_width) + shift
+ _create_cell(i, j, cell_position)
+
+
+func _create_cell(i: int, j: int, position: Vector3):
+ var cell := Area3D.new()
+ cell.position = position
+ cell.name = "GridCell %s %s" % [i, j]
+
+ if collide_with_areas:
+ cell.area_entered.connect(_on_cell_area_entered.bind(i, j))
+ cell.area_exited.connect(_on_cell_area_exited.bind(i, j))
+
+ if collide_with_bodies:
+ cell.body_entered.connect(_on_cell_body_entered.bind(i, j))
+ cell.body_exited.connect(_on_cell_body_exited.bind(i, j))
+
+# cell.body_shape_entered.connect(_on_cell_body_shape_entered.bind(i, j))
+# cell.body_shape_exited.connect(_on_cell_body_shape_exited.bind(i, j))
+
+ cell.collision_layer = 0
+ cell.collision_mask = detection_mask
+ cell.monitorable = true
+ cell.input_ray_pickable = false
+ add_child(cell)
+ cell.set_owner(get_tree().edited_scene_root)
+
+ var col_shape := CollisionShape3D.new()
+ col_shape.shape = _box_shape
+ col_shape.name = "CollisionShape3D"
+ cell.add_child(col_shape)
+ col_shape.set_owner(get_tree().edited_scene_root)
+
+ if debug_view:
+ var box = MeshInstance3D.new()
+ box.name = "MeshInstance3D"
+ var box_mesh = BoxMesh.new()
+
+ box_mesh.set_size(Vector3(cell_width, cell_height, cell_width))
+ box_mesh.material = _standard_box_material
+
+ box.mesh = box_mesh
+ cell.add_child(box)
+ box.set_owner(get_tree().edited_scene_root)
+
+
+func _update_obs(cell_i: int, cell_j: int, collision_layer: int, entered: bool):
+ for key in _collision_mapping:
+ var bit_mask = 2 ** key
+ if (collision_layer & bit_mask) > 0:
+ var collison_map_index = _collision_mapping[key]
+
+ var obs_index = (
+ (cell_i * grid_size_x * _n_layers_per_cell)
+ + (cell_j * _n_layers_per_cell)
+ + collison_map_index
+ )
+ #prints(obs_index, cell_i, cell_j)
+ if entered:
+ _obs_buffer[obs_index] += 1
+ else:
+ _obs_buffer[obs_index] -= 1
+
+
+func _toggle_cell(cell_i: int, cell_j: int):
+ var cell = get_node_or_null("GridCell %s %s" % [cell_i, cell_j])
+
+ if cell == null:
+ print("cell not found, returning")
+
+ var n_hits = 0
+ var start_index = (cell_i * grid_size_x * _n_layers_per_cell) + (cell_j * _n_layers_per_cell)
+ for i in _n_layers_per_cell:
+ n_hits += _obs_buffer[start_index + i]
+
+ var cell_mesh = cell.get_node_or_null("MeshInstance3D")
+ if n_hits > 0:
+ cell_mesh.mesh.material = _highlighted_box_material
+ else:
+ cell_mesh.mesh.material = _standard_box_material
+
+
+func _on_cell_area_entered(area: Area3D, cell_i: int, cell_j: int):
+ #prints("_on_cell_area_entered", cell_i, cell_j)
+ _update_obs(cell_i, cell_j, area.collision_layer, true)
+ if debug_view:
+ _toggle_cell(cell_i, cell_j)
+ #print(_obs_buffer)
+
+
+func _on_cell_area_exited(area: Area3D, cell_i: int, cell_j: int):
+ #prints("_on_cell_area_exited", cell_i, cell_j)
+ _update_obs(cell_i, cell_j, area.collision_layer, false)
+ if debug_view:
+ _toggle_cell(cell_i, cell_j)
+
+
+func _on_cell_body_entered(body: Node3D, cell_i: int, cell_j: int):
+ #prints("_on_cell_body_entered", cell_i, cell_j)
+ _update_obs(cell_i, cell_j, body.collision_layer, true)
+ if debug_view:
+ _toggle_cell(cell_i, cell_j)
+
+
+func _on_cell_body_exited(body: Node3D, cell_i: int, cell_j: int):
+ #prints("_on_cell_body_exited", cell_i, cell_j)
+ _update_obs(cell_i, cell_j, body.collision_layer, false)
+ if debug_view:
+ _toggle_cell(cell_i, cell_j)
diff --git a/addons/godot_rl_agents/sensors/sensors_3d/ISensor3D.gd b/addons/godot_rl_agents/sensors/sensors_3d/ISensor3D.gd
new file mode 100644
index 0000000..aca3c2d
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_3d/ISensor3D.gd
@@ -0,0 +1,25 @@
+extends Node3D
+class_name ISensor3D
+
+var _obs: Array = []
+var _active := false
+
+
+func get_observation():
+ pass
+
+
+func activate():
+ _active = true
+
+
+func deactivate():
+ _active = false
+
+
+func _update_observation():
+ pass
+
+
+func reset():
+ pass
diff --git a/addons/godot_rl_agents/sensors/sensors_3d/RGBCameraSensor3D.gd b/addons/godot_rl_agents/sensors/sensors_3d/RGBCameraSensor3D.gd
new file mode 100644
index 0000000..1037e97
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_3d/RGBCameraSensor3D.gd
@@ -0,0 +1,21 @@
+extends Node3D
+class_name RGBCameraSensor3D
+var camera_pixels = null
+
+@onready var camera_texture := $Control/TextureRect/CameraTexture as Sprite2D
+@onready var sub_viewport := $SubViewport as SubViewport
+
+
+func get_camera_pixel_encoding():
+ return camera_texture.get_texture().get_image().get_data().hex_encode()
+
+
+func get_camera_shape() -> Array:
+ assert(
+ sub_viewport.size.x >= 36 and sub_viewport.size.y >= 36,
+ "SubViewport size must be 36x36 or larger."
+ )
+ if sub_viewport.transparent_bg:
+ return [4, sub_viewport.size.y, sub_viewport.size.x]
+ else:
+ return [3, sub_viewport.size.y, sub_viewport.size.x]
diff --git a/addons/godot_rl_agents/sensors/sensors_3d/RGBCameraSensor3D.tscn b/addons/godot_rl_agents/sensors/sensors_3d/RGBCameraSensor3D.tscn
new file mode 100644
index 0000000..052b557
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_3d/RGBCameraSensor3D.tscn
@@ -0,0 +1,41 @@
+[gd_scene load_steps=3 format=3 uid="uid://baaywi3arsl2m"]
+
+[ext_resource type="Script" path="res://addons/godot_rl_agents/sensors/sensors_3d/RGBCameraSensor3D.gd" id="1"]
+
+[sub_resource type="ViewportTexture" id="1"]
+viewport_path = NodePath("SubViewport")
+
+[node name="RGBCameraSensor3D" type="Node3D"]
+script = ExtResource("1")
+
+[node name="RemoteTransform3D" type="RemoteTransform3D" parent="."]
+remote_path = NodePath("../SubViewport/Camera3D")
+
+[node name="SubViewport" type="SubViewport" parent="."]
+size = Vector2i(32, 32)
+render_target_update_mode = 3
+
+[node name="Camera3D" type="Camera3D" parent="SubViewport"]
+near = 0.5
+
+[node name="Control" type="Control" parent="."]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+
+[node name="TextureRect" type="ColorRect" parent="Control"]
+layout_mode = 0
+offset_left = 1096.0
+offset_top = 534.0
+offset_right = 1114.0
+offset_bottom = 552.0
+scale = Vector2(10, 10)
+color = Color(0.00784314, 0.00784314, 0.00784314, 1)
+
+[node name="CameraTexture" type="Sprite2D" parent="Control/TextureRect"]
+texture = SubResource("1")
+offset = Vector2(9, 9)
+flip_v = true
diff --git a/addons/godot_rl_agents/sensors/sensors_3d/RaycastSensor3D.gd b/addons/godot_rl_agents/sensors/sensors_3d/RaycastSensor3D.gd
new file mode 100644
index 0000000..1357529
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_3d/RaycastSensor3D.gd
@@ -0,0 +1,185 @@
+@tool
+extends ISensor3D
+class_name RayCastSensor3D
+@export_flags_3d_physics var collision_mask = 1:
+ get:
+ return collision_mask
+ set(value):
+ collision_mask = value
+ _update()
+@export_flags_3d_physics var boolean_class_mask = 1:
+ get:
+ return boolean_class_mask
+ set(value):
+ boolean_class_mask = value
+ _update()
+
+@export var n_rays_width := 6.0:
+ get:
+ return n_rays_width
+ set(value):
+ n_rays_width = value
+ _update()
+
+@export var n_rays_height := 6.0:
+ get:
+ return n_rays_height
+ set(value):
+ n_rays_height = value
+ _update()
+
+@export var ray_length := 10.0:
+ get:
+ return ray_length
+ set(value):
+ ray_length = value
+ _update()
+
+@export var cone_width := 60.0:
+ get:
+ return cone_width
+ set(value):
+ cone_width = value
+ _update()
+
+@export var cone_height := 60.0:
+ get:
+ return cone_height
+ set(value):
+ cone_height = value
+ _update()
+
+@export var collide_with_areas := false:
+ get:
+ return collide_with_areas
+ set(value):
+ collide_with_areas = value
+ _update()
+
+@export var collide_with_bodies := true:
+ get:
+ return collide_with_bodies
+ set(value):
+ collide_with_bodies = value
+ _update()
+
+@export var class_sensor := false
+
+var rays := []
+var geo = null
+
+
+func _update():
+ if Engine.is_editor_hint():
+ if is_node_ready():
+ _spawn_nodes()
+
+
+func _ready() -> void:
+ if Engine.is_editor_hint():
+ if get_child_count() == 0:
+ _spawn_nodes()
+ else:
+ _spawn_nodes()
+
+
+func _spawn_nodes():
+ print("spawning nodes")
+ for ray in get_children():
+ ray.queue_free()
+ if geo:
+ geo.clear()
+ #$Lines.remove_points()
+ rays = []
+
+ var horizontal_step = cone_width / (n_rays_width)
+ var vertical_step = cone_height / (n_rays_height)
+
+ var horizontal_start = horizontal_step / 2 - cone_width / 2
+ var vertical_start = vertical_step / 2 - cone_height / 2
+
+ var points = []
+
+ for i in n_rays_width:
+ for j in n_rays_height:
+ var angle_w = horizontal_start + i * horizontal_step
+ var angle_h = vertical_start + j * vertical_step
+ #angle_h = 0.0
+ var ray = RayCast3D.new()
+ var cast_to = to_spherical_coords(ray_length, angle_w, angle_h)
+ ray.set_target_position(cast_to)
+
+ points.append(cast_to)
+
+ ray.set_name("node_" + str(i) + " " + str(j))
+ ray.enabled = true
+ ray.collide_with_bodies = collide_with_bodies
+ ray.collide_with_areas = collide_with_areas
+ ray.collision_mask = collision_mask
+ add_child(ray)
+ ray.set_owner(get_tree().edited_scene_root)
+ rays.append(ray)
+ ray.force_raycast_update()
+
+
+# if Engine.editor_hint:
+# _create_debug_lines(points)
+
+
+func _create_debug_lines(points):
+ if not geo:
+ geo = ImmediateMesh.new()
+ add_child(geo)
+
+ geo.clear()
+ geo.begin(Mesh.PRIMITIVE_LINES)
+ for point in points:
+ geo.set_color(Color.AQUA)
+ geo.add_vertex(Vector3.ZERO)
+ geo.add_vertex(point)
+ geo.end()
+
+
+func display():
+ if geo:
+ geo.display()
+
+
+func to_spherical_coords(r, inc, azimuth) -> Vector3:
+ return Vector3(
+ r * sin(deg_to_rad(inc)) * cos(deg_to_rad(azimuth)),
+ r * sin(deg_to_rad(azimuth)),
+ r * cos(deg_to_rad(inc)) * cos(deg_to_rad(azimuth))
+ )
+
+
+func get_observation() -> Array:
+ return self.calculate_raycasts()
+
+
+func calculate_raycasts() -> Array:
+ var result = []
+ for ray in rays:
+ ray.set_enabled(true)
+ ray.force_raycast_update()
+ var distance = _get_raycast_distance(ray)
+
+ result.append(distance)
+ if class_sensor:
+ var hit_class: float = 0
+ if ray.get_collider():
+ var hit_collision_layer = ray.get_collider().collision_layer
+ hit_collision_layer = hit_collision_layer & collision_mask
+ hit_class = (hit_collision_layer & boolean_class_mask) > 0
+ result.append(float(hit_class))
+ ray.set_enabled(false)
+ return result
+
+
+func _get_raycast_distance(ray: RayCast3D) -> float:
+ if !ray.is_colliding():
+ return 0.0
+
+ var distance = (global_transform.origin - ray.get_collision_point()).length()
+ distance = clamp(distance, 0.0, ray_length)
+ return (ray_length - distance) / ray_length
diff --git a/addons/godot_rl_agents/sensors/sensors_3d/RaycastSensor3D.tscn b/addons/godot_rl_agents/sensors/sensors_3d/RaycastSensor3D.tscn
new file mode 100644
index 0000000..35f9796
--- /dev/null
+++ b/addons/godot_rl_agents/sensors/sensors_3d/RaycastSensor3D.tscn
@@ -0,0 +1,27 @@
+[gd_scene load_steps=2 format=3 uid="uid://b803cbh1fmy66"]
+
+[ext_resource type="Script" path="res://addons/godot_rl_agents/sensors/sensors_3d/RaycastSensor3D.gd" id="1"]
+
+[node name="RaycastSensor3D" type="Node3D"]
+script = ExtResource("1")
+n_rays_width = 4.0
+n_rays_height = 2.0
+ray_length = 11.0
+
+[node name="node_1 0" type="RayCast3D" parent="."]
+target_position = Vector3(-1.38686, -2.84701, 10.5343)
+
+[node name="node_1 1" type="RayCast3D" parent="."]
+target_position = Vector3(-1.38686, 2.84701, 10.5343)
+
+[node name="node_2 0" type="RayCast3D" parent="."]
+target_position = Vector3(1.38686, -2.84701, 10.5343)
+
+[node name="node_2 1" type="RayCast3D" parent="."]
+target_position = Vector3(1.38686, 2.84701, 10.5343)
+
+[node name="node_3 0" type="RayCast3D" parent="."]
+target_position = Vector3(4.06608, -2.84701, 9.81639)
+
+[node name="node_3 1" type="RayCast3D" parent="."]
+target_position = Vector3(4.06608, 2.84701, 9.81639)
diff --git a/addons/godot_rl_agents/sync.gd b/addons/godot_rl_agents/sync.gd
new file mode 100644
index 0000000..889127a
--- /dev/null
+++ b/addons/godot_rl_agents/sync.gd
@@ -0,0 +1,579 @@
+extends Node
+
+# --fixed-fps 2000 --disable-render-loop
+
+enum ControlModes { HUMAN, TRAINING, ONNX_INFERENCE }
+@export var control_mode: ControlModes = ControlModes.TRAINING
+@export_range(1, 10, 1, "or_greater") var action_repeat := 8
+@export_range(0, 10, 0.1, "or_greater") var speed_up := 1.0
+@export var onnx_model_path := ""
+
+# Onnx model stored for each requested path
+var onnx_models: Dictionary
+
+@onready var start_time = Time.get_ticks_msec()
+
+const MAJOR_VERSION := "0"
+const MINOR_VERSION := "7"
+const DEFAULT_PORT := "11008"
+const DEFAULT_SEED := "1"
+var stream: StreamPeerTCP = null
+var connected = false
+var message_center
+var should_connect = true
+
+var all_agents: Array
+var agents_training: Array
+## Policy name of each agent, for use with multi-policy multi-agent RL cases
+var agents_training_policy_names: Array[String] = ["shared_policy"]
+var agents_inference: Array
+var agents_heuristic: Array
+
+## For recording expert demos
+var agent_demo_record: Node
+## File path for writing recorded trajectories
+var expert_demo_save_path: String
+## Stores recorded trajectories
+var demo_trajectories: Array
+## A trajectory includes obs: Array, acts: Array, terminal (set in Python env instead)
+var current_demo_trajectory: Array
+
+var need_to_send_obs = false
+var args = null
+var initialized = false
+var just_reset = false
+var onnx_model = null
+var n_action_steps = 0
+
+var _action_space_training: Array[Dictionary] = []
+var _action_space_inference: Array[Dictionary] = []
+var _obs_space_training: Array[Dictionary] = []
+
+# Called when the node enters the scene tree for the first time.
+func _ready():
+ await get_tree().root.ready
+ get_tree().set_pause(true)
+ _initialize()
+ await get_tree().create_timer(1.0).timeout
+ get_tree().set_pause(false)
+
+
+func _initialize():
+ _get_agents()
+ args = _get_args()
+ Engine.physics_ticks_per_second = _get_speedup() * 60 # Replace with function body.
+ Engine.time_scale = _get_speedup() * 1.0
+ prints(
+ "physics ticks",
+ Engine.physics_ticks_per_second,
+ Engine.time_scale,
+ _get_speedup(),
+ speed_up
+ )
+
+ _set_heuristic("human", all_agents)
+
+ _initialize_training_agents()
+ _initialize_inference_agents()
+ _initialize_demo_recording()
+
+ _set_seed()
+ _set_action_repeat()
+ initialized = true
+
+
+func _initialize_training_agents():
+ if agents_training.size() > 0:
+ _obs_space_training.resize(agents_training.size())
+ _action_space_training.resize(agents_training.size())
+ for agent_idx in range(0, agents_training.size()):
+ _obs_space_training[agent_idx] = agents_training[agent_idx].get_obs_space()
+ _action_space_training[agent_idx] = agents_training[agent_idx].get_action_space()
+ connected = connect_to_server()
+ if connected:
+ _set_heuristic("model", agents_training)
+ _handshake()
+ _send_env_info()
+ else:
+ push_warning(
+ "Couldn't connect to Python server, using human controls instead. ",
+ "Did you start the training server using e.g. `gdrl` from the console?"
+ )
+
+
+func _initialize_inference_agents():
+ if agents_inference.size() > 0:
+ if control_mode == ControlModes.ONNX_INFERENCE:
+ assert(
+ FileAccess.file_exists(onnx_model_path),
+ "Onnx Model Path set on Sync node does not exist: %s" % onnx_model_path
+ )
+ onnx_models[onnx_model_path] = ONNXModel.new(onnx_model_path, 1)
+
+ for agent in agents_inference:
+ var action_space = agent.get_action_space()
+ _action_space_inference.append(action_space)
+
+ var agent_onnx_model: ONNXModel
+ if agent.onnx_model_path.is_empty():
+ assert(
+ onnx_models.has(onnx_model_path),
+ (
+ "Node %s has no onnx model path set " % agent.get_path()
+ + "and sync node's control mode is not set to OnnxInference. "
+ + "Either add the path to the AIController, "
+ + "or if you want to use the path set on sync node instead, "
+ + "set control mode to OnnxInference."
+ )
+ )
+ prints(
+ "Info: AIController %s" % agent.get_path(),
+ "has no onnx model path set.",
+ "Using path set on the sync node instead."
+ )
+ agent_onnx_model = onnx_models[onnx_model_path]
+ else:
+ if not onnx_models.has(agent.onnx_model_path):
+ assert(
+ FileAccess.file_exists(agent.onnx_model_path),
+ (
+ "Onnx Model Path set on %s node does not exist: %s"
+ % [agent.get_path(), agent.onnx_model_path]
+ )
+ )
+ onnx_models[agent.onnx_model_path] = ONNXModel.new(agent.onnx_model_path, 1)
+ agent_onnx_model = onnx_models[agent.onnx_model_path]
+
+ agent.onnx_model = agent_onnx_model
+ if not agent_onnx_model.action_means_only_set:
+ agent_onnx_model.set_action_means_only(action_space)
+
+ _set_heuristic("model", agents_inference)
+
+
+func _initialize_demo_recording():
+ if agent_demo_record:
+ expert_demo_save_path = agent_demo_record.expert_demo_save_path
+ assert(
+ not expert_demo_save_path.is_empty(),
+ "Expert demo save path set in %s is empty." % agent_demo_record.get_path()
+ )
+
+ InputMap.add_action("RemoveLastDemoEpisode")
+ InputMap.action_add_event(
+ "RemoveLastDemoEpisode", agent_demo_record.remove_last_episode_key
+ )
+ current_demo_trajectory.resize(2)
+ current_demo_trajectory[0] = []
+ current_demo_trajectory[1] = []
+ agent_demo_record.heuristic = "demo_record"
+
+
+func _physics_process(_delta):
+ # two modes, human control, agent control
+ # pause tree, send obs, get actions, set actions, unpause tree
+
+ _demo_record_process()
+
+ if n_action_steps % action_repeat != 0:
+ n_action_steps += 1
+ return
+
+ n_action_steps += 1
+
+ _training_process()
+ _inference_process()
+ _heuristic_process()
+
+
+func _training_process():
+ if connected:
+ get_tree().set_pause(true)
+
+ if just_reset:
+ just_reset = false
+ var obs = _get_obs_from_agents(agents_training)
+
+ var reply = {"type": "reset", "obs": obs}
+ _send_dict_as_json_message(reply)
+ # this should go straight to getting the action and setting it checked the agent, no need to perform one phyics tick
+ get_tree().set_pause(false)
+ return
+
+ if need_to_send_obs:
+ need_to_send_obs = false
+ var reward = _get_reward_from_agents()
+ var done = _get_done_from_agents()
+ #_reset_agents_if_done() # this ensures the new observation is from the next env instance : NEEDS REFACTOR
+
+ var obs = _get_obs_from_agents(agents_training)
+
+ var reply = {"type": "step", "obs": obs, "reward": reward, "done": done}
+ _send_dict_as_json_message(reply)
+
+ var handled = handle_message()
+
+
+func _inference_process():
+ if agents_inference.size() > 0:
+ var obs: Array = _get_obs_from_agents(agents_inference)
+ var actions = []
+
+ for agent_id in range(0, agents_inference.size()):
+ var model: ONNXModel = agents_inference[agent_id].onnx_model
+ var action = model.run_inference(
+ obs[agent_id]["obs"], 1.0
+ )
+ var action_dict = _extract_action_dict(
+ action["output"], _action_space_inference[agent_id], model.action_means_only
+ )
+ actions.append(action_dict)
+
+ _set_agent_actions(actions, agents_inference)
+ _reset_agents_if_done(agents_inference)
+ get_tree().set_pause(false)
+
+
+func _demo_record_process():
+ if not agent_demo_record:
+ return
+
+ if Input.is_action_just_pressed("RemoveLastDemoEpisode"):
+ print("[Sync script][Demo recorder] Removing last recorded episode.")
+ demo_trajectories.remove_at(demo_trajectories.size() - 1)
+ print("Remaining episode count: %d" % demo_trajectories.size())
+
+ if n_action_steps % agent_demo_record.action_repeat != 0:
+ return
+
+ var obs_dict: Dictionary = agent_demo_record.get_obs()
+
+ # Get the current obs from the agent
+ assert(
+ obs_dict.has("obs"),
+ "Demo recorder needs an 'obs' key in get_obs() returned dictionary to record obs from."
+ )
+ current_demo_trajectory[0].append(obs_dict.obs)
+
+ # Get the action applied for the current obs from the agent
+ agent_demo_record.set_action()
+ var acts = agent_demo_record.get_action()
+
+ var terminal = agent_demo_record.get_done()
+ # Record actions only for non-terminal states
+ if terminal:
+ agent_demo_record.set_done_false()
+ else:
+ current_demo_trajectory[1].append(acts)
+
+ if terminal:
+ #current_demo_trajectory[2].append(true)
+ demo_trajectories.append(current_demo_trajectory.duplicate(true))
+ print("[Sync script][Demo recorder] Recorded episode count: %d" % demo_trajectories.size())
+ current_demo_trajectory[0].clear()
+ current_demo_trajectory[1].clear()
+
+
+func _heuristic_process():
+ for agent in agents_heuristic:
+ _reset_agents_if_done(agents_heuristic)
+
+
+func _extract_action_dict(action_array: Array, action_space: Dictionary, action_means_only: bool):
+ var index = 0
+ var result = {}
+ for key in action_space.keys():
+ var size = action_space[key]["size"]
+ var action_type = action_space[key]["action_type"]
+ if action_type == "discrete":
+ var largest_logit: float # Value of the largest logit for this action in the actions array
+ var largest_logit_idx: int # Index of the largest logit for this action in the actions array
+ for logit_idx in range(0, size):
+ var logit_value = action_array[index + logit_idx]
+ if logit_value > largest_logit:
+ largest_logit = logit_value
+ largest_logit_idx = logit_idx
+ result[key] = largest_logit_idx # Index of the largest logit is the discrete action value
+ index += size
+ elif action_type == "continuous":
+ # For continous actions, we only take the action mean values
+ result[key] = clamp_array(action_array.slice(index, index + size), -1.0, 1.0)
+ if action_means_only:
+ index += size # model only outputs action means, so we move index by size
+ else:
+ index += size * 2 # model outputs logstd after action mean, we skip the logstd part
+
+ else:
+ assert(false, 'Only "discrete" and "continuous" action types supported. Found: %s action type set.' % action_type)
+
+
+ return result
+
+
+## For AIControllers that inherit mode from sync, sets the correct mode.
+func _set_agent_mode(agent: Node):
+ var agent_inherits_mode: bool = agent.control_mode == agent.ControlModes.INHERIT_FROM_SYNC
+
+ if agent_inherits_mode:
+ match control_mode:
+ ControlModes.HUMAN:
+ agent.control_mode = agent.ControlModes.HUMAN
+ ControlModes.TRAINING:
+ agent.control_mode = agent.ControlModes.TRAINING
+ ControlModes.ONNX_INFERENCE:
+ agent.control_mode = agent.ControlModes.ONNX_INFERENCE
+
+
+func _get_agents():
+ all_agents = get_tree().get_nodes_in_group("AGENT")
+ for agent in all_agents:
+ _set_agent_mode(agent)
+
+ if agent.control_mode == agent.ControlModes.TRAINING:
+ agents_training.append(agent)
+ elif agent.control_mode == agent.ControlModes.ONNX_INFERENCE:
+ agents_inference.append(agent)
+ elif agent.control_mode == agent.ControlModes.HUMAN:
+ agents_heuristic.append(agent)
+ elif agent.control_mode == agent.ControlModes.RECORD_EXPERT_DEMOS:
+ assert(
+ not agent_demo_record,
+ "Currently only a single AIController can be used for recording expert demos."
+ )
+ agent_demo_record = agent
+
+ var training_agent_count = agents_training.size()
+ agents_training_policy_names.resize(training_agent_count)
+ for i in range(0, training_agent_count):
+ agents_training_policy_names[i] = agents_training[i].policy_name
+
+
+func _set_heuristic(heuristic, agents: Array):
+ for agent in agents:
+ agent.set_heuristic(heuristic)
+
+
+func _handshake():
+ print("performing handshake")
+
+ var json_dict = _get_dict_json_message()
+ assert(json_dict["type"] == "handshake")
+ var major_version = json_dict["major_version"]
+ var minor_version = json_dict["minor_version"]
+ if major_version != MAJOR_VERSION:
+ print("WARNING: major verison mismatch ", major_version, " ", MAJOR_VERSION)
+ if minor_version != MINOR_VERSION:
+ print("WARNING: minor verison mismatch ", minor_version, " ", MINOR_VERSION)
+
+ print("handshake complete")
+
+
+func _get_dict_json_message():
+ # returns a dictionary from of the most recent message
+ # this is not waiting
+ while stream.get_available_bytes() == 0:
+ stream.poll()
+ if stream.get_status() != 2:
+ print("server disconnected status, closing")
+ get_tree().quit()
+ return null
+
+ OS.delay_usec(10)
+
+ var message = stream.get_string()
+ var json_data = JSON.parse_string(message)
+
+ return json_data
+
+
+func _send_dict_as_json_message(dict):
+ stream.put_string(JSON.stringify(dict, "", false))
+
+
+func _send_env_info():
+ var json_dict = _get_dict_json_message()
+ assert(json_dict["type"] == "env_info")
+
+ var message = {
+ "type": "env_info",
+ "observation_space": _obs_space_training,
+ "action_space": _action_space_training,
+ "n_agents": len(agents_training),
+ "agent_policy_names": agents_training_policy_names
+ }
+ _send_dict_as_json_message(message)
+
+
+func connect_to_server():
+ print("Waiting for one second to allow server to start")
+ OS.delay_msec(1000)
+ print("trying to connect to server")
+ stream = StreamPeerTCP.new()
+
+ # "localhost" was not working on windows VM, had to use the IP
+ var ip = "127.0.0.1"
+ var port = _get_port()
+ var connect = stream.connect_to_host(ip, port)
+ stream.set_no_delay(true) # TODO check if this improves performance or not
+ stream.poll()
+ # Fetch the status until it is either connected (2) or failed to connect (3)
+ while stream.get_status() < 2:
+ stream.poll()
+ return stream.get_status() == 2
+
+
+func _get_args():
+ print("getting command line arguments")
+ var arguments = {}
+ for argument in OS.get_cmdline_args():
+ print(argument)
+ if argument.find("=") > -1:
+ var key_value = argument.split("=")
+ arguments[key_value[0].lstrip("--")] = key_value[1]
+ else:
+ # Options without an argument will be present in the dictionary,
+ # with the value set to an empty string.
+ arguments[argument.lstrip("--")] = ""
+
+ return arguments
+
+
+func _get_speedup():
+ print(args)
+ return args.get("speedup", str(speed_up)).to_float()
+
+
+func _get_port():
+ return args.get("port", DEFAULT_PORT).to_int()
+
+
+func _set_seed():
+ var _seed = args.get("env_seed", DEFAULT_SEED).to_int()
+ seed(_seed)
+
+
+func _set_action_repeat():
+ action_repeat = args.get("action_repeat", str(action_repeat)).to_int()
+
+
+func disconnect_from_server():
+ stream.disconnect_from_host()
+
+
+func handle_message() -> bool:
+ # get json message: reset, step, close
+ var message = _get_dict_json_message()
+ if message["type"] == "close":
+ print("received close message, closing game")
+ get_tree().quit()
+ get_tree().set_pause(false)
+ return true
+
+ if message["type"] == "reset":
+ print("resetting all agents")
+ _reset_agents()
+ just_reset = true
+ get_tree().set_pause(false)
+ #print("resetting forcing draw")
+# RenderingServer.force_draw()
+# var obs = _get_obs_from_agents()
+# print("obs ", obs)
+# var reply = {
+# "type": "reset",
+# "obs": obs
+# }
+# _send_dict_as_json_message(reply)
+ return true
+
+ if message["type"] == "call":
+ var method = message["method"]
+ var returns = _call_method_on_agents(method)
+ var reply = {"type": "call", "returns": returns}
+ print("calling method from Python")
+ _send_dict_as_json_message(reply)
+ return handle_message()
+
+ if message["type"] == "action":
+ var action = message["action"]
+ _set_agent_actions(action, agents_training)
+ need_to_send_obs = true
+ get_tree().set_pause(false)
+ return true
+
+ print("message was not handled")
+ return false
+
+
+func _call_method_on_agents(method):
+ var returns = []
+ for agent in all_agents:
+ returns.append(agent.call(method))
+
+ return returns
+
+
+func _reset_agents_if_done(agents = all_agents):
+ for agent in agents:
+ if agent.get_done():
+ agent.set_done_false()
+
+
+func _reset_agents(agents = all_agents):
+ for agent in agents:
+ agent.needs_reset = true
+ #agent.reset()
+
+
+func _get_obs_from_agents(agents: Array = all_agents):
+ var obs = []
+ for agent in agents:
+ obs.append(agent.get_obs())
+ return obs
+
+
+func _get_reward_from_agents(agents: Array = agents_training):
+ var rewards = []
+ for agent in agents:
+ rewards.append(agent.get_reward())
+ agent.zero_reward()
+ return rewards
+
+
+func _get_done_from_agents(agents: Array = agents_training):
+ var dones = []
+ for agent in agents:
+ var done = agent.get_done()
+ if done:
+ agent.set_done_false()
+ dones.append(done)
+ return dones
+
+
+func _set_agent_actions(actions, agents: Array = all_agents):
+ for i in range(len(actions)):
+ agents[i].set_action(actions[i])
+
+
+func clamp_array(arr: Array, min: float, max: float):
+ var output: Array = []
+ for a in arr:
+ output.append(clamp(a, min, max))
+ return output
+
+
+## Save recorded export demos on window exit (Close game window instead of "Stop" button in Godot Editor)
+func _notification(what):
+ if demo_trajectories.size() == 0 or expert_demo_save_path.is_empty():
+ return
+
+ if what == NOTIFICATION_PREDELETE:
+ var json_string = JSON.stringify(demo_trajectories, "", false)
+ var file = FileAccess.open(expert_demo_save_path, FileAccess.WRITE)
+
+ if not file:
+ var error: Error = FileAccess.get_open_error()
+ assert(not error, "There was an error opening the file: %d" % error)
+
+ file.store_line(json_string)
+ var error = file.get_error()
+ assert(not error, "There was an error after trying to write to the file: %d" % error)
diff --git a/agent.py b/agent.py
new file mode 100644
index 0000000..a7aa494
--- /dev/null
+++ b/agent.py
@@ -0,0 +1,159 @@
+import args
+import os
+import pathlib
+
+import torch as T
+import torch.nn as nn
+
+from typing import Callable
+
+from stable_baselines3 import PPO
+from stable_baselines3.common.callbacks import CheckpointCallback
+from stable_baselines3.common.vec_env.vec_monitor import VecMonitor
+
+from godot_rl.core.utils import can_import
+from godot_rl.wrappers.onnx.stable_baselines_export import export_ppo_model_as_onnx
+from godot_rl.wrappers.stable_baselines_wrapper import StableBaselinesGodotEnv
+
+def main(policy_name=None, policy=None, parseargs=None):
+ if can_import("ray"):
+ print("WARNING: SB3 and ray[rllib] are not compatible.")
+
+ args, extras = parseargs
+ # args, extras = args.parse_args()
+
+ def handle_onnx_export():
+ '''
+ Enforces the onnx and zip extentions when saving models.
+ This avoids potential conflicts in case of identical names and extentions
+ '''
+ if args.onnx_export_path is not None:
+ path_onnx = pathlib.Path(args.onnx_export_path).with_suffix(".onnx")
+ print(f"Exporting onnx to: {os.path.abspath(path_onnx)}")
+ export_ppo_model_as_onnx(model, str(path_onnx))
+
+ def handle_model_save():
+ if args.save_model_path is not None:
+ zip_save_path = pathlib.Path(Args.save_model_path).with_suffix(".zip")
+ print(f"Saving model to: {os.path.abspath(zip_save_path)}")
+ model.save(zip_save_path)
+
+ def close_env():
+ try:
+ print("Closing env...")
+ env.close()
+ except Exception as e:
+ print(f"Exception while closing env: {e}")
+
+ if policy_name is None:
+ path_checkpoint = os.path.join(args.exper_dir, f"{args.exper_name}_checkpoints")
+ else:
+ path_checkpoint = os.path.join(args.exper_dir, f"{policy_name}_checkpoints")
+
+ abs_path_checkpoint = os.path.abspath(path_checkpoint)
+
+ if args.save_checkpoint_frequency is not None and os.path.isdir(path_checkpoint):
+ raise RuntimeError(
+ f"{abs_path_checkpoint} already exists."
+ "Use a different directory or different name."
+ "If you want to override previous checkpoints you have to delete them manually."
+ )
+
+ if args.inference and args.resume_model_path is None:
+ raise parser.error(
+ "Using --inference requires --resume_model_path to be set."
+ )
+
+ if args.env_path is None and args.viz:
+ print("Info: using --viz without --env_path set has no effect.")
+ print("\nIn editor training will always render.")
+
+ env = StableBaselinesGodotEnv(
+ env_path=args.env_path,
+ show_window=args.viz,
+ seed=args.seed,
+ n_parallel=args.n_parallel,
+ speedup=args.speedup
+ )
+ env = VecMonitor(env)
+
+ # LR schedule code snippet from:
+ # https://stable-baselines3.readthedocs.io/en/master/guide/examples.html#learning-rate-schedule
+ def linear_schedule(initial_value: float) -> Callable[[float], float]:
+ """
+ Linear learning rate schedule.
+
+ :param initial_value: Initial learning rate.
+ :return: schedule that computes
+ current learning rate depending on remaining progress
+ """
+
+ def func(progress_remaining: float) -> float:
+ """
+ Progress will decrease from 1 (beginning) to 0.
+
+ :param progress_remaining:
+ :return: current learning rate
+ """
+ return progress_remaining * initial_value
+
+ return func
+
+ if args.resume_model_path is None:
+ if not args.linear_lr_schedule:
+ learning_rate = 0.0003
+ else:
+ linear_schedule(0.0003)
+
+ model: PPO = PPO(
+ # 'MultiInputPolicy' serves as an alias for MultiInputActorCriticPolicy
+ "MultiInputPolicy",
+ env,
+ batch_size=64,
+ ent_coef=0.01,
+ verbose=2,
+ n_steps=256,
+ tensorboard_log=args.exper_dir,
+ learning_rate=learning_rate,
+ policy_kwargs=policy,
+ )
+ else:
+ path_zip = pathlib.Path(args.resume_model_path)
+ print(f"Loading model: {os.path.abspath(pathzip)}")
+ model: PPO = PPO.load(
+ path_zip,
+ env=env,
+ tensorboard_log=args.exper_dir
+ )
+
+ if args.inference:
+ obs = env.reset()
+ for i in range(args.timesteps):
+ action, _state = model.predict(obs, deterministic=True)
+ obs, reward, done, info = env.step(action)
+ else:
+ learn_arguments = dict(
+ total_timesteps=args.timesteps,
+ tb_log_name=policy_name
+ )
+ if args.save_checkpoint_frequency:
+ print("Checkpoint saving enabled.")
+ print(f"\nCheckpoints will be saved to {abs_path_checkpoint}")
+ checkpoint_callback = CheckpointCallback(
+ save_freq=(args.save_checkpoint_frequency // env.num_envs),
+ save_path=path_checkpoint,
+ name_prefix=policy_name
+ )
+ learn_arguments["callback"] = checkpoint_callback
+ try:
+ model.learn(**learn_arguments)
+ except KeyboardInterrupt:
+ print(
+ """
+ Training interrupted by user. Will save if --save_model_path was set and/or export if --onnx_export was set.
+ """
+ )
+
+ close_env()
+ handle_onnx_export()
+ handle_model_save()
diff --git a/args.py b/args.py
new file mode 100644
index 0000000..78a3483
--- /dev/null
+++ b/args.py
@@ -0,0 +1,109 @@
+import argparse
+
+def parse_args():
+
+ parser = argparse.ArgumentParser(
+ prog='Pneuma',
+ allow_abbrev=False,
+ description='A Reinforcement Learning platform made with Godot',
+ )
+ parser.add_argument(
+ "--env_path",
+ default=None,
+ type=str,
+ help="The Godot binary to use, do not include for in editor training",
+ )
+ parser.add_argument(
+ "--exper_dir",
+ default="logs/sb3",
+ type=str,
+ help="The name of the experiment directory, in which the tensorboard logs and checkpoints (if enabled) are "
+ "getting stored.",
+ )
+ parser.add_argument(
+ "--exper_name",
+ default="experiment",
+ type=str,
+ help="The name of the experiment, which will be displayed in tensorboard and "
+ "for checkpoint directory and name (if enabled).",
+ )
+ parser.add_argument(
+ "--seed",
+ type=int,
+ default=1,
+ help="seed of the experiment"
+ )
+ parser.add_argument(
+ "--resume_model_path",
+ default=None,
+ type=str,
+ help="The path to a model file previously saved using --save_model_path or a checkpoint saved using "
+ "--save_checkpoints_frequency. Use this to resume training or infer from a saved model.",
+ )
+ parser.add_argument(
+ "--save_model_path",
+ default=None,
+ type=str,
+ help="The path to use for saving the trained sb3 model after training is complete. Saved model can be used later "
+ "to resume training. Extension will be set to .zip",
+ )
+ parser.add_argument(
+ "--save_checkpoint_frequency",
+ default=None,
+ type=int,
+ help=(
+ "If set, will save checkpoints every 'frequency' environment steps. "
+ "Requires a unique --experiment_name or --experiment_dir for each run. "
+ "Does not need --save_model_path to be set. "
+ ),
+ )
+ parser.add_argument(
+ "--onnx_export_path",
+ default=None,
+ type=str,
+ help="If included, will export onnx file after training to the path specified.",
+ )
+ parser.add_argument(
+ "--timesteps",
+ default=1_000_000,
+ type=int,
+ help="The number of environment steps to train for, default is 1_000_000. If resuming from a saved model, "
+ "it will continue training for this amount of steps from the saved state without counting previously trained "
+ "steps",
+ )
+ parser.add_argument(
+ "--inference",
+ default=False,
+ action="store_true",
+ help="Instead of training, it will run inference on a loaded model for --timesteps steps. "
+ "Requires --resume_model_path to be set.",
+ )
+ parser.add_argument(
+ "--linear_lr_schedule",
+ default=False,
+ action="store_true",
+ help="Use a linear LR schedule for training. If set, learning rate will decrease until it reaches 0 at "
+ "--timesteps"
+ "value. Note: On resuming training, the schedule will reset. If disabled, constant LR will be used.",
+ )
+ parser.add_argument(
+ "--viz",
+ action="store_true",
+ help="If set, the simulation will be displayed in a window during training. Otherwise "
+ "training will run without rendering the simulation. This setting does not apply to in-editor training.",
+ default=False,
+ )
+ parser.add_argument(
+ "--speedup",
+ default=1,
+ type=int,
+ help="Whether to speed up the physics in the env"
+ )
+ parser.add_argument(
+ "--n_parallel",
+ default=1,
+ type=int,
+ help="How many instances of the environment executable to " "launch - requires --env_path to be set if > 1.",
+ )
+
+ return parser.parse_known_args()
diff --git a/assets/audio/Fire.wav b/assets/audio/Fire.wav
new file mode 100644
index 0000000..97bb0e4
Binary files /dev/null and b/assets/audio/Fire.wav differ
diff --git a/assets/audio/attack/claw.wav b/assets/audio/attack/claw.wav
new file mode 100644
index 0000000..1a98889
Binary files /dev/null and b/assets/audio/attack/claw.wav differ
diff --git a/assets/audio/attack/fireball.wav b/assets/audio/attack/fireball.wav
new file mode 100644
index 0000000..dc2c852
Binary files /dev/null and b/assets/audio/attack/fireball.wav differ
diff --git a/assets/audio/attack/slash.wav b/assets/audio/attack/slash.wav
new file mode 100644
index 0000000..942aeb0
Binary files /dev/null and b/assets/audio/attack/slash.wav differ
diff --git a/assets/audio/death.wav b/assets/audio/death.wav
new file mode 100644
index 0000000..ef03ab1
Binary files /dev/null and b/assets/audio/death.wav differ
diff --git a/assets/audio/heal.wav b/assets/audio/heal.wav
new file mode 100644
index 0000000..e94bab0
Binary files /dev/null and b/assets/audio/heal.wav differ
diff --git a/assets/audio/hit.wav b/assets/audio/hit.wav
new file mode 100644
index 0000000..435b317
Binary files /dev/null and b/assets/audio/hit.wav differ
diff --git a/assets/audio/main.ogg b/assets/audio/main.ogg
new file mode 100644
index 0000000..da5d252
Binary files /dev/null and b/assets/audio/main.ogg differ
diff --git a/assets/audio/sword.wav b/assets/audio/sword.wav
new file mode 100644
index 0000000..2e962d0
Binary files /dev/null and b/assets/audio/sword.wav differ
diff --git a/assets/graphics/font/joystix.ttf b/assets/graphics/font/joystix.ttf
new file mode 100644
index 0000000..5fd36a5
Binary files /dev/null and b/assets/graphics/font/joystix.ttf differ
diff --git a/assets/graphics/grass/grass_1.png b/assets/graphics/grass/grass_1.png
new file mode 100644
index 0000000..e59c1d4
Binary files /dev/null and b/assets/graphics/grass/grass_1.png differ
diff --git a/assets/graphics/grass/grass_2.png b/assets/graphics/grass/grass_2.png
new file mode 100644
index 0000000..74c656a
Binary files /dev/null and b/assets/graphics/grass/grass_2.png differ
diff --git a/assets/graphics/grass/grass_3.png b/assets/graphics/grass/grass_3.png
new file mode 100644
index 0000000..da65a05
Binary files /dev/null and b/assets/graphics/grass/grass_3.png differ
diff --git a/assets/graphics/monsters/bamboo/attack/0.png b/assets/graphics/monsters/bamboo/attack/0.png
new file mode 100644
index 0000000..c14d75b
Binary files /dev/null and b/assets/graphics/monsters/bamboo/attack/0.png differ
diff --git a/assets/graphics/monsters/bamboo/idle/0.png b/assets/graphics/monsters/bamboo/idle/0.png
new file mode 100644
index 0000000..c14d75b
Binary files /dev/null and b/assets/graphics/monsters/bamboo/idle/0.png differ
diff --git a/assets/graphics/monsters/bamboo/idle/1.png b/assets/graphics/monsters/bamboo/idle/1.png
new file mode 100644
index 0000000..9dd1acc
Binary files /dev/null and b/assets/graphics/monsters/bamboo/idle/1.png differ
diff --git a/assets/graphics/monsters/bamboo/idle/2.png b/assets/graphics/monsters/bamboo/idle/2.png
new file mode 100644
index 0000000..c14d75b
Binary files /dev/null and b/assets/graphics/monsters/bamboo/idle/2.png differ
diff --git a/assets/graphics/monsters/bamboo/idle/3.png b/assets/graphics/monsters/bamboo/idle/3.png
new file mode 100644
index 0000000..6411298
Binary files /dev/null and b/assets/graphics/monsters/bamboo/idle/3.png differ
diff --git a/assets/graphics/monsters/bamboo/move/0.png b/assets/graphics/monsters/bamboo/move/0.png
new file mode 100644
index 0000000..c14d75b
Binary files /dev/null and b/assets/graphics/monsters/bamboo/move/0.png differ
diff --git a/assets/graphics/monsters/bamboo/move/1.png b/assets/graphics/monsters/bamboo/move/1.png
new file mode 100644
index 0000000..9dd1acc
Binary files /dev/null and b/assets/graphics/monsters/bamboo/move/1.png differ
diff --git a/assets/graphics/monsters/bamboo/move/2.png b/assets/graphics/monsters/bamboo/move/2.png
new file mode 100644
index 0000000..c14d75b
Binary files /dev/null and b/assets/graphics/monsters/bamboo/move/2.png differ
diff --git a/assets/graphics/monsters/bamboo/move/3.png b/assets/graphics/monsters/bamboo/move/3.png
new file mode 100644
index 0000000..6411298
Binary files /dev/null and b/assets/graphics/monsters/bamboo/move/3.png differ
diff --git a/assets/graphics/monsters/raccoon/attack/0.png b/assets/graphics/monsters/raccoon/attack/0.png
new file mode 100644
index 0000000..2e53f25
Binary files /dev/null and b/assets/graphics/monsters/raccoon/attack/0.png differ
diff --git a/assets/graphics/monsters/raccoon/attack/1.png b/assets/graphics/monsters/raccoon/attack/1.png
new file mode 100644
index 0000000..21c4d49
Binary files /dev/null and b/assets/graphics/monsters/raccoon/attack/1.png differ
diff --git a/assets/graphics/monsters/raccoon/attack/2.png b/assets/graphics/monsters/raccoon/attack/2.png
new file mode 100644
index 0000000..3319c79
Binary files /dev/null and b/assets/graphics/monsters/raccoon/attack/2.png differ
diff --git a/assets/graphics/monsters/raccoon/attack/3.png b/assets/graphics/monsters/raccoon/attack/3.png
new file mode 100644
index 0000000..aa2d58f
Binary files /dev/null and b/assets/graphics/monsters/raccoon/attack/3.png differ
diff --git a/assets/graphics/monsters/raccoon/idle/0.png b/assets/graphics/monsters/raccoon/idle/0.png
new file mode 100644
index 0000000..cf0fb7f
Binary files /dev/null and b/assets/graphics/monsters/raccoon/idle/0.png differ
diff --git a/assets/graphics/monsters/raccoon/idle/1.png b/assets/graphics/monsters/raccoon/idle/1.png
new file mode 100644
index 0000000..cf0fb7f
Binary files /dev/null and b/assets/graphics/monsters/raccoon/idle/1.png differ
diff --git a/assets/graphics/monsters/raccoon/idle/2.png b/assets/graphics/monsters/raccoon/idle/2.png
new file mode 100644
index 0000000..8d16e08
Binary files /dev/null and b/assets/graphics/monsters/raccoon/idle/2.png differ
diff --git a/assets/graphics/monsters/raccoon/idle/3.png b/assets/graphics/monsters/raccoon/idle/3.png
new file mode 100644
index 0000000..dc57a96
Binary files /dev/null and b/assets/graphics/monsters/raccoon/idle/3.png differ
diff --git a/assets/graphics/monsters/raccoon/idle/4.png b/assets/graphics/monsters/raccoon/idle/4.png
new file mode 100644
index 0000000..fb12e6c
Binary files /dev/null and b/assets/graphics/monsters/raccoon/idle/4.png differ
diff --git a/assets/graphics/monsters/raccoon/idle/5.png b/assets/graphics/monsters/raccoon/idle/5.png
new file mode 100644
index 0000000..c0ede56
Binary files /dev/null and b/assets/graphics/monsters/raccoon/idle/5.png differ
diff --git a/assets/graphics/monsters/raccoon/move/0.png b/assets/graphics/monsters/raccoon/move/0.png
new file mode 100644
index 0000000..a60b9d0
Binary files /dev/null and b/assets/graphics/monsters/raccoon/move/0.png differ
diff --git a/assets/graphics/monsters/raccoon/move/1.png b/assets/graphics/monsters/raccoon/move/1.png
new file mode 100644
index 0000000..34410ca
Binary files /dev/null and b/assets/graphics/monsters/raccoon/move/1.png differ
diff --git a/assets/graphics/monsters/raccoon/move/2.png b/assets/graphics/monsters/raccoon/move/2.png
new file mode 100644
index 0000000..c299286
Binary files /dev/null and b/assets/graphics/monsters/raccoon/move/2.png differ
diff --git a/assets/graphics/monsters/raccoon/move/3.png b/assets/graphics/monsters/raccoon/move/3.png
new file mode 100644
index 0000000..7d9ee77
Binary files /dev/null and b/assets/graphics/monsters/raccoon/move/3.png differ
diff --git a/assets/graphics/monsters/raccoon/move/4.png b/assets/graphics/monsters/raccoon/move/4.png
new file mode 100644
index 0000000..656981c
Binary files /dev/null and b/assets/graphics/monsters/raccoon/move/4.png differ
diff --git a/assets/graphics/monsters/spirit/attack/0.png b/assets/graphics/monsters/spirit/attack/0.png
new file mode 100644
index 0000000..0afa8f1
Binary files /dev/null and b/assets/graphics/monsters/spirit/attack/0.png differ
diff --git a/assets/graphics/monsters/spirit/idle/0.png b/assets/graphics/monsters/spirit/idle/0.png
new file mode 100644
index 0000000..0aee4b5
Binary files /dev/null and b/assets/graphics/monsters/spirit/idle/0.png differ
diff --git a/assets/graphics/monsters/spirit/idle/1.png b/assets/graphics/monsters/spirit/idle/1.png
new file mode 100644
index 0000000..efe735c
Binary files /dev/null and b/assets/graphics/monsters/spirit/idle/1.png differ
diff --git a/assets/graphics/monsters/spirit/idle/2.png b/assets/graphics/monsters/spirit/idle/2.png
new file mode 100644
index 0000000..a46d5e2
Binary files /dev/null and b/assets/graphics/monsters/spirit/idle/2.png differ
diff --git a/assets/graphics/monsters/spirit/idle/3.png b/assets/graphics/monsters/spirit/idle/3.png
new file mode 100644
index 0000000..15e5d4c
Binary files /dev/null and b/assets/graphics/monsters/spirit/idle/3.png differ
diff --git a/assets/graphics/monsters/spirit/move/0.png b/assets/graphics/monsters/spirit/move/0.png
new file mode 100644
index 0000000..0afa8f1
Binary files /dev/null and b/assets/graphics/monsters/spirit/move/0.png differ
diff --git a/assets/graphics/monsters/spirit/move/1.png b/assets/graphics/monsters/spirit/move/1.png
new file mode 100644
index 0000000..bf8f85b
Binary files /dev/null and b/assets/graphics/monsters/spirit/move/1.png differ
diff --git a/assets/graphics/monsters/spirit/move/2.png b/assets/graphics/monsters/spirit/move/2.png
new file mode 100644
index 0000000..809ebc2
Binary files /dev/null and b/assets/graphics/monsters/spirit/move/2.png differ
diff --git a/assets/graphics/monsters/spirit/move/3.png b/assets/graphics/monsters/spirit/move/3.png
new file mode 100644
index 0000000..463875f
Binary files /dev/null and b/assets/graphics/monsters/spirit/move/3.png differ
diff --git a/assets/graphics/monsters/squid/attack/0 - Copy (2).png b/assets/graphics/monsters/squid/attack/0 - Copy (2).png
new file mode 100644
index 0000000..644197e
Binary files /dev/null and b/assets/graphics/monsters/squid/attack/0 - Copy (2).png differ
diff --git a/assets/graphics/monsters/squid/attack/0 - Copy (3).png b/assets/graphics/monsters/squid/attack/0 - Copy (3).png
new file mode 100644
index 0000000..644197e
Binary files /dev/null and b/assets/graphics/monsters/squid/attack/0 - Copy (3).png differ
diff --git a/assets/graphics/monsters/squid/attack/0 - Copy.png b/assets/graphics/monsters/squid/attack/0 - Copy.png
new file mode 100644
index 0000000..644197e
Binary files /dev/null and b/assets/graphics/monsters/squid/attack/0 - Copy.png differ
diff --git a/assets/graphics/monsters/squid/attack/0.png b/assets/graphics/monsters/squid/attack/0.png
new file mode 100644
index 0000000..644197e
Binary files /dev/null and b/assets/graphics/monsters/squid/attack/0.png differ
diff --git a/assets/graphics/monsters/squid/idle/0.png b/assets/graphics/monsters/squid/idle/0.png
new file mode 100644
index 0000000..a9beba8
Binary files /dev/null and b/assets/graphics/monsters/squid/idle/0.png differ
diff --git a/assets/graphics/monsters/squid/idle/1.png b/assets/graphics/monsters/squid/idle/1.png
new file mode 100644
index 0000000..f854919
Binary files /dev/null and b/assets/graphics/monsters/squid/idle/1.png differ
diff --git a/assets/graphics/monsters/squid/idle/2.png b/assets/graphics/monsters/squid/idle/2.png
new file mode 100644
index 0000000..a9beba8
Binary files /dev/null and b/assets/graphics/monsters/squid/idle/2.png differ
diff --git a/assets/graphics/monsters/squid/idle/3.png b/assets/graphics/monsters/squid/idle/3.png
new file mode 100644
index 0000000..9c588e1
Binary files /dev/null and b/assets/graphics/monsters/squid/idle/3.png differ
diff --git a/assets/graphics/monsters/squid/idle/4.png b/assets/graphics/monsters/squid/idle/4.png
new file mode 100644
index 0000000..9c588e1
Binary files /dev/null and b/assets/graphics/monsters/squid/idle/4.png differ
diff --git a/assets/graphics/monsters/squid/move/0.png b/assets/graphics/monsters/squid/move/0.png
new file mode 100644
index 0000000..a9beba8
Binary files /dev/null and b/assets/graphics/monsters/squid/move/0.png differ
diff --git a/assets/graphics/monsters/squid/move/1.png b/assets/graphics/monsters/squid/move/1.png
new file mode 100644
index 0000000..f854919
Binary files /dev/null and b/assets/graphics/monsters/squid/move/1.png differ
diff --git a/assets/graphics/monsters/squid/move/2.png b/assets/graphics/monsters/squid/move/2.png
new file mode 100644
index 0000000..9c588e1
Binary files /dev/null and b/assets/graphics/monsters/squid/move/2.png differ
diff --git a/assets/graphics/monsters/squid/move/3.png b/assets/graphics/monsters/squid/move/3.png
new file mode 100644
index 0000000..9c588e1
Binary files /dev/null and b/assets/graphics/monsters/squid/move/3.png differ
diff --git a/assets/graphics/objects/0.png b/assets/graphics/objects/0.png
new file mode 100644
index 0000000..05fc485
Binary files /dev/null and b/assets/graphics/objects/0.png differ
diff --git a/assets/graphics/objects/01.png b/assets/graphics/objects/01.png
new file mode 100644
index 0000000..3fa3af9
Binary files /dev/null and b/assets/graphics/objects/01.png differ
diff --git a/assets/graphics/objects/02.png b/assets/graphics/objects/02.png
new file mode 100644
index 0000000..c91ceec
Binary files /dev/null and b/assets/graphics/objects/02.png differ
diff --git a/assets/graphics/objects/03.png b/assets/graphics/objects/03.png
new file mode 100644
index 0000000..186ff45
Binary files /dev/null and b/assets/graphics/objects/03.png differ
diff --git a/assets/graphics/objects/04.png b/assets/graphics/objects/04.png
new file mode 100644
index 0000000..f3a3e7a
Binary files /dev/null and b/assets/graphics/objects/04.png differ
diff --git a/assets/graphics/objects/05.png b/assets/graphics/objects/05.png
new file mode 100644
index 0000000..eab8994
Binary files /dev/null and b/assets/graphics/objects/05.png differ
diff --git a/assets/graphics/objects/06.png b/assets/graphics/objects/06.png
new file mode 100644
index 0000000..a7859b7
Binary files /dev/null and b/assets/graphics/objects/06.png differ
diff --git a/assets/graphics/objects/07.png b/assets/graphics/objects/07.png
new file mode 100644
index 0000000..a436b83
Binary files /dev/null and b/assets/graphics/objects/07.png differ
diff --git a/assets/graphics/objects/08.png b/assets/graphics/objects/08.png
new file mode 100644
index 0000000..7fde04e
Binary files /dev/null and b/assets/graphics/objects/08.png differ
diff --git a/assets/graphics/objects/09.png b/assets/graphics/objects/09.png
new file mode 100644
index 0000000..fbd0ebb
Binary files /dev/null and b/assets/graphics/objects/09.png differ
diff --git a/assets/graphics/objects/10.png b/assets/graphics/objects/10.png
new file mode 100644
index 0000000..067a503
Binary files /dev/null and b/assets/graphics/objects/10.png differ
diff --git a/assets/graphics/objects/11.png b/assets/graphics/objects/11.png
new file mode 100644
index 0000000..37edc1e
Binary files /dev/null and b/assets/graphics/objects/11.png differ
diff --git a/assets/graphics/objects/12.png b/assets/graphics/objects/12.png
new file mode 100644
index 0000000..d1967c2
Binary files /dev/null and b/assets/graphics/objects/12.png differ
diff --git a/assets/graphics/objects/13.png b/assets/graphics/objects/13.png
new file mode 100644
index 0000000..f01d839
Binary files /dev/null and b/assets/graphics/objects/13.png differ
diff --git a/assets/graphics/objects/14.png b/assets/graphics/objects/14.png
new file mode 100644
index 0000000..6a7b4bc
Binary files /dev/null and b/assets/graphics/objects/14.png differ
diff --git a/assets/graphics/objects/15.png b/assets/graphics/objects/15.png
new file mode 100644
index 0000000..783c417
Binary files /dev/null and b/assets/graphics/objects/15.png differ
diff --git a/assets/graphics/objects/16.png b/assets/graphics/objects/16.png
new file mode 100644
index 0000000..69b3119
Binary files /dev/null and b/assets/graphics/objects/16.png differ
diff --git a/assets/graphics/objects/17.png b/assets/graphics/objects/17.png
new file mode 100644
index 0000000..23cfa85
Binary files /dev/null and b/assets/graphics/objects/17.png differ
diff --git a/assets/graphics/objects/18.png b/assets/graphics/objects/18.png
new file mode 100644
index 0000000..8497695
Binary files /dev/null and b/assets/graphics/objects/18.png differ
diff --git a/assets/graphics/objects/19.png b/assets/graphics/objects/19.png
new file mode 100644
index 0000000..425d16f
Binary files /dev/null and b/assets/graphics/objects/19.png differ
diff --git a/assets/graphics/objects/20.png b/assets/graphics/objects/20.png
new file mode 100644
index 0000000..7028a89
Binary files /dev/null and b/assets/graphics/objects/20.png differ
diff --git a/assets/graphics/particles/aura/0.png b/assets/graphics/particles/aura/0.png
new file mode 100644
index 0000000..ca3080c
Binary files /dev/null and b/assets/graphics/particles/aura/0.png differ
diff --git a/assets/graphics/particles/aura/1.png b/assets/graphics/particles/aura/1.png
new file mode 100644
index 0000000..587df6e
Binary files /dev/null and b/assets/graphics/particles/aura/1.png differ
diff --git a/assets/graphics/particles/aura/2.png b/assets/graphics/particles/aura/2.png
new file mode 100644
index 0000000..345b25a
Binary files /dev/null and b/assets/graphics/particles/aura/2.png differ
diff --git a/assets/graphics/particles/aura/3.png b/assets/graphics/particles/aura/3.png
new file mode 100644
index 0000000..f5aa4c5
Binary files /dev/null and b/assets/graphics/particles/aura/3.png differ
diff --git a/assets/graphics/particles/bamboo/0.png b/assets/graphics/particles/bamboo/0.png
new file mode 100644
index 0000000..a28b25a
Binary files /dev/null and b/assets/graphics/particles/bamboo/0.png differ
diff --git a/assets/graphics/particles/bamboo/1.png b/assets/graphics/particles/bamboo/1.png
new file mode 100644
index 0000000..234355a
Binary files /dev/null and b/assets/graphics/particles/bamboo/1.png differ
diff --git a/assets/graphics/particles/claw/0.png b/assets/graphics/particles/claw/0.png
new file mode 100644
index 0000000..b9af05a
Binary files /dev/null and b/assets/graphics/particles/claw/0.png differ
diff --git a/assets/graphics/particles/claw/1.png b/assets/graphics/particles/claw/1.png
new file mode 100644
index 0000000..60ab800
Binary files /dev/null and b/assets/graphics/particles/claw/1.png differ
diff --git a/assets/graphics/particles/claw/2.png b/assets/graphics/particles/claw/2.png
new file mode 100644
index 0000000..e3c239b
Binary files /dev/null and b/assets/graphics/particles/claw/2.png differ
diff --git a/assets/graphics/particles/claw/3.png b/assets/graphics/particles/claw/3.png
new file mode 100644
index 0000000..2a579b7
Binary files /dev/null and b/assets/graphics/particles/claw/3.png differ
diff --git a/assets/graphics/particles/flame/fire.png b/assets/graphics/particles/flame/fire.png
new file mode 100644
index 0000000..2fb9ffc
Binary files /dev/null and b/assets/graphics/particles/flame/fire.png differ
diff --git a/assets/graphics/particles/flame/frames/0.png b/assets/graphics/particles/flame/frames/0.png
new file mode 100644
index 0000000..fe33ae5
Binary files /dev/null and b/assets/graphics/particles/flame/frames/0.png differ
diff --git a/assets/graphics/particles/flame/frames/01.png b/assets/graphics/particles/flame/frames/01.png
new file mode 100644
index 0000000..734a74f
Binary files /dev/null and b/assets/graphics/particles/flame/frames/01.png differ
diff --git a/assets/graphics/particles/flame/frames/02.png b/assets/graphics/particles/flame/frames/02.png
new file mode 100644
index 0000000..63536a7
Binary files /dev/null and b/assets/graphics/particles/flame/frames/02.png differ
diff --git a/assets/graphics/particles/flame/frames/03.png b/assets/graphics/particles/flame/frames/03.png
new file mode 100644
index 0000000..49c4995
Binary files /dev/null and b/assets/graphics/particles/flame/frames/03.png differ
diff --git a/assets/graphics/particles/flame/frames/04.png b/assets/graphics/particles/flame/frames/04.png
new file mode 100644
index 0000000..77e0474
Binary files /dev/null and b/assets/graphics/particles/flame/frames/04.png differ
diff --git a/assets/graphics/particles/flame/frames/05.png b/assets/graphics/particles/flame/frames/05.png
new file mode 100644
index 0000000..04691a5
Binary files /dev/null and b/assets/graphics/particles/flame/frames/05.png differ
diff --git a/assets/graphics/particles/flame/frames/06.png b/assets/graphics/particles/flame/frames/06.png
new file mode 100644
index 0000000..4738aa7
Binary files /dev/null and b/assets/graphics/particles/flame/frames/06.png differ
diff --git a/assets/graphics/particles/flame/frames/07.png b/assets/graphics/particles/flame/frames/07.png
new file mode 100644
index 0000000..1faa1d3
Binary files /dev/null and b/assets/graphics/particles/flame/frames/07.png differ
diff --git a/assets/graphics/particles/flame/frames/08.png b/assets/graphics/particles/flame/frames/08.png
new file mode 100644
index 0000000..44b7e28
Binary files /dev/null and b/assets/graphics/particles/flame/frames/08.png differ
diff --git a/assets/graphics/particles/flame/frames/09.png b/assets/graphics/particles/flame/frames/09.png
new file mode 100644
index 0000000..cd35c03
Binary files /dev/null and b/assets/graphics/particles/flame/frames/09.png differ
diff --git a/assets/graphics/particles/flame/frames/10.png b/assets/graphics/particles/flame/frames/10.png
new file mode 100644
index 0000000..7164544
Binary files /dev/null and b/assets/graphics/particles/flame/frames/10.png differ
diff --git a/assets/graphics/particles/flame/frames/11.png b/assets/graphics/particles/flame/frames/11.png
new file mode 100644
index 0000000..5555377
Binary files /dev/null and b/assets/graphics/particles/flame/frames/11.png differ
diff --git a/assets/graphics/particles/heal/frames/0.png b/assets/graphics/particles/heal/frames/0.png
new file mode 100644
index 0000000..cd93684
Binary files /dev/null and b/assets/graphics/particles/heal/frames/0.png differ
diff --git a/assets/graphics/particles/heal/frames/1.png b/assets/graphics/particles/heal/frames/1.png
new file mode 100644
index 0000000..83b4cf1
Binary files /dev/null and b/assets/graphics/particles/heal/frames/1.png differ
diff --git a/assets/graphics/particles/heal/frames/2.png b/assets/graphics/particles/heal/frames/2.png
new file mode 100644
index 0000000..de0b9bd
Binary files /dev/null and b/assets/graphics/particles/heal/frames/2.png differ
diff --git a/assets/graphics/particles/heal/frames/3.png b/assets/graphics/particles/heal/frames/3.png
new file mode 100644
index 0000000..d5ab576
Binary files /dev/null and b/assets/graphics/particles/heal/frames/3.png differ
diff --git a/assets/graphics/particles/heal/frames/4.png b/assets/graphics/particles/heal/frames/4.png
new file mode 100644
index 0000000..e26afd3
Binary files /dev/null and b/assets/graphics/particles/heal/frames/4.png differ
diff --git a/assets/graphics/particles/heal/heal.png b/assets/graphics/particles/heal/heal.png
new file mode 100644
index 0000000..ad7de97
Binary files /dev/null and b/assets/graphics/particles/heal/heal.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00000.png b/assets/graphics/particles/leaf1/leaf1_00000.png
new file mode 100644
index 0000000..b3d34ea
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00000.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00001.png b/assets/graphics/particles/leaf1/leaf1_00001.png
new file mode 100644
index 0000000..22fce58
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00001.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00002.png b/assets/graphics/particles/leaf1/leaf1_00002.png
new file mode 100644
index 0000000..f8d2b65
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00002.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00003.png b/assets/graphics/particles/leaf1/leaf1_00003.png
new file mode 100644
index 0000000..e3e59b6
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00003.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00004.png b/assets/graphics/particles/leaf1/leaf1_00004.png
new file mode 100644
index 0000000..a703f36
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00004.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00005.png b/assets/graphics/particles/leaf1/leaf1_00005.png
new file mode 100644
index 0000000..39e159a
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00005.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00006.png b/assets/graphics/particles/leaf1/leaf1_00006.png
new file mode 100644
index 0000000..a83b3d0
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00006.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00007.png b/assets/graphics/particles/leaf1/leaf1_00007.png
new file mode 100644
index 0000000..ed3fca8
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00007.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00008.png b/assets/graphics/particles/leaf1/leaf1_00008.png
new file mode 100644
index 0000000..f6bf4c9
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00008.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00009.png b/assets/graphics/particles/leaf1/leaf1_00009.png
new file mode 100644
index 0000000..1e27176
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00009.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00010.png b/assets/graphics/particles/leaf1/leaf1_00010.png
new file mode 100644
index 0000000..4be9658
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00010.png differ
diff --git a/assets/graphics/particles/leaf1/leaf1_00011.png b/assets/graphics/particles/leaf1/leaf1_00011.png
new file mode 100644
index 0000000..57f0d06
Binary files /dev/null and b/assets/graphics/particles/leaf1/leaf1_00011.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00000.png b/assets/graphics/particles/leaf2/leaf1_00000.png
new file mode 100644
index 0000000..bd43308
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00000.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00001.png b/assets/graphics/particles/leaf2/leaf1_00001.png
new file mode 100644
index 0000000..3013b91
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00001.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00002.png b/assets/graphics/particles/leaf2/leaf1_00002.png
new file mode 100644
index 0000000..30300af
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00002.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00003.png b/assets/graphics/particles/leaf2/leaf1_00003.png
new file mode 100644
index 0000000..8f0b661
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00003.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00004.png b/assets/graphics/particles/leaf2/leaf1_00004.png
new file mode 100644
index 0000000..8248fba
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00004.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00005.png b/assets/graphics/particles/leaf2/leaf1_00005.png
new file mode 100644
index 0000000..ecf4ffa
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00005.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00006.png b/assets/graphics/particles/leaf2/leaf1_00006.png
new file mode 100644
index 0000000..ece22b8
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00006.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00007.png b/assets/graphics/particles/leaf2/leaf1_00007.png
new file mode 100644
index 0000000..1f1f7ee
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00007.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00008.png b/assets/graphics/particles/leaf2/leaf1_00008.png
new file mode 100644
index 0000000..33f28bd
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00008.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00009.png b/assets/graphics/particles/leaf2/leaf1_00009.png
new file mode 100644
index 0000000..6d6ff48
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00009.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00010.png b/assets/graphics/particles/leaf2/leaf1_00010.png
new file mode 100644
index 0000000..d1a770e
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00010.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00011.png b/assets/graphics/particles/leaf2/leaf1_00011.png
new file mode 100644
index 0000000..0435cea
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00011.png differ
diff --git a/assets/graphics/particles/leaf2/leaf1_00012.png b/assets/graphics/particles/leaf2/leaf1_00012.png
new file mode 100644
index 0000000..3848e8d
Binary files /dev/null and b/assets/graphics/particles/leaf2/leaf1_00012.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00000.png b/assets/graphics/particles/leaf3/leaf1_00000.png
new file mode 100644
index 0000000..c31c69f
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00000.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00001.png b/assets/graphics/particles/leaf3/leaf1_00001.png
new file mode 100644
index 0000000..ad36fe5
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00001.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00002.png b/assets/graphics/particles/leaf3/leaf1_00002.png
new file mode 100644
index 0000000..8338ffd
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00002.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00003.png b/assets/graphics/particles/leaf3/leaf1_00003.png
new file mode 100644
index 0000000..444a0e1
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00003.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00004.png b/assets/graphics/particles/leaf3/leaf1_00004.png
new file mode 100644
index 0000000..4f62188
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00004.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00005.png b/assets/graphics/particles/leaf3/leaf1_00005.png
new file mode 100644
index 0000000..99dc366
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00005.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00006.png b/assets/graphics/particles/leaf3/leaf1_00006.png
new file mode 100644
index 0000000..50c0d9a
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00006.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00007.png b/assets/graphics/particles/leaf3/leaf1_00007.png
new file mode 100644
index 0000000..d7a7a37
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00007.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00008.png b/assets/graphics/particles/leaf3/leaf1_00008.png
new file mode 100644
index 0000000..8df60d4
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00008.png differ
diff --git a/assets/graphics/particles/leaf3/leaf1_00009.png b/assets/graphics/particles/leaf3/leaf1_00009.png
new file mode 100644
index 0000000..d14ee99
Binary files /dev/null and b/assets/graphics/particles/leaf3/leaf1_00009.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00000.png b/assets/graphics/particles/leaf4/leaf1_00000.png
new file mode 100644
index 0000000..a6309fe
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00000.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00001.png b/assets/graphics/particles/leaf4/leaf1_00001.png
new file mode 100644
index 0000000..3d31420
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00001.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00002.png b/assets/graphics/particles/leaf4/leaf1_00002.png
new file mode 100644
index 0000000..cfcc565
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00002.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00003.png b/assets/graphics/particles/leaf4/leaf1_00003.png
new file mode 100644
index 0000000..af077e3
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00003.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00004.png b/assets/graphics/particles/leaf4/leaf1_00004.png
new file mode 100644
index 0000000..7b0be93
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00004.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00005.png b/assets/graphics/particles/leaf4/leaf1_00005.png
new file mode 100644
index 0000000..7b5ac2a
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00005.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00006.png b/assets/graphics/particles/leaf4/leaf1_00006.png
new file mode 100644
index 0000000..8229334
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00006.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00007.png b/assets/graphics/particles/leaf4/leaf1_00007.png
new file mode 100644
index 0000000..1915fab
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00007.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00008.png b/assets/graphics/particles/leaf4/leaf1_00008.png
new file mode 100644
index 0000000..157a04a
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00008.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00009.png b/assets/graphics/particles/leaf4/leaf1_00009.png
new file mode 100644
index 0000000..27fb1fd
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00009.png differ
diff --git a/assets/graphics/particles/leaf4/leaf1_00010.png b/assets/graphics/particles/leaf4/leaf1_00010.png
new file mode 100644
index 0000000..5030b8c
Binary files /dev/null and b/assets/graphics/particles/leaf4/leaf1_00010.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00000.png b/assets/graphics/particles/leaf5/leaf1_00000.png
new file mode 100644
index 0000000..b0e81b0
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00000.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00001.png b/assets/graphics/particles/leaf5/leaf1_00001.png
new file mode 100644
index 0000000..b7828b6
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00001.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00002.png b/assets/graphics/particles/leaf5/leaf1_00002.png
new file mode 100644
index 0000000..ccc2714
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00002.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00003.png b/assets/graphics/particles/leaf5/leaf1_00003.png
new file mode 100644
index 0000000..f1fd9b1
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00003.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00004.png b/assets/graphics/particles/leaf5/leaf1_00004.png
new file mode 100644
index 0000000..de90457
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00004.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00005.png b/assets/graphics/particles/leaf5/leaf1_00005.png
new file mode 100644
index 0000000..661a16a
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00005.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00006.png b/assets/graphics/particles/leaf5/leaf1_00006.png
new file mode 100644
index 0000000..996ed74
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00006.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00007.png b/assets/graphics/particles/leaf5/leaf1_00007.png
new file mode 100644
index 0000000..bc0ab50
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00007.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00008.png b/assets/graphics/particles/leaf5/leaf1_00008.png
new file mode 100644
index 0000000..9de760e
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00008.png differ
diff --git a/assets/graphics/particles/leaf5/leaf1_00009.png b/assets/graphics/particles/leaf5/leaf1_00009.png
new file mode 100644
index 0000000..ec73497
Binary files /dev/null and b/assets/graphics/particles/leaf5/leaf1_00009.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00000.png b/assets/graphics/particles/leaf6/leaf1_00000.png
new file mode 100644
index 0000000..4969977
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00000.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00001.png b/assets/graphics/particles/leaf6/leaf1_00001.png
new file mode 100644
index 0000000..4212765
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00001.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00002.png b/assets/graphics/particles/leaf6/leaf1_00002.png
new file mode 100644
index 0000000..7237076
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00002.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00003.png b/assets/graphics/particles/leaf6/leaf1_00003.png
new file mode 100644
index 0000000..a03d0fe
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00003.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00004.png b/assets/graphics/particles/leaf6/leaf1_00004.png
new file mode 100644
index 0000000..e585fb4
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00004.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00005.png b/assets/graphics/particles/leaf6/leaf1_00005.png
new file mode 100644
index 0000000..13d8d55
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00005.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00006.png b/assets/graphics/particles/leaf6/leaf1_00006.png
new file mode 100644
index 0000000..8b153dc
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00006.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00007.png b/assets/graphics/particles/leaf6/leaf1_00007.png
new file mode 100644
index 0000000..aab3b60
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00007.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00008.png b/assets/graphics/particles/leaf6/leaf1_00008.png
new file mode 100644
index 0000000..9d32aa9
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00008.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00009.png b/assets/graphics/particles/leaf6/leaf1_00009.png
new file mode 100644
index 0000000..1f87666
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00009.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00010.png b/assets/graphics/particles/leaf6/leaf1_00010.png
new file mode 100644
index 0000000..c54c793
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00010.png differ
diff --git a/assets/graphics/particles/leaf6/leaf1_00011.png b/assets/graphics/particles/leaf6/leaf1_00011.png
new file mode 100644
index 0000000..3659600
Binary files /dev/null and b/assets/graphics/particles/leaf6/leaf1_00011.png differ
diff --git a/assets/graphics/particles/leaf_attack/0.png b/assets/graphics/particles/leaf_attack/0.png
new file mode 100644
index 0000000..a9dc64d
Binary files /dev/null and b/assets/graphics/particles/leaf_attack/0.png differ
diff --git a/assets/graphics/particles/leaf_attack/1.png b/assets/graphics/particles/leaf_attack/1.png
new file mode 100644
index 0000000..2cfe1a5
Binary files /dev/null and b/assets/graphics/particles/leaf_attack/1.png differ
diff --git a/assets/graphics/particles/leaf_attack/2.png b/assets/graphics/particles/leaf_attack/2.png
new file mode 100644
index 0000000..19eabbd
Binary files /dev/null and b/assets/graphics/particles/leaf_attack/2.png differ
diff --git a/assets/graphics/particles/leaf_attack/3.png b/assets/graphics/particles/leaf_attack/3.png
new file mode 100644
index 0000000..b7c453f
Binary files /dev/null and b/assets/graphics/particles/leaf_attack/3.png differ
diff --git a/assets/graphics/particles/leaf_attack/4.png b/assets/graphics/particles/leaf_attack/4.png
new file mode 100644
index 0000000..d26d38e
Binary files /dev/null and b/assets/graphics/particles/leaf_attack/4.png differ
diff --git a/assets/graphics/particles/leaf_attack/5.png b/assets/graphics/particles/leaf_attack/5.png
new file mode 100644
index 0000000..73c1f4f
Binary files /dev/null and b/assets/graphics/particles/leaf_attack/5.png differ
diff --git a/assets/graphics/particles/leaf_attack/6.png b/assets/graphics/particles/leaf_attack/6.png
new file mode 100644
index 0000000..d68a09d
Binary files /dev/null and b/assets/graphics/particles/leaf_attack/6.png differ
diff --git a/assets/graphics/particles/nova/0.png b/assets/graphics/particles/nova/0.png
new file mode 100644
index 0000000..fdcc423
Binary files /dev/null and b/assets/graphics/particles/nova/0.png differ
diff --git a/assets/graphics/particles/nova/1.png b/assets/graphics/particles/nova/1.png
new file mode 100644
index 0000000..320b930
Binary files /dev/null and b/assets/graphics/particles/nova/1.png differ
diff --git a/assets/graphics/particles/nova/2.png b/assets/graphics/particles/nova/2.png
new file mode 100644
index 0000000..91766d8
Binary files /dev/null and b/assets/graphics/particles/nova/2.png differ
diff --git a/assets/graphics/particles/nova/3.png b/assets/graphics/particles/nova/3.png
new file mode 100644
index 0000000..98371b1
Binary files /dev/null and b/assets/graphics/particles/nova/3.png differ
diff --git a/assets/graphics/particles/nova/4.png b/assets/graphics/particles/nova/4.png
new file mode 100644
index 0000000..26924ab
Binary files /dev/null and b/assets/graphics/particles/nova/4.png differ
diff --git a/assets/graphics/particles/nova/5.png b/assets/graphics/particles/nova/5.png
new file mode 100644
index 0000000..f6aae60
Binary files /dev/null and b/assets/graphics/particles/nova/5.png differ
diff --git a/assets/graphics/particles/raccoon/0.png b/assets/graphics/particles/raccoon/0.png
new file mode 100644
index 0000000..cc1a9eb
Binary files /dev/null and b/assets/graphics/particles/raccoon/0.png differ
diff --git a/assets/graphics/particles/raccoon/1.png b/assets/graphics/particles/raccoon/1.png
new file mode 100644
index 0000000..7385737
Binary files /dev/null and b/assets/graphics/particles/raccoon/1.png differ
diff --git a/assets/graphics/particles/raccoon/2.png b/assets/graphics/particles/raccoon/2.png
new file mode 100644
index 0000000..8b384be
Binary files /dev/null and b/assets/graphics/particles/raccoon/2.png differ
diff --git a/assets/graphics/particles/raccoon/3.png b/assets/graphics/particles/raccoon/3.png
new file mode 100644
index 0000000..d6feaf3
Binary files /dev/null and b/assets/graphics/particles/raccoon/3.png differ
diff --git a/assets/graphics/particles/raccoon/4.png b/assets/graphics/particles/raccoon/4.png
new file mode 100644
index 0000000..e550c15
Binary files /dev/null and b/assets/graphics/particles/raccoon/4.png differ
diff --git a/assets/graphics/particles/raccoon/5.png b/assets/graphics/particles/raccoon/5.png
new file mode 100644
index 0000000..13797ad
Binary files /dev/null and b/assets/graphics/particles/raccoon/5.png differ
diff --git a/assets/graphics/particles/slash/0.png b/assets/graphics/particles/slash/0.png
new file mode 100644
index 0000000..75b73d5
Binary files /dev/null and b/assets/graphics/particles/slash/0.png differ
diff --git a/assets/graphics/particles/slash/1.png b/assets/graphics/particles/slash/1.png
new file mode 100644
index 0000000..011e4a9
Binary files /dev/null and b/assets/graphics/particles/slash/1.png differ
diff --git a/assets/graphics/particles/slash/2.png b/assets/graphics/particles/slash/2.png
new file mode 100644
index 0000000..922e970
Binary files /dev/null and b/assets/graphics/particles/slash/2.png differ
diff --git a/assets/graphics/particles/slash/3.png b/assets/graphics/particles/slash/3.png
new file mode 100644
index 0000000..58821d9
Binary files /dev/null and b/assets/graphics/particles/slash/3.png differ
diff --git a/assets/graphics/particles/smoke/0.png b/assets/graphics/particles/smoke/0.png
new file mode 100644
index 0000000..73e9a59
Binary files /dev/null and b/assets/graphics/particles/smoke/0.png differ
diff --git a/assets/graphics/particles/smoke/1.png b/assets/graphics/particles/smoke/1.png
new file mode 100644
index 0000000..f21e130
Binary files /dev/null and b/assets/graphics/particles/smoke/1.png differ
diff --git a/assets/graphics/particles/smoke/2.png b/assets/graphics/particles/smoke/2.png
new file mode 100644
index 0000000..8e2ecb9
Binary files /dev/null and b/assets/graphics/particles/smoke/2.png differ
diff --git a/assets/graphics/particles/smoke/3.png b/assets/graphics/particles/smoke/3.png
new file mode 100644
index 0000000..244b1a1
Binary files /dev/null and b/assets/graphics/particles/smoke/3.png differ
diff --git a/assets/graphics/particles/smoke/4.png b/assets/graphics/particles/smoke/4.png
new file mode 100644
index 0000000..e60a29b
Binary files /dev/null and b/assets/graphics/particles/smoke/4.png differ
diff --git a/assets/graphics/particles/smoke/5.png b/assets/graphics/particles/smoke/5.png
new file mode 100644
index 0000000..6475ce3
Binary files /dev/null and b/assets/graphics/particles/smoke/5.png differ
diff --git a/assets/graphics/particles/smoke2/0.png b/assets/graphics/particles/smoke2/0.png
new file mode 100644
index 0000000..c3267c0
Binary files /dev/null and b/assets/graphics/particles/smoke2/0.png differ
diff --git a/assets/graphics/particles/smoke2/1.png b/assets/graphics/particles/smoke2/1.png
new file mode 100644
index 0000000..f392845
Binary files /dev/null and b/assets/graphics/particles/smoke2/1.png differ
diff --git a/assets/graphics/particles/smoke2/2.png b/assets/graphics/particles/smoke2/2.png
new file mode 100644
index 0000000..d611b6f
Binary files /dev/null and b/assets/graphics/particles/smoke2/2.png differ
diff --git a/assets/graphics/particles/smoke2/3.png b/assets/graphics/particles/smoke2/3.png
new file mode 100644
index 0000000..c817380
Binary files /dev/null and b/assets/graphics/particles/smoke2/3.png differ
diff --git a/assets/graphics/particles/smoke2/4.png b/assets/graphics/particles/smoke2/4.png
new file mode 100644
index 0000000..abd4af8
Binary files /dev/null and b/assets/graphics/particles/smoke2/4.png differ
diff --git a/assets/graphics/particles/smoke2/5.png b/assets/graphics/particles/smoke2/5.png
new file mode 100644
index 0000000..c89158a
Binary files /dev/null and b/assets/graphics/particles/smoke2/5.png differ
diff --git a/assets/graphics/particles/smoke_orange/0.png b/assets/graphics/particles/smoke_orange/0.png
new file mode 100644
index 0000000..e4baa13
Binary files /dev/null and b/assets/graphics/particles/smoke_orange/0.png differ
diff --git a/assets/graphics/particles/smoke_orange/1.png b/assets/graphics/particles/smoke_orange/1.png
new file mode 100644
index 0000000..7cce227
Binary files /dev/null and b/assets/graphics/particles/smoke_orange/1.png differ
diff --git a/assets/graphics/particles/smoke_orange/2.png b/assets/graphics/particles/smoke_orange/2.png
new file mode 100644
index 0000000..4425e33
Binary files /dev/null and b/assets/graphics/particles/smoke_orange/2.png differ
diff --git a/assets/graphics/particles/smoke_orange/3.png b/assets/graphics/particles/smoke_orange/3.png
new file mode 100644
index 0000000..a817e8d
Binary files /dev/null and b/assets/graphics/particles/smoke_orange/3.png differ
diff --git a/assets/graphics/particles/smoke_orange/4.png b/assets/graphics/particles/smoke_orange/4.png
new file mode 100644
index 0000000..b6ff7a5
Binary files /dev/null and b/assets/graphics/particles/smoke_orange/4.png differ
diff --git a/assets/graphics/particles/smoke_orange/5.png b/assets/graphics/particles/smoke_orange/5.png
new file mode 100644
index 0000000..3dfab88
Binary files /dev/null and b/assets/graphics/particles/smoke_orange/5.png differ
diff --git a/assets/graphics/particles/sparkle/0.png b/assets/graphics/particles/sparkle/0.png
new file mode 100644
index 0000000..2bc0bf2
Binary files /dev/null and b/assets/graphics/particles/sparkle/0.png differ
diff --git a/assets/graphics/particles/sparkle/1.png b/assets/graphics/particles/sparkle/1.png
new file mode 100644
index 0000000..5b3a810
Binary files /dev/null and b/assets/graphics/particles/sparkle/1.png differ
diff --git a/assets/graphics/particles/sparkle/2.png b/assets/graphics/particles/sparkle/2.png
new file mode 100644
index 0000000..d13930a
Binary files /dev/null and b/assets/graphics/particles/sparkle/2.png differ
diff --git a/assets/graphics/particles/sparkle/3.png b/assets/graphics/particles/sparkle/3.png
new file mode 100644
index 0000000..8384774
Binary files /dev/null and b/assets/graphics/particles/sparkle/3.png differ
diff --git a/assets/graphics/particles/sparkle/4.png b/assets/graphics/particles/sparkle/4.png
new file mode 100644
index 0000000..b07148f
Binary files /dev/null and b/assets/graphics/particles/sparkle/4.png differ
diff --git a/assets/graphics/particles/thunder/0.png b/assets/graphics/particles/thunder/0.png
new file mode 100644
index 0000000..781f52b
Binary files /dev/null and b/assets/graphics/particles/thunder/0.png differ
diff --git a/assets/graphics/particles/thunder/1.png b/assets/graphics/particles/thunder/1.png
new file mode 100644
index 0000000..ac1fa39
Binary files /dev/null and b/assets/graphics/particles/thunder/1.png differ
diff --git a/assets/graphics/particles/thunder/2.png b/assets/graphics/particles/thunder/2.png
new file mode 100644
index 0000000..c4bb34b
Binary files /dev/null and b/assets/graphics/particles/thunder/2.png differ
diff --git a/assets/graphics/particles/thunder/3.png b/assets/graphics/particles/thunder/3.png
new file mode 100644
index 0000000..91c92a3
Binary files /dev/null and b/assets/graphics/particles/thunder/3.png differ
diff --git a/assets/graphics/particles/thunder/4.png b/assets/graphics/particles/thunder/4.png
new file mode 100644
index 0000000..0d51893
Binary files /dev/null and b/assets/graphics/particles/thunder/4.png differ
diff --git a/assets/graphics/particles/thunder/5.png b/assets/graphics/particles/thunder/5.png
new file mode 100644
index 0000000..55d2698
Binary files /dev/null and b/assets/graphics/particles/thunder/5.png differ
diff --git a/assets/graphics/particles/thunder/6.png b/assets/graphics/particles/thunder/6.png
new file mode 100644
index 0000000..4d79092
Binary files /dev/null and b/assets/graphics/particles/thunder/6.png differ
diff --git a/assets/graphics/particles/thunder/7.png b/assets/graphics/particles/thunder/7.png
new file mode 100644
index 0000000..0b8b41c
Binary files /dev/null and b/assets/graphics/particles/thunder/7.png differ
diff --git a/assets/graphics/player/down/down_0.png b/assets/graphics/player/down/down_0.png
new file mode 100644
index 0000000..dbbe852
Binary files /dev/null and b/assets/graphics/player/down/down_0.png differ
diff --git a/assets/graphics/player/down/down_1.png b/assets/graphics/player/down/down_1.png
new file mode 100644
index 0000000..8545561
Binary files /dev/null and b/assets/graphics/player/down/down_1.png differ
diff --git a/assets/graphics/player/down/down_2.png b/assets/graphics/player/down/down_2.png
new file mode 100644
index 0000000..dbbe852
Binary files /dev/null and b/assets/graphics/player/down/down_2.png differ
diff --git a/assets/graphics/player/down/down_3.png b/assets/graphics/player/down/down_3.png
new file mode 100644
index 0000000..eb692a2
Binary files /dev/null and b/assets/graphics/player/down/down_3.png differ
diff --git a/assets/graphics/player/down_attack/attack_down.png b/assets/graphics/player/down_attack/attack_down.png
new file mode 100644
index 0000000..0ecc144
Binary files /dev/null and b/assets/graphics/player/down_attack/attack_down.png differ
diff --git a/assets/graphics/player/down_idle/idle_down.png b/assets/graphics/player/down_idle/idle_down.png
new file mode 100644
index 0000000..dbbe852
Binary files /dev/null and b/assets/graphics/player/down_idle/idle_down.png differ
diff --git a/assets/graphics/player/left/left_0.png b/assets/graphics/player/left/left_0.png
new file mode 100644
index 0000000..dafb10b
Binary files /dev/null and b/assets/graphics/player/left/left_0.png differ
diff --git a/assets/graphics/player/left/left_1.png b/assets/graphics/player/left/left_1.png
new file mode 100644
index 0000000..b84ec9c
Binary files /dev/null and b/assets/graphics/player/left/left_1.png differ
diff --git a/assets/graphics/player/left/left_2.png b/assets/graphics/player/left/left_2.png
new file mode 100644
index 0000000..0e22f2e
Binary files /dev/null and b/assets/graphics/player/left/left_2.png differ
diff --git a/assets/graphics/player/left/left_3.png b/assets/graphics/player/left/left_3.png
new file mode 100644
index 0000000..b771463
Binary files /dev/null and b/assets/graphics/player/left/left_3.png differ
diff --git a/assets/graphics/player/left_attack/attack_left.png b/assets/graphics/player/left_attack/attack_left.png
new file mode 100644
index 0000000..0b6c05a
Binary files /dev/null and b/assets/graphics/player/left_attack/attack_left.png differ
diff --git a/assets/graphics/player/left_idle/idle_left.png b/assets/graphics/player/left_idle/idle_left.png
new file mode 100644
index 0000000..dafb10b
Binary files /dev/null and b/assets/graphics/player/left_idle/idle_left.png differ
diff --git a/assets/graphics/player/right/right_0.png b/assets/graphics/player/right/right_0.png
new file mode 100644
index 0000000..fe82409
Binary files /dev/null and b/assets/graphics/player/right/right_0.png differ
diff --git a/assets/graphics/player/right/right_1.png b/assets/graphics/player/right/right_1.png
new file mode 100644
index 0000000..983fbc9
Binary files /dev/null and b/assets/graphics/player/right/right_1.png differ
diff --git a/assets/graphics/player/right/right_2.png b/assets/graphics/player/right/right_2.png
new file mode 100644
index 0000000..8fcb491
Binary files /dev/null and b/assets/graphics/player/right/right_2.png differ
diff --git a/assets/graphics/player/right/right_3.png b/assets/graphics/player/right/right_3.png
new file mode 100644
index 0000000..0a7a454
Binary files /dev/null and b/assets/graphics/player/right/right_3.png differ
diff --git a/assets/graphics/player/right_attack/attack_right.png b/assets/graphics/player/right_attack/attack_right.png
new file mode 100644
index 0000000..9fa1657
Binary files /dev/null and b/assets/graphics/player/right_attack/attack_right.png differ
diff --git a/assets/graphics/player/right_idle/idle_right.png b/assets/graphics/player/right_idle/idle_right.png
new file mode 100644
index 0000000..fe82409
Binary files /dev/null and b/assets/graphics/player/right_idle/idle_right.png differ
diff --git a/assets/graphics/player/up/up_0.png b/assets/graphics/player/up/up_0.png
new file mode 100644
index 0000000..d0dae1c
Binary files /dev/null and b/assets/graphics/player/up/up_0.png differ
diff --git a/assets/graphics/player/up/up_1.png b/assets/graphics/player/up/up_1.png
new file mode 100644
index 0000000..2b0de88
Binary files /dev/null and b/assets/graphics/player/up/up_1.png differ
diff --git a/assets/graphics/player/up/up_2.png b/assets/graphics/player/up/up_2.png
new file mode 100644
index 0000000..d0dae1c
Binary files /dev/null and b/assets/graphics/player/up/up_2.png differ
diff --git a/assets/graphics/player/up/up_3.png b/assets/graphics/player/up/up_3.png
new file mode 100644
index 0000000..b6ebf56
Binary files /dev/null and b/assets/graphics/player/up/up_3.png differ
diff --git a/assets/graphics/player/up_attack/attack_up.png b/assets/graphics/player/up_attack/attack_up.png
new file mode 100644
index 0000000..d165d7c
Binary files /dev/null and b/assets/graphics/player/up_attack/attack_up.png differ
diff --git a/assets/graphics/player/up_idle/idle_up.png b/assets/graphics/player/up_idle/idle_up.png
new file mode 100644
index 0000000..d0dae1c
Binary files /dev/null and b/assets/graphics/player/up_idle/idle_up.png differ
diff --git a/assets/graphics/test/player.png b/assets/graphics/test/player.png
new file mode 100644
index 0000000..dbbe852
Binary files /dev/null and b/assets/graphics/test/player.png differ
diff --git a/assets/graphics/test/rock.png b/assets/graphics/test/rock.png
new file mode 100644
index 0000000..30a74e5
Binary files /dev/null and b/assets/graphics/test/rock.png differ
diff --git a/assets/graphics/tilemap/Floor.png b/assets/graphics/tilemap/Floor.png
new file mode 100644
index 0000000..2971cdd
Binary files /dev/null and b/assets/graphics/tilemap/Floor.png differ
diff --git a/assets/graphics/tilemap/details.png b/assets/graphics/tilemap/details.png
new file mode 100644
index 0000000..8e43aaa
Binary files /dev/null and b/assets/graphics/tilemap/details.png differ
diff --git a/assets/graphics/tilemap/ground.png b/assets/graphics/tilemap/ground.png
new file mode 100644
index 0000000..548b57f
Binary files /dev/null and b/assets/graphics/tilemap/ground.png differ
diff --git a/assets/graphics/weapons/axe/down.png b/assets/graphics/weapons/axe/down.png
new file mode 100644
index 0000000..66761cd
Binary files /dev/null and b/assets/graphics/weapons/axe/down.png differ
diff --git a/assets/graphics/weapons/axe/full.png b/assets/graphics/weapons/axe/full.png
new file mode 100644
index 0000000..99f0318
Binary files /dev/null and b/assets/graphics/weapons/axe/full.png differ
diff --git a/assets/graphics/weapons/axe/left.png b/assets/graphics/weapons/axe/left.png
new file mode 100644
index 0000000..fbd9b02
Binary files /dev/null and b/assets/graphics/weapons/axe/left.png differ
diff --git a/assets/graphics/weapons/axe/right.png b/assets/graphics/weapons/axe/right.png
new file mode 100644
index 0000000..72c1d42
Binary files /dev/null and b/assets/graphics/weapons/axe/right.png differ
diff --git a/assets/graphics/weapons/axe/up.png b/assets/graphics/weapons/axe/up.png
new file mode 100644
index 0000000..5f49b89
Binary files /dev/null and b/assets/graphics/weapons/axe/up.png differ
diff --git a/assets/graphics/weapons/lance/down.png b/assets/graphics/weapons/lance/down.png
new file mode 100644
index 0000000..f58aeba
Binary files /dev/null and b/assets/graphics/weapons/lance/down.png differ
diff --git a/assets/graphics/weapons/lance/full.png b/assets/graphics/weapons/lance/full.png
new file mode 100644
index 0000000..76ce170
Binary files /dev/null and b/assets/graphics/weapons/lance/full.png differ
diff --git a/assets/graphics/weapons/lance/left.png b/assets/graphics/weapons/lance/left.png
new file mode 100644
index 0000000..b961b43
Binary files /dev/null and b/assets/graphics/weapons/lance/left.png differ
diff --git a/assets/graphics/weapons/lance/right.png b/assets/graphics/weapons/lance/right.png
new file mode 100644
index 0000000..af7fd12
Binary files /dev/null and b/assets/graphics/weapons/lance/right.png differ
diff --git a/assets/graphics/weapons/lance/up.png b/assets/graphics/weapons/lance/up.png
new file mode 100644
index 0000000..96040e5
Binary files /dev/null and b/assets/graphics/weapons/lance/up.png differ
diff --git a/assets/graphics/weapons/rapier/down.png b/assets/graphics/weapons/rapier/down.png
new file mode 100644
index 0000000..dd103a5
Binary files /dev/null and b/assets/graphics/weapons/rapier/down.png differ
diff --git a/assets/graphics/weapons/rapier/full.png b/assets/graphics/weapons/rapier/full.png
new file mode 100644
index 0000000..a5f2835
Binary files /dev/null and b/assets/graphics/weapons/rapier/full.png differ
diff --git a/assets/graphics/weapons/rapier/left.png b/assets/graphics/weapons/rapier/left.png
new file mode 100644
index 0000000..31f5b8b
Binary files /dev/null and b/assets/graphics/weapons/rapier/left.png differ
diff --git a/assets/graphics/weapons/rapier/right.png b/assets/graphics/weapons/rapier/right.png
new file mode 100644
index 0000000..30910a2
Binary files /dev/null and b/assets/graphics/weapons/rapier/right.png differ
diff --git a/assets/graphics/weapons/rapier/up.png b/assets/graphics/weapons/rapier/up.png
new file mode 100644
index 0000000..5839792
Binary files /dev/null and b/assets/graphics/weapons/rapier/up.png differ
diff --git a/assets/graphics/weapons/sai/down.png b/assets/graphics/weapons/sai/down.png
new file mode 100644
index 0000000..bda7e15
Binary files /dev/null and b/assets/graphics/weapons/sai/down.png differ
diff --git a/assets/graphics/weapons/sai/full.png b/assets/graphics/weapons/sai/full.png
new file mode 100644
index 0000000..6f752d6
Binary files /dev/null and b/assets/graphics/weapons/sai/full.png differ
diff --git a/assets/graphics/weapons/sai/left.png b/assets/graphics/weapons/sai/left.png
new file mode 100644
index 0000000..c9847e2
Binary files /dev/null and b/assets/graphics/weapons/sai/left.png differ
diff --git a/assets/graphics/weapons/sai/right.png b/assets/graphics/weapons/sai/right.png
new file mode 100644
index 0000000..0631803
Binary files /dev/null and b/assets/graphics/weapons/sai/right.png differ
diff --git a/assets/graphics/weapons/sai/up.png b/assets/graphics/weapons/sai/up.png
new file mode 100644
index 0000000..366e70b
Binary files /dev/null and b/assets/graphics/weapons/sai/up.png differ
diff --git a/assets/graphics/weapons/sword/down.png b/assets/graphics/weapons/sword/down.png
new file mode 100644
index 0000000..ebcfa93
Binary files /dev/null and b/assets/graphics/weapons/sword/down.png differ
diff --git a/assets/graphics/weapons/sword/full.png b/assets/graphics/weapons/sword/full.png
new file mode 100644
index 0000000..3b395d8
Binary files /dev/null and b/assets/graphics/weapons/sword/full.png differ
diff --git a/assets/graphics/weapons/sword/left.png b/assets/graphics/weapons/sword/left.png
new file mode 100644
index 0000000..34abbfa
Binary files /dev/null and b/assets/graphics/weapons/sword/left.png differ
diff --git a/assets/graphics/weapons/sword/right.png b/assets/graphics/weapons/sword/right.png
new file mode 100644
index 0000000..fd96c2c
Binary files /dev/null and b/assets/graphics/weapons/sword/right.png differ
diff --git a/assets/graphics/weapons/sword/up.png b/assets/graphics/weapons/sword/up.png
new file mode 100644
index 0000000..5cac8d4
Binary files /dev/null and b/assets/graphics/weapons/sword/up.png differ
diff --git a/code/AIController2D.gd b/code/AIController2D.gd
new file mode 100644
index 0000000..efbd446
--- /dev/null
+++ b/code/AIController2D.gd
@@ -0,0 +1,53 @@
+extends AIController2D
+
+# meta-name: AI Controller Logic
+# meta-description: Methods that need implementing for AI controllers
+# meta-default: true
+
+#-- Methods that need implementing using the "extend script" option in Godot --#
+
+@onready var player = $".."
+@onready var bamboos = $"../../../Bamboos"
+@onready var move: int
+
+func get_obs() -> Dictionary:
+ var dict = {"obs":[
+ player.position.x,
+ player.position.y,
+ player.health,
+ player.experience,
+ ]}
+ for bamboo in bamboos.get_children():
+ dict["obs"].append(bamboo.position.x)
+ dict["obs"].append(bamboo.position.y)
+ dict["obs"].append(bamboo.health)
+ dict["obs"].append(bamboo.position.direction_to(player.position).x)
+ dict["obs"].append(bamboo.position.direction_to(player.position).y)
+ return dict
+
+func get_reward() -> float:
+ return reward
+
+func get_action_space() -> Dictionary:
+ return {
+ "move" : {
+ "size": 5,
+ "action_type": "discrete"
+ }
+ }
+
+func set_action(action) -> void:
+ move = action["move"]
+# -----------------------------------------------------------------------------#
+
+#-- Methods that can be overridden if needed --#
+
+#func get_obs_space() -> Dictionary:
+# May need overriding if the obs space is complex
+# var obs = get_obs()
+# return {
+# "obs": {
+# "size": [len(obs["obs"])],
+# "space": "box"
+# },
+# }
diff --git a/code/bamboo.gd b/code/bamboo.gd
new file mode 100644
index 0000000..3c44d52
--- /dev/null
+++ b/code/bamboo.gd
@@ -0,0 +1,98 @@
+extends CharacterBody2D
+
+const SPEED = 150
+const DAMAGE = 7
+const EXP_AMOUNT = 1
+
+@onready var knockback_timer = $KnockbackTimer
+@onready var attack_timer = $AttackTimer
+@onready var notice = $Notice
+@onready var attack = $Attack
+
+@onready var animation_player = $AnimationPlayer
+
+@export var health = 100
+
+var knockback = Vector2.ZERO
+var near_player = false
+var is_attacking = false
+var is_knocked = false
+var is_dead = false
+var can_move = true
+
+signal death
+
+
+func change_hp(dmg):
+ if not is_dead:
+ health += dmg
+ if health <= 0:
+ health = 0
+ for body in attack.get_overlapping_bodies():
+ body.change_hp(DAMAGE)
+ body.add_exp(EXP_AMOUNT)
+ is_dead = true
+ death.emit()
+
+func _on_notice_body_entered(body):
+ near_player = true
+ body.ai_controller.reward += 1
+
+
+func _on_notice_body_exited(body):
+ near_player = false
+
+func _on_attack_body_entered(body):
+ is_attacking = false
+ body.ai_controller.reward += 1
+
+func _on_attack_body_exited(body):
+ is_attacking = true
+
+func _physics_process(delta):
+ if near_player and not is_dead:
+ if not is_knocked:
+ for body in notice.get_overlapping_bodies():
+ if self.to_local(body.global_position).x > 30:
+ velocity.x = SPEED
+ elif self.to_local(body.global_position).x < -30:
+ velocity.x = -SPEED
+ else:
+ velocity.x = move_toward(velocity.x, 0, SPEED)
+
+ if self.to_local(body.global_position).y > 30:
+ velocity.y = SPEED
+ elif self.to_local(body.global_position).y < -30:
+ velocity.y = -SPEED
+ else:
+ velocity.y = move_toward(velocity.y, 0, SPEED)
+
+ if not is_attacking:
+ for enemy in attack.get_overlapping_bodies():
+ enemy.change_hp(-DAMAGE)
+ attack_timer.start()
+ is_attacking = true
+
+
+ else:
+ if can_move:
+ self.velocity = knockback
+ knockback_timer.start()
+ can_move = false
+ else:
+ velocity.x = move_toward(velocity.x, 0, SPEED)
+ velocity.y = move_toward(velocity.y, 0, SPEED)
+
+ move_and_slide()
+
+
+func _on_attack_timer_timeout():
+ is_attacking = false
+
+func _on_knockback_timer_timeout():
+ knockback = Vector2.ZERO
+ is_knocked = false
+ can_move = true
+
+func _on_death():
+ animation_player.play("death")
diff --git a/code/exp.gd b/code/exp.gd
new file mode 100644
index 0000000..2bf741f
--- /dev/null
+++ b/code/exp.gd
@@ -0,0 +1,3 @@
+extends Label
+
+
diff --git a/code/killzone.gd b/code/killzone.gd
new file mode 100644
index 0000000..65bb34d
--- /dev/null
+++ b/code/killzone.gd
@@ -0,0 +1,4 @@
+extends Area2D
+
+func _on_body_entered(body):
+ body.death.emit()
diff --git a/code/main.gd b/code/main.gd
new file mode 100644
index 0000000..8d0814e
--- /dev/null
+++ b/code/main.gd
@@ -0,0 +1,62 @@
+extends Node2D
+
+@onready var main_camera = %Overworld
+@onready var timer = %WorldTimer
+
+@onready var players = $Players
+#TODO: Fix camera
+@onready var player_camera = $Players/Player/Camera
+@onready var bamboos = $Bamboos
+
+@onready var player_starting_pos = []
+@onready var bamboo_starting_pos = []
+
+
+
+# Called when the node enters the scene tree for the first time.
+func _ready():
+ main_camera.make_current()
+ for player in players.get_children():
+ player_starting_pos.append(player.position)
+ for bamboo in bamboos.get_children():
+ bamboo_starting_pos.append(bamboo.position)
+ timer.start()
+
+func _input(event):
+ if event.is_action_pressed("reset_camera"):
+ main_camera.make_current()
+ player_camera.visible = false
+
+func _process(delta):
+ var dead_state = 0
+ var i=0
+
+ for bamboo in bamboos.get_children():
+ if bamboo.is_dead:
+ dead_state += 1
+
+ if dead_state == bamboos.get_children().size():
+ for player in players.get_children():
+ player.change_hp(-1000)
+
+func _on_player_death():
+ var i = 0
+ for player in players.get_children():
+ player.position = player_starting_pos[i]
+ player.health = 100
+ player.ai_controller.done = true
+ player.ai_controller.reset()
+ i += 1
+ var j = 0
+ for bamboo in bamboos.get_children():
+ bamboo.position = bamboo_starting_pos[j]
+ bamboo.health = 40
+ bamboo.is_dead = false
+ bamboo.animation_player.play("RESET")
+ j += 1
+
+func _on_timer_timeout():
+ for player in players.get_children():
+ player.change_hp(-1000)
+ timer.start()
+
diff --git a/code/player.gd b/code/player.gd
new file mode 100644
index 0000000..783ae3a
--- /dev/null
+++ b/code/player.gd
@@ -0,0 +1,190 @@
+extends CharacterBody2D
+
+const SPEED = 300.0
+
+var is_attacking = false
+var last_action = 0
+var cooldown_start = false
+
+var zoomed_in = false
+
+var starting_position = self.position
+
+signal death
+
+@onready var ai_controller = $AIController2D
+
+@onready var animated_sprite = $AnimatedSprite2D
+
+@onready var overworld = %Overworld
+
+@onready var camera = $Camera
+@onready var exp_label = $Camera/ExpPanel/ExpLabel
+@onready var hp_label = $Camera/HPPanel/HPLabel
+
+@onready var attack_timer = $AttackTimer
+@onready var weapon = $Weapon
+@onready var weapon_player = $Weapon/AnimationPlayer
+
+
+@export var health = 100
+@export var experience = 0
+
+
+func _ready():
+ exp_label.text = "Experience\n"+str(experience)
+ hp_label.text = "Health\n"+str(health)
+
+func add_exp(exp_amount):
+ experience += exp_amount
+ ai_controller.reward = experience
+ exp_label.text = "Experience\n"+str(experience)
+
+
+func change_hp(dmg):
+ health += dmg
+ #ai_controller.reward += dmg/10
+ if health <= 0:
+ health = 0
+ add_exp(-1)
+ death.emit()
+ hp_label.text = "Health\n"+str(health)
+
+func move_left():
+ last_action = 1
+ velocity.x = -SPEED
+func move_right():
+ last_action = 3
+ velocity.x = SPEED
+func move_up():
+ last_action = 2
+ velocity.y = -SPEED
+func move_down():
+ last_action = 0
+ velocity.y = SPEED
+
+func _physics_process(_delta):
+ velocity.x = move_toward(velocity.x, 0, SPEED)
+ velocity.y = move_toward(velocity.y, 0, SPEED)
+
+ # Get the input direction and handle the movement/deceleration.
+ if not is_attacking:
+ # Handle and movement
+ ## X Axis
+ if Input.is_action_pressed("move_right") or ai_controller.move == 3:
+ move_right()
+ if Input.is_action_pressed("move_left") or ai_controller.move == 1:
+ move_left()
+
+ ## Y Axis
+ if Input.is_action_pressed("move_up") or ai_controller.move == 2:
+ move_up()
+ if Input.is_action_pressed("move_down") or ai_controller.move == 0:
+ move_down()
+
+ # Handle animations
+ if velocity.x > 0:
+ animated_sprite.play("move_right")
+ elif velocity.x < 0:
+ animated_sprite.play("move_left")
+ elif velocity.y > 0 :
+ animated_sprite.play("move_down")
+ elif velocity.y < 0:
+ animated_sprite.play("move_up")
+
+ # Stop movement or change direction (left/right or up/down)
+ if Input.is_action_just_released("move_right"):
+ if Input.is_action_pressed("move_left"):
+ move_left()
+ else:
+ last_action = 3
+ velocity.x = move_toward(velocity.x, 0, SPEED)
+ animated_sprite.play("idle_right")
+ if Input.is_action_just_released("move_left"):
+ if Input.is_action_pressed("move_right"):
+ move_right()
+ else:
+ last_action = 1
+ velocity.x = move_toward(velocity.x, 0, SPEED)
+ animated_sprite.play("idle_left")
+
+ if Input.is_action_just_released("move_up"):
+ if Input.is_action_pressed("move_down"):
+ move_down()
+ else:
+ last_action = 2
+ velocity.y = move_toward(velocity.y, 0, SPEED)
+ animated_sprite.play("idle_up")
+ if Input.is_action_just_released("move_down"):
+ if Input.is_action_pressed("move_up"):
+ move_up()
+ else:
+ last_action = 0
+ velocity.y = move_toward(velocity.y, 0, SPEED)
+ animated_sprite.play("idle_down")
+
+ # Handle attacking and magic
+ if Input.is_action_just_pressed("attack") or ai_controller.move == 4:
+
+ is_attacking = true
+ if last_action == 1:
+ weapon.position = Vector2i(-54,14)
+ weapon.rotation_degrees = 90*last_action
+ animated_sprite.play("attack_left")
+ weapon_player.play("attack")
+ elif last_action == 2:
+ weapon.position = Vector2i(8,-44)
+ animated_sprite.play("attack_up")
+ weapon.rotation_degrees = 90*last_action
+ weapon_player.play("attack")
+ elif last_action == 3:
+ weapon.rotation_degrees = 90*last_action
+ weapon.position = Vector2i(54,14)
+ animated_sprite.play("attack_right")
+ weapon_player.play("attack")
+ else:
+ weapon.position = Vector2i(-12,52)
+ animated_sprite.play("attack_down")
+ weapon.rotation_degrees = 90*last_action
+ weapon_player.play("attack")
+#
+ ## TODO: Fix magic
+ #elif Input.is_action_just_pressed("cast_magic"):
+ #is_attacking = true
+ #velocity.x = move_toward(velocity.x, 0, SPEED)
+ #velocity.y = move_toward(velocity.y, 0, SPEED)
+ #if last_action == 1:
+ #animated_sprite.play("attack_right")
+ #elif last_action == 2:
+ #animated_sprite.play("attack_left")
+ #elif last_action == 3:
+ #animated_sprite.play("attack_up")
+ #else:
+ #animated_sprite.play("attack_down")
+
+ move_and_slide()
+
+ else:
+ attack_cooldown()
+
+func attack_cooldown():
+ if cooldown_start == false:
+ attack_timer.start()
+ cooldown_start = true
+
+# TODO: Find more elegant way to go back
+func _on_button_pressed():
+ if not zoomed_in:
+ camera.visible = true
+ camera.make_current()
+ zoomed_in = true
+ else:
+ camera.visible = false
+ overworld.make_current()
+ zoomed_in = false
+
+
+func _on_attack_timer_timeout():
+ is_attacking = false
+ cooldown_start = false
+ weapon_player.play("RESET")
diff --git a/code/weapon.gd b/code/weapon.gd
new file mode 100644
index 0000000..7151c3b
--- /dev/null
+++ b/code/weapon.gd
@@ -0,0 +1,12 @@
+extends Area2D
+
+const DAMAGE = 20
+const KNOCKBACK_STR = 120
+
+func _on_body_entered(body):
+ var direction = self.global_position.direction_to(body.global_position)
+ var knockback_force = direction * KNOCKBACK_STR
+ if not body.is_dead:
+ body.change_hp(-DAMAGE)
+ body.knockback = knockback_force
+ body.is_knocked = true
diff --git a/default_bus_layout.tres b/default_bus_layout.tres
new file mode 100644
index 0000000..23bf494
--- /dev/null
+++ b/default_bus_layout.tres
@@ -0,0 +1,9 @@
+[gd_resource type="AudioBusLayout" format=3 uid="uid://crne71jxj5jib"]
+
+[resource]
+bus/1/name = &"SFX"
+bus/1/solo = false
+bus/1/mute = false
+bus/1/bypass_fx = false
+bus/1/volume_db = -5.32994
+bus/1/send = &"Master"
diff --git a/icon.svg b/icon.svg
new file mode 100644
index 0000000..fcfa04a
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1,43 @@
+
+
+
\ No newline at end of file
diff --git a/logs/sb3/policy_big_1/events.out.tfevents.1716226582.valanixos.22227.8 b/logs/sb3/policy_big_1/events.out.tfevents.1716226582.valanixos.22227.8
new file mode 100644
index 0000000..d32669a
Binary files /dev/null and b/logs/sb3/policy_big_1/events.out.tfevents.1716226582.valanixos.22227.8 differ
diff --git a/logs/sb3/policy_big_optim_1/events.out.tfevents.1716291894.valanixos.22227.9 b/logs/sb3/policy_big_optim_1/events.out.tfevents.1716291894.valanixos.22227.9
new file mode 100644
index 0000000..3dfbeac
Binary files /dev/null and b/logs/sb3/policy_big_optim_1/events.out.tfevents.1716291894.valanixos.22227.9 differ
diff --git a/logs/sb3/policy_mid_1/events.out.tfevents.1716201050.valanixos.22227.4 b/logs/sb3/policy_mid_1/events.out.tfevents.1716201050.valanixos.22227.4
new file mode 100644
index 0000000..afaeb24
Binary files /dev/null and b/logs/sb3/policy_mid_1/events.out.tfevents.1716201050.valanixos.22227.4 differ
diff --git a/logs/sb3/policy_mid_optim_1/events.out.tfevents.1716207305.valanixos.22227.5 b/logs/sb3/policy_mid_optim_1/events.out.tfevents.1716207305.valanixos.22227.5
new file mode 100644
index 0000000..c5e528f
Binary files /dev/null and b/logs/sb3/policy_mid_optim_1/events.out.tfevents.1716207305.valanixos.22227.5 differ
diff --git a/logs/sb3/policy_mid_optim_tanh_1/events.out.tfevents.1716220373.valanixos.22227.7 b/logs/sb3/policy_mid_optim_tanh_1/events.out.tfevents.1716220373.valanixos.22227.7
new file mode 100644
index 0000000..fbb210e
Binary files /dev/null and b/logs/sb3/policy_mid_optim_tanh_1/events.out.tfevents.1716220373.valanixos.22227.7 differ
diff --git a/logs/sb3/policy_mid_tanh_1/events.out.tfevents.1716213770.valanixos.22227.6 b/logs/sb3/policy_mid_tanh_1/events.out.tfevents.1716213770.valanixos.22227.6
new file mode 100644
index 0000000..993f5d3
Binary files /dev/null and b/logs/sb3/policy_mid_tanh_1/events.out.tfevents.1716213770.valanixos.22227.6 differ
diff --git a/logs/sb3/policy_small_1/events.out.tfevents.1716193022.valanixos.22227.0 b/logs/sb3/policy_small_1/events.out.tfevents.1716193022.valanixos.22227.0
new file mode 100644
index 0000000..18c4c86
Binary files /dev/null and b/logs/sb3/policy_small_1/events.out.tfevents.1716193022.valanixos.22227.0 differ
diff --git a/logs/sb3/policy_small_optim_1/events.out.tfevents.1716195018.valanixos.22227.1 b/logs/sb3/policy_small_optim_1/events.out.tfevents.1716195018.valanixos.22227.1
new file mode 100644
index 0000000..28a07a4
Binary files /dev/null and b/logs/sb3/policy_small_optim_1/events.out.tfevents.1716195018.valanixos.22227.1 differ
diff --git a/logs/sb3/policy_small_optim_tanh_1/events.out.tfevents.1716199031.valanixos.22227.3 b/logs/sb3/policy_small_optim_tanh_1/events.out.tfevents.1716199031.valanixos.22227.3
new file mode 100644
index 0000000..895f529
Binary files /dev/null and b/logs/sb3/policy_small_optim_tanh_1/events.out.tfevents.1716199031.valanixos.22227.3 differ
diff --git a/logs/sb3/policy_small_tanh_1/events.out.tfevents.1716197041.valanixos.22227.2 b/logs/sb3/policy_small_tanh_1/events.out.tfevents.1716197041.valanixos.22227.2
new file mode 100644
index 0000000..eb2779e
Binary files /dev/null and b/logs/sb3/policy_small_tanh_1/events.out.tfevents.1716197041.valanixos.22227.2 differ
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..ead1e90
--- /dev/null
+++ b/main.py
@@ -0,0 +1,6 @@
+from policy import policies
+from agent import main
+import args
+
+for policy_name, policy in policies.items():
+ main(policy_name=policy_name, policy=policy, parseargs=args.parse_args())
diff --git a/old_logs/basic_sb3/events.out.tfevents.1716039274.valanixos.5296.0 b/old_logs/basic_sb3/events.out.tfevents.1716039274.valanixos.5296.0
new file mode 100644
index 0000000..36f9f80
Binary files /dev/null and b/old_logs/basic_sb3/events.out.tfevents.1716039274.valanixos.5296.0 differ
diff --git a/old_logs/experiment_1/events.out.tfevents.1716072142.valanixos.132214.0 b/old_logs/experiment_1/events.out.tfevents.1716072142.valanixos.132214.0
new file mode 100644
index 0000000..f9ffd02
Binary files /dev/null and b/old_logs/experiment_1/events.out.tfevents.1716072142.valanixos.132214.0 differ
diff --git a/old_logs/experiment_2/events.out.tfevents.1716141463.valanixos.1153942.0 b/old_logs/experiment_2/events.out.tfevents.1716141463.valanixos.1153942.0
new file mode 100644
index 0000000..339b7cc
Binary files /dev/null and b/old_logs/experiment_2/events.out.tfevents.1716141463.valanixos.1153942.0 differ
diff --git a/old_logs/sb3_bigger_net/events.out.tfevents.1716047196.valanixos.40801.0 b/old_logs/sb3_bigger_net/events.out.tfevents.1716047196.valanixos.40801.0
new file mode 100644
index 0000000..54e8f5f
Binary files /dev/null and b/old_logs/sb3_bigger_net/events.out.tfevents.1716047196.valanixos.40801.0 differ
diff --git a/old_logs/sb3_bigger_net_tanh/events.out.tfevents.1716062748.valanixos.97391.0 b/old_logs/sb3_bigger_net_tanh/events.out.tfevents.1716062748.valanixos.97391.0
new file mode 100644
index 0000000..ef34e74
Binary files /dev/null and b/old_logs/sb3_bigger_net_tanh/events.out.tfevents.1716062748.valanixos.97391.0 differ
diff --git a/pneuma.sh b/pneuma.sh
new file mode 100755
index 0000000..f448f3b
--- /dev/null
+++ b/pneuma.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+echo -ne '\033c\033]0;Pneuma\a'
+base_path="$(dirname "$(realpath "$0")")"
+"$base_path/pneuma.x86_64" "$@"
diff --git a/poetry.lock b/poetry.lock
new file mode 100644
index 0000000..cd5ded8
--- /dev/null
+++ b/poetry.lock
@@ -0,0 +1,2207 @@
+# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
+
+[[package]]
+name = "absl-py"
+version = "2.1.0"
+description = "Abseil Python Common Libraries, see https://github.com/abseil/abseil-py."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "absl-py-2.1.0.tar.gz", hash = "sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff"},
+ {file = "absl_py-2.1.0-py3-none-any.whl", hash = "sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308"},
+]
+
+[[package]]
+name = "certifi"
+version = "2024.2.2"
+description = "Python package for providing Mozilla's CA Bundle."
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"},
+ {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"},
+]
+
+[[package]]
+name = "charset-normalizer"
+version = "3.3.2"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
+optional = false
+python-versions = ">=3.7.0"
+files = [
+ {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"},
+ {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"},
+ {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"},
+ {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"},
+ {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"},
+ {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"},
+ {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"},
+ {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
+]
+
+[[package]]
+name = "click"
+version = "8.1.7"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
+ {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "cloudpickle"
+version = "3.0.0"
+description = "Pickler class to extend the standard pickle.Pickler functionality"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "cloudpickle-3.0.0-py3-none-any.whl", hash = "sha256:246ee7d0c295602a036e86369c77fecda4ab17b506496730f2f576d9016fd9c7"},
+ {file = "cloudpickle-3.0.0.tar.gz", hash = "sha256:996d9a482c6fb4f33c1a35335cf8afd065d2a56e973270364840712d9131a882"},
+]
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "coloredlogs"
+version = "15.0.1"
+description = "Colored terminal output for Python's logging module"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"},
+ {file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"},
+]
+
+[package.dependencies]
+humanfriendly = ">=9.1"
+
+[package.extras]
+cron = ["capturer (>=2.4)"]
+
+[[package]]
+name = "contourpy"
+version = "1.2.1"
+description = "Python library for calculating contours of 2D quadrilateral grids"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040"},
+ {file = "contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd"},
+ {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480"},
+ {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9"},
+ {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da"},
+ {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b"},
+ {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd"},
+ {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619"},
+ {file = "contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8"},
+ {file = "contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9"},
+ {file = "contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5"},
+ {file = "contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72"},
+ {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f"},
+ {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965"},
+ {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2"},
+ {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df"},
+ {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205"},
+ {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8"},
+ {file = "contourpy-1.2.1-cp311-cp311-win32.whl", hash = "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec"},
+ {file = "contourpy-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922"},
+ {file = "contourpy-1.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc"},
+ {file = "contourpy-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e"},
+ {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4"},
+ {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7"},
+ {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0"},
+ {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b"},
+ {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce"},
+ {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4"},
+ {file = "contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f"},
+ {file = "contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce"},
+ {file = "contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b"},
+ {file = "contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f"},
+ {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364"},
+ {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe"},
+ {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985"},
+ {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445"},
+ {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02"},
+ {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083"},
+ {file = "contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba"},
+ {file = "contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9"},
+ {file = "contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609"},
+ {file = "contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3"},
+ {file = "contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f"},
+ {file = "contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c"},
+]
+
+[package.dependencies]
+numpy = ">=1.20"
+
+[package.extras]
+bokeh = ["bokeh", "selenium"]
+docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"]
+mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pillow"]
+test = ["Pillow", "contourpy[test-no-images]", "matplotlib"]
+test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"]
+
+[[package]]
+name = "cycler"
+version = "0.12.1"
+description = "Composable style cycles"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"},
+ {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"},
+]
+
+[package.extras]
+docs = ["ipython", "matplotlib", "numpydoc", "sphinx"]
+tests = ["pytest", "pytest-cov", "pytest-xdist"]
+
+[[package]]
+name = "dm-tree"
+version = "0.1.8"
+description = "Tree is a library for working with nested data structures."
+optional = false
+python-versions = "*"
+files = [
+ {file = "dm-tree-0.1.8.tar.gz", hash = "sha256:0fcaabbb14e7980377439e7140bd05552739ca5e515ecb3119f234acee4b9430"},
+ {file = "dm_tree-0.1.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:35cc164a79336bfcfafb47e5f297898359123bbd3330c1967f0c4994f9cf9f60"},
+ {file = "dm_tree-0.1.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39070ba268c0491af9fe7a58644d99e8b4f2cde6e5884ba3380bddc84ed43d5f"},
+ {file = "dm_tree-0.1.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2869228d9c619074de501a3c10dc7f07c75422f8fab36ecdcb859b6f1b1ec3ef"},
+ {file = "dm_tree-0.1.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d20f2faa3672b52e5013f4077117bfb99c4cfc0b445d3bde1584c34032b57436"},
+ {file = "dm_tree-0.1.8-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5483dca4d7eb1a0d65fe86d3b6a53ae717face83c1f17e0887b1a4a64ae5c410"},
+ {file = "dm_tree-0.1.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1d7c26e431fc93cc7e0cba867eb000db6a05f6f2b25af11ac4e9dada88fc5bca"},
+ {file = "dm_tree-0.1.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d714371bb08839e4e5e29024fc95832d9affe129825ef38836b143028bd144"},
+ {file = "dm_tree-0.1.8-cp310-cp310-win_amd64.whl", hash = "sha256:d40fa4106ca6edc66760246a08f500ec0c85ef55c762fb4a363f6ee739ba02ee"},
+ {file = "dm_tree-0.1.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad16ceba90a56ec47cf45b21856d14962ac314787975ef786efb5e6e9ca75ec7"},
+ {file = "dm_tree-0.1.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:803bfc53b4659f447ac694dbd04235f94a73ef7c1fd1e0df7c84ac41e0bc963b"},
+ {file = "dm_tree-0.1.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:378cc8ad93c5fe3590f405a309980721f021c790ca1bdf9b15bb1d59daec57f5"},
+ {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1607ce49aa42f010d1e5e616d92ce899d66835d4d8bea49679582435285515de"},
+ {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:343a4a4ebaa127451ff971254a4be4084eb4bdc0b2513c32b46f6f728fd03f9e"},
+ {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa42a605d099ee7d41ba2b5fb75e21423951fd26e5d50583a00471238fb3021d"},
+ {file = "dm_tree-0.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83b7764de0d855338abefc6e3ee9fe40d301668310aa3baea3f778ff051f4393"},
+ {file = "dm_tree-0.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:a5d819c38c03f0bb5b3b3703c60e4b170355a0fc6b5819325bf3d4ceb3ae7e80"},
+ {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ea9e59e0451e7d29aece402d9f908f2e2a80922bcde2ebfd5dcb07750fcbfee8"},
+ {file = "dm_tree-0.1.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:94d3f0826311f45ee19b75f5b48c99466e4218a0489e81c0f0167bda50cacf22"},
+ {file = "dm_tree-0.1.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:435227cf3c5dc63f4de054cf3d00183790bd9ead4c3623138c74dde7f67f521b"},
+ {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09964470f76a5201aff2e8f9b26842976de7889300676f927930f6285e256760"},
+ {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75c5d528bb992981c20793b6b453e91560784215dffb8a5440ba999753c14ceb"},
+ {file = "dm_tree-0.1.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a94aba18a35457a1b5cd716fd7b46c5dafdc4cf7869b4bae665b91c4682a8e"},
+ {file = "dm_tree-0.1.8-cp312-cp312-win_amd64.whl", hash = "sha256:96a548a406a6fb15fe58f6a30a57ff2f2aafbf25f05afab00c8f5e5977b6c715"},
+ {file = "dm_tree-0.1.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8c60a7eadab64c2278861f56bca320b2720f163dca9d7558103c3b77f2416571"},
+ {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af4b3d372f2477dcd89a6e717e4a575ca35ccc20cc4454a8a4b6f8838a00672d"},
+ {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de287fabc464b8734be251e46e06aa9aa1001f34198da2b6ce07bd197172b9cb"},
+ {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:054b461f8176f4bce7a21f7b1870f873a1ced3bdbe1282c816c550bb43c71fa6"},
+ {file = "dm_tree-0.1.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f7915660f59c09068e428613c480150180df1060561fd0d1470684ae7007bd1"},
+ {file = "dm_tree-0.1.8-cp37-cp37m-win_amd64.whl", hash = "sha256:b9f89a454e98806b44fe9d40ec9eee61f848388f7e79ac2371a55679bd5a3ac6"},
+ {file = "dm_tree-0.1.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0e9620ccf06393eb6b613b5e366469304622d4ea96ae6540b28a33840e6c89cf"},
+ {file = "dm_tree-0.1.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b095ba4f8ca1ba19350fd53cf1f8f3eb0bd406aa28af64a6dfc86707b32a810a"},
+ {file = "dm_tree-0.1.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b9bd9b9ccb59409d33d51d84b7668010c04c2af7d4a371632874c1ca356cff3d"},
+ {file = "dm_tree-0.1.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d3172394079a86c3a759179c65f64c48d1a42b89495fcf38976d11cc3bb952c"},
+ {file = "dm_tree-0.1.8-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1612fcaecd79023dbc6a6ae48d51a80beb5c385d6f3f6d71688e57bc8d07de8"},
+ {file = "dm_tree-0.1.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5c8c12e3fda754ef6af94161bacdaeda816d941995fac415d6855c6c386af68"},
+ {file = "dm_tree-0.1.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:694c3654cfd2a81552c08ec66bb5c4a3d48fa292b9a181880fb081c36c5b9134"},
+ {file = "dm_tree-0.1.8-cp38-cp38-win_amd64.whl", hash = "sha256:bb2d109f42190225112da899b9f3d46d0d5f26aef501c61e43529fe9322530b5"},
+ {file = "dm_tree-0.1.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d16e1f2a073604cfcc09f7131ae8d534674f43c3aef4c25742eae295bc60d04f"},
+ {file = "dm_tree-0.1.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:250b692fb75f45f02e2f58fbef9ab338904ef334b90557565621fa251df267cf"},
+ {file = "dm_tree-0.1.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81fce77f22a302d7a5968aebdf4efafef4def7ce96528719a354e6990dcd49c7"},
+ {file = "dm_tree-0.1.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7ac31b9aecccb2c6e1ab29706f6ded3eba0c2c69c770322c9c685929c3d6afb"},
+ {file = "dm_tree-0.1.8-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fe962015b2fe1282892b28ebe962faed53c7f98d942da9a4625cbf27baef913"},
+ {file = "dm_tree-0.1.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c52cbf4f8b3dbd0beaedf44f69fa85eec5e9dede612e08035e06ada6ec9426"},
+ {file = "dm_tree-0.1.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:181c35521d480d0365f39300542cb6cd7fd2b77351bb43d7acfda15aef63b317"},
+ {file = "dm_tree-0.1.8-cp39-cp39-win_amd64.whl", hash = "sha256:8ed3564abed97c806db122c2d3e1a2b64c74a63debe9903aad795167cc301368"},
+]
+
+[[package]]
+name = "farama-notifications"
+version = "0.0.4"
+description = "Notifications for all Farama Foundation maintained libraries."
+optional = false
+python-versions = "*"
+files = [
+ {file = "Farama-Notifications-0.0.4.tar.gz", hash = "sha256:13fceff2d14314cf80703c8266462ebf3733c7d165336eee998fc58e545efd18"},
+ {file = "Farama_Notifications-0.0.4-py3-none-any.whl", hash = "sha256:14de931035a41961f7c056361dc7f980762a143d05791ef5794a751a2caf05ae"},
+]
+
+[[package]]
+name = "filelock"
+version = "3.14.0"
+description = "A platform independent file lock."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"},
+ {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"},
+]
+
+[package.extras]
+docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
+typing = ["typing-extensions (>=4.8)"]
+
+[[package]]
+name = "flatbuffers"
+version = "24.3.25"
+description = "The FlatBuffers serialization format for Python"
+optional = false
+python-versions = "*"
+files = [
+ {file = "flatbuffers-24.3.25-py2.py3-none-any.whl", hash = "sha256:8dbdec58f935f3765e4f7f3cf635ac3a77f83568138d6a2311f524ec96364812"},
+ {file = "flatbuffers-24.3.25.tar.gz", hash = "sha256:de2ec5b203f21441716617f38443e0a8ebf3d25bf0d9c0bb0ce68fa00ad546a4"},
+]
+
+[[package]]
+name = "fonttools"
+version = "4.51.0"
+description = "Tools to manipulate font files"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:84d7751f4468dd8cdd03ddada18b8b0857a5beec80bce9f435742abc9a851a74"},
+ {file = "fonttools-4.51.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8b4850fa2ef2cfbc1d1f689bc159ef0f45d8d83298c1425838095bf53ef46308"},
+ {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5b48a1121117047d82695d276c2af2ee3a24ffe0f502ed581acc2673ecf1037"},
+ {file = "fonttools-4.51.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716"},
+ {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:96a48e137c36be55e68845fc4284533bda2980f8d6f835e26bca79d7e2006438"},
+ {file = "fonttools-4.51.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:806e7912c32a657fa39d2d6eb1d3012d35f841387c8fc6cf349ed70b7c340039"},
+ {file = "fonttools-4.51.0-cp310-cp310-win32.whl", hash = "sha256:32b17504696f605e9e960647c5f64b35704782a502cc26a37b800b4d69ff3c77"},
+ {file = "fonttools-4.51.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7e91abdfae1b5c9e3a543f48ce96013f9a08c6c9668f1e6be0beabf0a569c1b"},
+ {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a8feca65bab31479d795b0d16c9a9852902e3a3c0630678efb0b2b7941ea9c74"},
+ {file = "fonttools-4.51.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ac27f436e8af7779f0bb4d5425aa3535270494d3bc5459ed27de3f03151e4c2"},
+ {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e19bd9e9964a09cd2433a4b100ca7f34e34731e0758e13ba9a1ed6e5468cc0f"},
+ {file = "fonttools-4.51.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2b92381f37b39ba2fc98c3a45a9d6383bfc9916a87d66ccb6553f7bdd129097"},
+ {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5f6bc991d1610f5c3bbe997b0233cbc234b8e82fa99fc0b2932dc1ca5e5afec0"},
+ {file = "fonttools-4.51.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9696fe9f3f0c32e9a321d5268208a7cc9205a52f99b89479d1b035ed54c923f1"},
+ {file = "fonttools-4.51.0-cp311-cp311-win32.whl", hash = "sha256:3bee3f3bd9fa1d5ee616ccfd13b27ca605c2b4270e45715bd2883e9504735034"},
+ {file = "fonttools-4.51.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f08c901d3866a8905363619e3741c33f0a83a680d92a9f0e575985c2634fcc1"},
+ {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4060acc2bfa2d8e98117828a238889f13b6f69d59f4f2d5857eece5277b829ba"},
+ {file = "fonttools-4.51.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1250e818b5f8a679ad79660855528120a8f0288f8f30ec88b83db51515411fcc"},
+ {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76f1777d8b3386479ffb4a282e74318e730014d86ce60f016908d9801af9ca2a"},
+ {file = "fonttools-4.51.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b5ad456813d93b9c4b7ee55302208db2b45324315129d85275c01f5cb7e61a2"},
+ {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:68b3fb7775a923be73e739f92f7e8a72725fd333eab24834041365d2278c3671"},
+ {file = "fonttools-4.51.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8e2f1a4499e3b5ee82c19b5ee57f0294673125c65b0a1ff3764ea1f9db2f9ef5"},
+ {file = "fonttools-4.51.0-cp312-cp312-win32.whl", hash = "sha256:278e50f6b003c6aed19bae2242b364e575bcb16304b53f2b64f6551b9c000e15"},
+ {file = "fonttools-4.51.0-cp312-cp312-win_amd64.whl", hash = "sha256:b3c61423f22165541b9403ee39874dcae84cd57a9078b82e1dce8cb06b07fa2e"},
+ {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:1621ee57da887c17312acc4b0e7ac30d3a4fb0fec6174b2e3754a74c26bbed1e"},
+ {file = "fonttools-4.51.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e9d9298be7a05bb4801f558522adbe2feea1b0b103d5294ebf24a92dd49b78e5"},
+ {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee1af4be1c5afe4c96ca23badd368d8dc75f611887fb0c0dac9f71ee5d6f110e"},
+ {file = "fonttools-4.51.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c18b49adc721a7d0b8dfe7c3130c89b8704baf599fb396396d07d4aa69b824a1"},
+ {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:de7c29bdbdd35811f14493ffd2534b88f0ce1b9065316433b22d63ca1cd21f14"},
+ {file = "fonttools-4.51.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cadf4e12a608ef1d13e039864f484c8a968840afa0258b0b843a0556497ea9ed"},
+ {file = "fonttools-4.51.0-cp38-cp38-win32.whl", hash = "sha256:aefa011207ed36cd280babfaa8510b8176f1a77261833e895a9d96e57e44802f"},
+ {file = "fonttools-4.51.0-cp38-cp38-win_amd64.whl", hash = "sha256:865a58b6e60b0938874af0968cd0553bcd88e0b2cb6e588727117bd099eef836"},
+ {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:60a3409c9112aec02d5fb546f557bca6efa773dcb32ac147c6baf5f742e6258b"},
+ {file = "fonttools-4.51.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f7e89853d8bea103c8e3514b9f9dc86b5b4120afb4583b57eb10dfa5afbe0936"},
+ {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56fc244f2585d6c00b9bcc59e6593e646cf095a96fe68d62cd4da53dd1287b55"},
+ {file = "fonttools-4.51.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d145976194a5242fdd22df18a1b451481a88071feadf251221af110ca8f00ce"},
+ {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c5b8cab0c137ca229433570151b5c1fc6af212680b58b15abd797dcdd9dd5051"},
+ {file = "fonttools-4.51.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:54dcf21a2f2d06ded676e3c3f9f74b2bafded3a8ff12f0983160b13e9f2fb4a7"},
+ {file = "fonttools-4.51.0-cp39-cp39-win32.whl", hash = "sha256:0118ef998a0699a96c7b28457f15546815015a2710a1b23a7bf6c1be60c01636"},
+ {file = "fonttools-4.51.0-cp39-cp39-win_amd64.whl", hash = "sha256:599bdb75e220241cedc6faebfafedd7670335d2e29620d207dd0378a4e9ccc5a"},
+ {file = "fonttools-4.51.0-py3-none-any.whl", hash = "sha256:15c94eeef6b095831067f72c825eb0e2d48bb4cea0647c1b05c981ecba2bf39f"},
+ {file = "fonttools-4.51.0.tar.gz", hash = "sha256:dc0673361331566d7a663d7ce0f6fdcbfbdc1f59c6e3ed1165ad7202ca183c68"},
+]
+
+[package.extras]
+all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"]
+graphite = ["lz4 (>=1.7.4.2)"]
+interpolatable = ["munkres", "pycairo", "scipy"]
+lxml = ["lxml (>=4.0)"]
+pathops = ["skia-pathops (>=0.5.0)"]
+plot = ["matplotlib"]
+repacker = ["uharfbuzz (>=0.23.0)"]
+symfont = ["sympy"]
+type1 = ["xattr"]
+ufo = ["fs (>=2.2.0,<3)"]
+unicode = ["unicodedata2 (>=15.1.0)"]
+woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
+
+[[package]]
+name = "fsspec"
+version = "2024.3.1"
+description = "File-system specification"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "fsspec-2024.3.1-py3-none-any.whl", hash = "sha256:918d18d41bf73f0e2b261824baeb1b124bcf771767e3a26425cd7dec3332f512"},
+ {file = "fsspec-2024.3.1.tar.gz", hash = "sha256:f39780e282d7d117ffb42bb96992f8a90795e4d0fb0f661a70ca39fe9c43ded9"},
+]
+
+[package.extras]
+abfs = ["adlfs"]
+adl = ["adlfs"]
+arrow = ["pyarrow (>=1)"]
+dask = ["dask", "distributed"]
+devel = ["pytest", "pytest-cov"]
+dropbox = ["dropbox", "dropboxdrivefs", "requests"]
+full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"]
+fuse = ["fusepy"]
+gcs = ["gcsfs"]
+git = ["pygit2"]
+github = ["requests"]
+gs = ["gcsfs"]
+gui = ["panel"]
+hdfs = ["pyarrow (>=1)"]
+http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"]
+libarchive = ["libarchive-c"]
+oci = ["ocifs"]
+s3 = ["s3fs"]
+sftp = ["paramiko"]
+smb = ["smbprotocol"]
+ssh = ["paramiko"]
+tqdm = ["tqdm"]
+
+[[package]]
+name = "godot_rl"
+version = "0.7.0"
+description = "A Deep Reinforcement Learning package for the Godot game engine"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "main.zip", hash = "sha256:06fb53a2d74205f67c3bd46337727f382ceef7781aff37b50d13e685e0e4e6e9"},
+]
+
+[package.dependencies]
+gymnasium = "*"
+huggingface-hub = ">=0.10"
+huggingface-sb3 = "*"
+numpy = "*"
+onnx = "*"
+onnxruntime = "*"
+stable-baselines3 = ">=2.0.0"
+tensorboard = "*"
+wget = "*"
+
+[package.extras]
+cleanrl = ["wandb"]
+dev = ["black", "flake8", "isort", "pytest (>=6.0)", "pytest-xdist", "pyyaml (>=5.3.1)"]
+rllib = ["ray[rllib]"]
+sf = ["sample-factory"]
+test = ["pytest (>=6.0)", "pytest-xdist"]
+
+[package.source]
+type = "url"
+url = "https://github.com/edbeeching/godot_rl_agents/archive/refs/heads/main.zip"
+
+[[package]]
+name = "grpcio"
+version = "1.63.0"
+description = "HTTP/2-based RPC framework"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "grpcio-1.63.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:2e93aca840c29d4ab5db93f94ed0a0ca899e241f2e8aec6334ab3575dc46125c"},
+ {file = "grpcio-1.63.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:91b73d3f1340fefa1e1716c8c1ec9930c676d6b10a3513ab6c26004cb02d8b3f"},
+ {file = "grpcio-1.63.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:b3afbd9d6827fa6f475a4f91db55e441113f6d3eb9b7ebb8fb806e5bb6d6bd0d"},
+ {file = "grpcio-1.63.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f3f6883ce54a7a5f47db43289a0a4c776487912de1a0e2cc83fdaec9685cc9f"},
+ {file = "grpcio-1.63.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf8dae9cc0412cb86c8de5a8f3be395c5119a370f3ce2e69c8b7d46bb9872c8d"},
+ {file = "grpcio-1.63.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:08e1559fd3b3b4468486b26b0af64a3904a8dbc78d8d936af9c1cf9636eb3e8b"},
+ {file = "grpcio-1.63.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5c039ef01516039fa39da8a8a43a95b64e288f79f42a17e6c2904a02a319b357"},
+ {file = "grpcio-1.63.0-cp310-cp310-win32.whl", hash = "sha256:ad2ac8903b2eae071055a927ef74121ed52d69468e91d9bcbd028bd0e554be6d"},
+ {file = "grpcio-1.63.0-cp310-cp310-win_amd64.whl", hash = "sha256:b2e44f59316716532a993ca2966636df6fbe7be4ab6f099de6815570ebe4383a"},
+ {file = "grpcio-1.63.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:f28f8b2db7b86c77916829d64ab21ff49a9d8289ea1564a2b2a3a8ed9ffcccd3"},
+ {file = "grpcio-1.63.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:65bf975639a1f93bee63ca60d2e4951f1b543f498d581869922910a476ead2f5"},
+ {file = "grpcio-1.63.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:b5194775fec7dc3dbd6a935102bb156cd2c35efe1685b0a46c67b927c74f0cfb"},
+ {file = "grpcio-1.63.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e4cbb2100ee46d024c45920d16e888ee5d3cf47c66e316210bc236d5bebc42b3"},
+ {file = "grpcio-1.63.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ff737cf29b5b801619f10e59b581869e32f400159e8b12d7a97e7e3bdeee6a2"},
+ {file = "grpcio-1.63.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:cd1e68776262dd44dedd7381b1a0ad09d9930ffb405f737d64f505eb7f77d6c7"},
+ {file = "grpcio-1.63.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:93f45f27f516548e23e4ec3fbab21b060416007dbe768a111fc4611464cc773f"},
+ {file = "grpcio-1.63.0-cp311-cp311-win32.whl", hash = "sha256:878b1d88d0137df60e6b09b74cdb73db123f9579232c8456f53e9abc4f62eb3c"},
+ {file = "grpcio-1.63.0-cp311-cp311-win_amd64.whl", hash = "sha256:756fed02dacd24e8f488f295a913f250b56b98fb793f41d5b2de6c44fb762434"},
+ {file = "grpcio-1.63.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:93a46794cc96c3a674cdfb59ef9ce84d46185fe9421baf2268ccb556f8f81f57"},
+ {file = "grpcio-1.63.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a7b19dfc74d0be7032ca1eda0ed545e582ee46cd65c162f9e9fc6b26ef827dc6"},
+ {file = "grpcio-1.63.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:8064d986d3a64ba21e498b9a376cbc5d6ab2e8ab0e288d39f266f0fca169b90d"},
+ {file = "grpcio-1.63.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:219bb1848cd2c90348c79ed0a6b0ea51866bc7e72fa6e205e459fedab5770172"},
+ {file = "grpcio-1.63.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2d60cd1d58817bc5985fae6168d8b5655c4981d448d0f5b6194bbcc038090d2"},
+ {file = "grpcio-1.63.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9e350cb096e5c67832e9b6e018cf8a0d2a53b2a958f6251615173165269a91b0"},
+ {file = "grpcio-1.63.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:56cdf96ff82e3cc90dbe8bac260352993f23e8e256e063c327b6cf9c88daf7a9"},
+ {file = "grpcio-1.63.0-cp312-cp312-win32.whl", hash = "sha256:3a6d1f9ea965e750db7b4ee6f9fdef5fdf135abe8a249e75d84b0a3e0c668a1b"},
+ {file = "grpcio-1.63.0-cp312-cp312-win_amd64.whl", hash = "sha256:d2497769895bb03efe3187fb1888fc20e98a5f18b3d14b606167dacda5789434"},
+ {file = "grpcio-1.63.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:fdf348ae69c6ff484402cfdb14e18c1b0054ac2420079d575c53a60b9b2853ae"},
+ {file = "grpcio-1.63.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a3abfe0b0f6798dedd2e9e92e881d9acd0fdb62ae27dcbbfa7654a57e24060c0"},
+ {file = "grpcio-1.63.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:6ef0ad92873672a2a3767cb827b64741c363ebaa27e7f21659e4e31f4d750280"},
+ {file = "grpcio-1.63.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b416252ac5588d9dfb8a30a191451adbf534e9ce5f56bb02cd193f12d8845b7f"},
+ {file = "grpcio-1.63.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b77eaefc74d7eb861d3ffbdf91b50a1bb1639514ebe764c47773b833fa2d91"},
+ {file = "grpcio-1.63.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b005292369d9c1f80bf70c1db1c17c6c342da7576f1c689e8eee4fb0c256af85"},
+ {file = "grpcio-1.63.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cdcda1156dcc41e042d1e899ba1f5c2e9f3cd7625b3d6ebfa619806a4c1aadda"},
+ {file = "grpcio-1.63.0-cp38-cp38-win32.whl", hash = "sha256:01799e8649f9e94ba7db1aeb3452188048b0019dc37696b0f5ce212c87c560c3"},
+ {file = "grpcio-1.63.0-cp38-cp38-win_amd64.whl", hash = "sha256:6a1a3642d76f887aa4009d92f71eb37809abceb3b7b5a1eec9c554a246f20e3a"},
+ {file = "grpcio-1.63.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:75f701ff645858a2b16bc8c9fc68af215a8bb2d5a9b647448129de6e85d52bce"},
+ {file = "grpcio-1.63.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cacdef0348a08e475a721967f48206a2254a1b26ee7637638d9e081761a5ba86"},
+ {file = "grpcio-1.63.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:0697563d1d84d6985e40ec5ec596ff41b52abb3fd91ec240e8cb44a63b895094"},
+ {file = "grpcio-1.63.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6426e1fb92d006e47476d42b8f240c1d916a6d4423c5258ccc5b105e43438f61"},
+ {file = "grpcio-1.63.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48cee31bc5f5a31fb2f3b573764bd563aaa5472342860edcc7039525b53e46a"},
+ {file = "grpcio-1.63.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:50344663068041b34a992c19c600236e7abb42d6ec32567916b87b4c8b8833b3"},
+ {file = "grpcio-1.63.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:259e11932230d70ef24a21b9fb5bb947eb4703f57865a404054400ee92f42f5d"},
+ {file = "grpcio-1.63.0-cp39-cp39-win32.whl", hash = "sha256:a44624aad77bf8ca198c55af811fd28f2b3eaf0a50ec5b57b06c034416ef2d0a"},
+ {file = "grpcio-1.63.0-cp39-cp39-win_amd64.whl", hash = "sha256:166e5c460e5d7d4656ff9e63b13e1f6029b122104c1633d5f37eaea348d7356d"},
+ {file = "grpcio-1.63.0.tar.gz", hash = "sha256:f3023e14805c61bc439fb40ca545ac3d5740ce66120a678a3c6c2c55b70343d1"},
+]
+
+[package.extras]
+protobuf = ["grpcio-tools (>=1.63.0)"]
+
+[[package]]
+name = "gymnasium"
+version = "0.28.1"
+description = "A standard API for reinforcement learning and a diverse set of reference environments (formerly Gym)."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "gymnasium-0.28.1-py3-none-any.whl", hash = "sha256:7bc9a5bce1022f997d1dbc152fc91d1ac977bad9cc7794cdc25437010867cabf"},
+ {file = "gymnasium-0.28.1.tar.gz", hash = "sha256:4c2c745808792c8f45c6e88ad0a5504774394e0c126f6e3db555e720d3da6f24"},
+]
+
+[package.dependencies]
+cloudpickle = ">=1.2.0"
+farama-notifications = ">=0.0.1"
+jax-jumpy = ">=1.0.0"
+numpy = ">=1.21.0"
+typing-extensions = ">=4.3.0"
+
+[package.extras]
+accept-rom-license = ["autorom[accept-rom-license] (>=0.4.2,<0.5.0)"]
+all = ["box2d-py (==2.3.5)", "imageio (>=2.14.1)", "jax (==0.3.24)", "jaxlib (==0.3.24)", "lz4 (>=3.1.0)", "matplotlib (>=3.0)", "moviepy (>=1.0.0)", "mujoco (>=2.3.2)", "mujoco-py (>=2.1,<2.2)", "opencv-python (>=3.0)", "pygame (==2.1.3)", "shimmy[atari] (>=0.1.0,<1.0)", "swig (==4.*)", "torch (>=1.0.0)"]
+atari = ["shimmy[atari] (>=0.1.0,<1.0)"]
+box2d = ["box2d-py (==2.3.5)", "pygame (==2.1.3)", "swig (==4.*)"]
+classic-control = ["pygame (==2.1.3)", "pygame (==2.1.3)"]
+jax = ["jax (==0.3.24)", "jaxlib (==0.3.24)"]
+mujoco = ["imageio (>=2.14.1)", "mujoco (>=2.3.2)"]
+mujoco-py = ["mujoco-py (>=2.1,<2.2)", "mujoco-py (>=2.1,<2.2)"]
+other = ["lz4 (>=3.1.0)", "matplotlib (>=3.0)", "moviepy (>=1.0.0)", "opencv-python (>=3.0)", "torch (>=1.0.0)"]
+testing = ["pytest (==7.1.3)", "scipy (==1.7.3)"]
+toy-text = ["pygame (==2.1.3)", "pygame (==2.1.3)"]
+
+[[package]]
+name = "huggingface-hub"
+version = "0.23.0"
+description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "huggingface_hub-0.23.0-py3-none-any.whl", hash = "sha256:075c30d48ee7db2bba779190dc526d2c11d422aed6f9044c5e2fdc2c432fdb91"},
+ {file = "huggingface_hub-0.23.0.tar.gz", hash = "sha256:7126dedd10a4c6fac796ced4d87a8cf004efc722a5125c2c09299017fa366fa9"},
+]
+
+[package.dependencies]
+filelock = "*"
+fsspec = ">=2023.5.0"
+packaging = ">=20.9"
+pyyaml = ">=5.1"
+requests = "*"
+tqdm = ">=4.42.1"
+typing-extensions = ">=3.7.4.3"
+
+[package.extras]
+all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
+cli = ["InquirerPy (==0.3.4)"]
+dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "mypy (==1.5.1)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.3.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
+fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"]
+hf-transfer = ["hf-transfer (>=0.1.4)"]
+inference = ["aiohttp", "minijinja (>=1.0)"]
+quality = ["mypy (==1.5.1)", "ruff (>=0.3.0)"]
+tensorflow = ["graphviz", "pydot", "tensorflow"]
+tensorflow-testing = ["keras (<3.0)", "tensorflow"]
+testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "fastapi", "gradio", "jedi", "minijinja (>=1.0)", "numpy", "pytest", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"]
+torch = ["safetensors", "torch"]
+typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"]
+
+[[package]]
+name = "huggingface-sb3"
+version = "3.0"
+description = "Additional code for Stable-baselines3 to load and upload models from the Hub."
+optional = false
+python-versions = "*"
+files = [
+ {file = "huggingface_sb3-3.0-py3-none-any.whl", hash = "sha256:f543f1e5d840425044b9f83cd6915da77cc308c1a7dd4585208f17efad1e8321"},
+ {file = "huggingface_sb3-3.0.tar.gz", hash = "sha256:abaf901808dc5827976e3029646e463da65536068d910cd8ef4a8e985087d515"},
+]
+
+[package.dependencies]
+cloudpickle = ">=1.6"
+huggingface-hub = ">=0.8,<1.0"
+numpy = "*"
+pyyaml = ">=6.0,<7.0"
+wasabi = "*"
+
+[package.extras]
+quality = ["black (>=22.0,<23.0)", "flake8 (>=3.8.3)", "isort (>=5.5.4)"]
+
+[[package]]
+name = "humanfriendly"
+version = "10.0"
+description = "Human friendly output for text interfaces using Python"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+files = [
+ {file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
+ {file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
+]
+
+[package.dependencies]
+pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""}
+
+[[package]]
+name = "idna"
+version = "3.7"
+description = "Internationalized Domain Names in Applications (IDNA)"
+optional = false
+python-versions = ">=3.5"
+files = [
+ {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
+ {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
+]
+
+[[package]]
+name = "imageio"
+version = "2.34.1"
+description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "imageio-2.34.1-py3-none-any.whl", hash = "sha256:408c1d4d62f72c9e8347e7d1ca9bc11d8673328af3913868db3b828e28b40a4c"},
+ {file = "imageio-2.34.1.tar.gz", hash = "sha256:f13eb76e4922f936ac4a7fec77ce8a783e63b93543d4ea3e40793a6cabd9ac7d"},
+]
+
+[package.dependencies]
+numpy = "*"
+pillow = ">=8.3.2"
+
+[package.extras]
+all-plugins = ["astropy", "av", "imageio-ffmpeg", "pillow-heif", "psutil", "tifffile"]
+all-plugins-pypy = ["av", "imageio-ffmpeg", "pillow-heif", "psutil", "tifffile"]
+build = ["wheel"]
+dev = ["black", "flake8", "fsspec[github]", "pytest", "pytest-cov"]
+docs = ["numpydoc", "pydata-sphinx-theme", "sphinx (<6)"]
+ffmpeg = ["imageio-ffmpeg", "psutil"]
+fits = ["astropy"]
+full = ["astropy", "av", "black", "flake8", "fsspec[github]", "gdal", "imageio-ffmpeg", "itk", "numpydoc", "pillow-heif", "psutil", "pydata-sphinx-theme", "pytest", "pytest-cov", "sphinx (<6)", "tifffile", "wheel"]
+gdal = ["gdal"]
+itk = ["itk"]
+linting = ["black", "flake8"]
+pillow-heif = ["pillow-heif"]
+pyav = ["av"]
+test = ["fsspec[github]", "pytest", "pytest-cov"]
+tifffile = ["tifffile"]
+
+[[package]]
+name = "intel-openmp"
+version = "2021.4.0"
+description = "Intel OpenMP* Runtime Library"
+optional = false
+python-versions = "*"
+files = [
+ {file = "intel_openmp-2021.4.0-py2.py3-none-macosx_10_15_x86_64.macosx_11_0_x86_64.whl", hash = "sha256:41c01e266a7fdb631a7609191709322da2bbf24b252ba763f125dd651bcc7675"},
+ {file = "intel_openmp-2021.4.0-py2.py3-none-manylinux1_i686.whl", hash = "sha256:3b921236a38384e2016f0f3d65af6732cf2c12918087128a9163225451e776f2"},
+ {file = "intel_openmp-2021.4.0-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:e2240ab8d01472fed04f3544a878cda5da16c26232b7ea1b59132dbfb48b186e"},
+ {file = "intel_openmp-2021.4.0-py2.py3-none-win32.whl", hash = "sha256:6e863d8fd3d7e8ef389d52cf97a50fe2afe1a19247e8c0d168ce021546f96fc9"},
+ {file = "intel_openmp-2021.4.0-py2.py3-none-win_amd64.whl", hash = "sha256:eef4c8bcc8acefd7f5cd3b9384dbf73d59e2c99fc56545712ded913f43c4a94f"},
+]
+
+[[package]]
+name = "jax-jumpy"
+version = "1.0.0"
+description = "Common backend for Jax or Numpy."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "jax-jumpy-1.0.0.tar.gz", hash = "sha256:195fb955cc4c2b7f0b1453e3cb1fb1c414a51a407ffac7a51e69a73cb30d59ad"},
+ {file = "jax_jumpy-1.0.0-py3-none-any.whl", hash = "sha256:ab7e01454bba462de3c4d098e3e585c302a8f06bc36d9182ab4e7e4aa7067c5e"},
+]
+
+[package.dependencies]
+numpy = ">=1.18.0"
+
+[package.extras]
+jax = ["jax (>=0.3.24)", "jaxlib (>=0.3.24)"]
+testing = ["pytest (==7.1.3)"]
+
+[[package]]
+name = "jinja2"
+version = "3.1.4"
+description = "A very fast and expressive template engine."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
+ {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=2.0"
+
+[package.extras]
+i18n = ["Babel (>=2.7)"]
+
+[[package]]
+name = "kiwisolver"
+version = "1.4.5"
+description = "A fast implementation of the Cassowary constraint solver"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"},
+ {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"},
+ {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"},
+ {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"},
+ {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"},
+ {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"},
+ {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"},
+ {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"},
+ {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"},
+ {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"},
+ {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"},
+]
+
+[[package]]
+name = "lazy-loader"
+version = "0.4"
+description = "Makes it easy to load subpackages and functions on demand."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "lazy_loader-0.4-py3-none-any.whl", hash = "sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc"},
+ {file = "lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1"},
+]
+
+[package.dependencies]
+packaging = "*"
+
+[package.extras]
+dev = ["changelist (==0.5)"]
+lint = ["pre-commit (==3.7.0)"]
+test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
+
+[[package]]
+name = "lz4"
+version = "4.3.3"
+description = "LZ4 Bindings for Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "lz4-4.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b891880c187e96339474af2a3b2bfb11a8e4732ff5034be919aa9029484cd201"},
+ {file = "lz4-4.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:222a7e35137d7539c9c33bb53fcbb26510c5748779364014235afc62b0ec797f"},
+ {file = "lz4-4.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f76176492ff082657ada0d0f10c794b6da5800249ef1692b35cf49b1e93e8ef7"},
+ {file = "lz4-4.3.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d18718f9d78182c6b60f568c9a9cec8a7204d7cb6fad4e511a2ef279e4cb05"},
+ {file = "lz4-4.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cdc60e21ec70266947a48839b437d46025076eb4b12c76bd47f8e5eb8a75dcc"},
+ {file = "lz4-4.3.3-cp310-cp310-win32.whl", hash = "sha256:c81703b12475da73a5d66618856d04b1307e43428a7e59d98cfe5a5d608a74c6"},
+ {file = "lz4-4.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:43cf03059c0f941b772c8aeb42a0813d68d7081c009542301637e5782f8a33e2"},
+ {file = "lz4-4.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:30e8c20b8857adef7be045c65f47ab1e2c4fabba86a9fa9a997d7674a31ea6b6"},
+ {file = "lz4-4.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2f7b1839f795315e480fb87d9bc60b186a98e3e5d17203c6e757611ef7dcef61"},
+ {file = "lz4-4.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edfd858985c23523f4e5a7526ca6ee65ff930207a7ec8a8f57a01eae506aaee7"},
+ {file = "lz4-4.3.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e9c410b11a31dbdc94c05ac3c480cb4b222460faf9231f12538d0074e56c563"},
+ {file = "lz4-4.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d2507ee9c99dbddd191c86f0e0c8b724c76d26b0602db9ea23232304382e1f21"},
+ {file = "lz4-4.3.3-cp311-cp311-win32.whl", hash = "sha256:f180904f33bdd1e92967923a43c22899e303906d19b2cf8bb547db6653ea6e7d"},
+ {file = "lz4-4.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:b14d948e6dce389f9a7afc666d60dd1e35fa2138a8ec5306d30cd2e30d36b40c"},
+ {file = "lz4-4.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e36cd7b9d4d920d3bfc2369840da506fa68258f7bb176b8743189793c055e43d"},
+ {file = "lz4-4.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:31ea4be9d0059c00b2572d700bf2c1bc82f241f2c3282034a759c9a4d6ca4dc2"},
+ {file = "lz4-4.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33c9a6fd20767ccaf70649982f8f3eeb0884035c150c0b818ea660152cf3c809"},
+ {file = "lz4-4.3.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca8fccc15e3add173da91be8f34121578dc777711ffd98d399be35487c934bf"},
+ {file = "lz4-4.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d84b479ddf39fe3ea05387f10b779155fc0990125f4fb35d636114e1c63a2e"},
+ {file = "lz4-4.3.3-cp312-cp312-win32.whl", hash = "sha256:337cb94488a1b060ef1685187d6ad4ba8bc61d26d631d7ba909ee984ea736be1"},
+ {file = "lz4-4.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:5d35533bf2cee56f38ced91f766cd0038b6abf46f438a80d50c52750088be93f"},
+ {file = "lz4-4.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:363ab65bf31338eb364062a15f302fc0fab0a49426051429866d71c793c23394"},
+ {file = "lz4-4.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a136e44a16fc98b1abc404fbabf7f1fada2bdab6a7e970974fb81cf55b636d0"},
+ {file = "lz4-4.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abc197e4aca8b63f5ae200af03eb95fb4b5055a8f990079b5bdf042f568469dd"},
+ {file = "lz4-4.3.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56f4fe9c6327adb97406f27a66420b22ce02d71a5c365c48d6b656b4aaeb7775"},
+ {file = "lz4-4.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f0e822cd7644995d9ba248cb4b67859701748a93e2ab7fc9bc18c599a52e4604"},
+ {file = "lz4-4.3.3-cp38-cp38-win32.whl", hash = "sha256:24b3206de56b7a537eda3a8123c644a2b7bf111f0af53bc14bed90ce5562d1aa"},
+ {file = "lz4-4.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:b47839b53956e2737229d70714f1d75f33e8ac26e52c267f0197b3189ca6de24"},
+ {file = "lz4-4.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6756212507405f270b66b3ff7f564618de0606395c0fe10a7ae2ffcbbe0b1fba"},
+ {file = "lz4-4.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee9ff50557a942d187ec85462bb0960207e7ec5b19b3b48949263993771c6205"},
+ {file = "lz4-4.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b901c7784caac9a1ded4555258207d9e9697e746cc8532129f150ffe1f6ba0d"},
+ {file = "lz4-4.3.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6d9ec061b9eca86e4dcc003d93334b95d53909afd5a32c6e4f222157b50c071"},
+ {file = "lz4-4.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4c7bf687303ca47d69f9f0133274958fd672efaa33fb5bcde467862d6c621f0"},
+ {file = "lz4-4.3.3-cp39-cp39-win32.whl", hash = "sha256:054b4631a355606e99a42396f5db4d22046a3397ffc3269a348ec41eaebd69d2"},
+ {file = "lz4-4.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:eac9af361e0d98335a02ff12fb56caeb7ea1196cf1a49dbf6f17828a131da807"},
+ {file = "lz4-4.3.3.tar.gz", hash = "sha256:01fe674ef2889dbb9899d8a67361e0c4a2c833af5aeb37dd505727cf5d2a131e"},
+]
+
+[package.extras]
+docs = ["sphinx (>=1.6.0)", "sphinx-bootstrap-theme"]
+flake8 = ["flake8"]
+tests = ["psutil", "pytest (!=3.3.0)", "pytest-cov"]
+
+[[package]]
+name = "markdown"
+version = "3.6"
+description = "Python implementation of John Gruber's Markdown."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"},
+ {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"},
+]
+
+[package.extras]
+docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"]
+testing = ["coverage", "pyyaml"]
+
+[[package]]
+name = "markdown-it-py"
+version = "3.0.0"
+description = "Python port of markdown-it. Markdown parsing, done right!"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
+ {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
+]
+
+[package.dependencies]
+mdurl = ">=0.1,<1.0"
+
+[package.extras]
+benchmarking = ["psutil", "pytest", "pytest-benchmark"]
+code-style = ["pre-commit (>=3.0,<4.0)"]
+compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
+linkify = ["linkify-it-py (>=1,<3)"]
+plugins = ["mdit-py-plugins"]
+profiling = ["gprof2dot"]
+rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
+testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
+
+[[package]]
+name = "markupsafe"
+version = "2.1.5"
+description = "Safely add untrusted strings to HTML/XML markup."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
+ {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
+ {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"},
+ {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"},
+ {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"},
+ {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"},
+ {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"},
+ {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"},
+ {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"},
+ {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"},
+ {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"},
+ {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"},
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"},
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"},
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"},
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"},
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"},
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"},
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"},
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"},
+ {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"},
+ {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"},
+ {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"},
+ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
+]
+
+[[package]]
+name = "matplotlib"
+version = "3.8.4"
+description = "Python plotting package"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "matplotlib-3.8.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:abc9d838f93583650c35eca41cfcec65b2e7cb50fd486da6f0c49b5e1ed23014"},
+ {file = "matplotlib-3.8.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f65c9f002d281a6e904976007b2d46a1ee2bcea3a68a8c12dda24709ddc9106"},
+ {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce1edd9f5383b504dbc26eeea404ed0a00656c526638129028b758fd43fc5f10"},
+ {file = "matplotlib-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0"},
+ {file = "matplotlib-3.8.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:90df07db7b599fe7035d2f74ab7e438b656528c68ba6bb59b7dc46af39ee48ef"},
+ {file = "matplotlib-3.8.4-cp310-cp310-win_amd64.whl", hash = "sha256:ac24233e8f2939ac4fd2919eed1e9c0871eac8057666070e94cbf0b33dd9c338"},
+ {file = "matplotlib-3.8.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:72f9322712e4562e792b2961971891b9fbbb0e525011e09ea0d1f416c4645661"},
+ {file = "matplotlib-3.8.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:232ce322bfd020a434caaffbd9a95333f7c2491e59cfc014041d95e38ab90d1c"},
+ {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6addbd5b488aedb7f9bc19f91cd87ea476206f45d7116fcfe3d31416702a82fa"},
+ {file = "matplotlib-3.8.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc4ccdc64e3039fc303defd119658148f2349239871db72cd74e2eeaa9b80b71"},
+ {file = "matplotlib-3.8.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b7a2a253d3b36d90c8993b4620183b55665a429da8357a4f621e78cd48b2b30b"},
+ {file = "matplotlib-3.8.4-cp311-cp311-win_amd64.whl", hash = "sha256:8080d5081a86e690d7688ffa542532e87f224c38a6ed71f8fbed34dd1d9fedae"},
+ {file = "matplotlib-3.8.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6485ac1f2e84676cff22e693eaa4fbed50ef5dc37173ce1f023daef4687df616"},
+ {file = "matplotlib-3.8.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c89ee9314ef48c72fe92ce55c4e95f2f39d70208f9f1d9db4e64079420d8d732"},
+ {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50bac6e4d77e4262c4340d7a985c30912054745ec99756ce213bfbc3cb3808eb"},
+ {file = "matplotlib-3.8.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f51c4c869d4b60d769f7b4406eec39596648d9d70246428745a681c327a8ad30"},
+ {file = "matplotlib-3.8.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b12ba985837e4899b762b81f5b2845bd1a28f4fdd1a126d9ace64e9c4eb2fb25"},
+ {file = "matplotlib-3.8.4-cp312-cp312-win_amd64.whl", hash = "sha256:7a6769f58ce51791b4cb8b4d7642489df347697cd3e23d88266aaaee93b41d9a"},
+ {file = "matplotlib-3.8.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:843cbde2f0946dadd8c5c11c6d91847abd18ec76859dc319362a0964493f0ba6"},
+ {file = "matplotlib-3.8.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c13f041a7178f9780fb61cc3a2b10423d5e125480e4be51beaf62b172413b67"},
+ {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb44f53af0a62dc80bba4443d9b27f2fde6acfdac281d95bc872dc148a6509cc"},
+ {file = "matplotlib-3.8.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:606e3b90897554c989b1e38a258c626d46c873523de432b1462f295db13de6f9"},
+ {file = "matplotlib-3.8.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9bb0189011785ea794ee827b68777db3ca3f93f3e339ea4d920315a0e5a78d54"},
+ {file = "matplotlib-3.8.4-cp39-cp39-win_amd64.whl", hash = "sha256:6209e5c9aaccc056e63b547a8152661324404dd92340a6e479b3a7f24b42a5d0"},
+ {file = "matplotlib-3.8.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c7064120a59ce6f64103c9cefba8ffe6fba87f2c61d67c401186423c9a20fd35"},
+ {file = "matplotlib-3.8.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0e47eda4eb2614300fc7bb4657fced3e83d6334d03da2173b09e447418d499f"},
+ {file = "matplotlib-3.8.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:493e9f6aa5819156b58fce42b296ea31969f2aab71c5b680b4ea7a3cb5c07d94"},
+ {file = "matplotlib-3.8.4.tar.gz", hash = "sha256:8aac397d5e9ec158960e31c381c5ffc52ddd52bd9a47717e2a694038167dffea"},
+]
+
+[package.dependencies]
+contourpy = ">=1.0.1"
+cycler = ">=0.10"
+fonttools = ">=4.22.0"
+kiwisolver = ">=1.3.1"
+numpy = ">=1.21"
+packaging = ">=20.0"
+pillow = ">=8"
+pyparsing = ">=2.3.1"
+python-dateutil = ">=2.7"
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+description = "Markdown URL utilities"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
+ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
+]
+
+[[package]]
+name = "mkl"
+version = "2021.4.0"
+description = "Intel® oneAPI Math Kernel Library"
+optional = false
+python-versions = "*"
+files = [
+ {file = "mkl-2021.4.0-py2.py3-none-macosx_10_15_x86_64.macosx_11_0_x86_64.whl", hash = "sha256:67460f5cd7e30e405b54d70d1ed3ca78118370b65f7327d495e9c8847705e2fb"},
+ {file = "mkl-2021.4.0-py2.py3-none-manylinux1_i686.whl", hash = "sha256:636d07d90e68ccc9630c654d47ce9fdeb036bb46e2b193b3a9ac8cfea683cce5"},
+ {file = "mkl-2021.4.0-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:398dbf2b0d12acaf54117a5210e8f191827f373d362d796091d161f610c1ebfb"},
+ {file = "mkl-2021.4.0-py2.py3-none-win32.whl", hash = "sha256:439c640b269a5668134e3dcbcea4350459c4a8bc46469669b2d67e07e3d330e8"},
+ {file = "mkl-2021.4.0-py2.py3-none-win_amd64.whl", hash = "sha256:ceef3cafce4c009dd25f65d7ad0d833a0fbadc3d8903991ec92351fe5de1e718"},
+]
+
+[package.dependencies]
+intel-openmp = "==2021.*"
+tbb = "==2021.*"
+
+[[package]]
+name = "mpmath"
+version = "1.3.0"
+description = "Python library for arbitrary-precision floating-point arithmetic"
+optional = false
+python-versions = "*"
+files = [
+ {file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"},
+ {file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"},
+]
+
+[package.extras]
+develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"]
+docs = ["sphinx"]
+gmpy = ["gmpy2 (>=2.1.0a4)"]
+tests = ["pytest (>=4.6)"]
+
+[[package]]
+name = "networkx"
+version = "3.3"
+description = "Python package for creating and manipulating graphs and networks"
+optional = false
+python-versions = ">=3.10"
+files = [
+ {file = "networkx-3.3-py3-none-any.whl", hash = "sha256:28575580c6ebdaf4505b22c6256a2b9de86b316dc63ba9e93abde3d78dfdbcf2"},
+ {file = "networkx-3.3.tar.gz", hash = "sha256:0c127d8b2f4865f59ae9cb8aafcd60b5c70f3241ebd66f7defad7c4ab90126c9"},
+]
+
+[package.extras]
+default = ["matplotlib (>=3.6)", "numpy (>=1.23)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"]
+developer = ["changelist (==0.5)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"]
+doc = ["myst-nb (>=1.0)", "numpydoc (>=1.7)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"]
+extra = ["lxml (>=4.6)", "pydot (>=2.0)", "pygraphviz (>=1.12)", "sympy (>=1.10)"]
+test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"]
+
+[[package]]
+name = "numpy"
+version = "1.26.4"
+description = "Fundamental package for array computing in Python"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0"},
+ {file = "numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a"},
+ {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4"},
+ {file = "numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f"},
+ {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a"},
+ {file = "numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2"},
+ {file = "numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07"},
+ {file = "numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5"},
+ {file = "numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71"},
+ {file = "numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef"},
+ {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e"},
+ {file = "numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5"},
+ {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a"},
+ {file = "numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a"},
+ {file = "numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20"},
+ {file = "numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2"},
+ {file = "numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b3ce300f3644fb06443ee2222c2201dd3a89ea6040541412b8fa189341847218"},
+ {file = "numpy-1.26.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:03a8c78d01d9781b28a6989f6fa1bb2c4f2d51201cf99d3dd875df6fbd96b23b"},
+ {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fad7dcb1aac3c7f0584a5a8133e3a43eeb2fe127f47e3632d43d677c66c102b"},
+ {file = "numpy-1.26.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675d61ffbfa78604709862923189bad94014bef562cc35cf61d3a07bba02a7ed"},
+ {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ab47dbe5cc8210f55aa58e4805fe224dac469cde56b9f731a4c098b91917159a"},
+ {file = "numpy-1.26.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:1dda2e7b4ec9dd512f84935c5f126c8bd8b9f2fc001e9f54af255e8c5f16b0e0"},
+ {file = "numpy-1.26.4-cp312-cp312-win32.whl", hash = "sha256:50193e430acfc1346175fcbdaa28ffec49947a06918b7b92130744e81e640110"},
+ {file = "numpy-1.26.4-cp312-cp312-win_amd64.whl", hash = "sha256:08beddf13648eb95f8d867350f6a018a4be2e5ad54c8d8caed89ebca558b2818"},
+ {file = "numpy-1.26.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7349ab0fa0c429c82442a27a9673fc802ffdb7c7775fad780226cb234965e53c"},
+ {file = "numpy-1.26.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:52b8b60467cd7dd1e9ed082188b4e6bb35aa5cdd01777621a1658910745b90be"},
+ {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d5241e0a80d808d70546c697135da2c613f30e28251ff8307eb72ba696945764"},
+ {file = "numpy-1.26.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f870204a840a60da0b12273ef34f7051e98c3b5961b61b0c2c1be6dfd64fbcd3"},
+ {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:679b0076f67ecc0138fd2ede3a8fd196dddc2ad3254069bcb9faf9a79b1cebcd"},
+ {file = "numpy-1.26.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47711010ad8555514b434df65f7d7b076bb8261df1ca9bb78f53d3b2db02e95c"},
+ {file = "numpy-1.26.4-cp39-cp39-win32.whl", hash = "sha256:a354325ee03388678242a4d7ebcd08b5c727033fcff3b2f536aea978e15ee9e6"},
+ {file = "numpy-1.26.4-cp39-cp39-win_amd64.whl", hash = "sha256:3373d5d70a5fe74a2c1bb6d2cfd9609ecf686d47a2d7b1d37a8f3b6bf6003aea"},
+ {file = "numpy-1.26.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:afedb719a9dcfc7eaf2287b839d8198e06dcd4cb5d276a3df279231138e83d30"},
+ {file = "numpy-1.26.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95a7476c59002f2f6c590b9b7b998306fba6a5aa646b1e22ddfeaf8f78c3a29c"},
+ {file = "numpy-1.26.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7e50d0a0cc3189f9cb0aeb3a6a6af18c16f59f004b866cd2be1c14b36134a4a0"},
+ {file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"},
+]
+
+[[package]]
+name = "nvidia-cublas-cu12"
+version = "12.1.3.1"
+description = "CUBLAS native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728"},
+ {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-win_amd64.whl", hash = "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906"},
+]
+
+[[package]]
+name = "nvidia-cuda-cupti-cu12"
+version = "12.1.105"
+description = "CUDA profiling tools runtime libs."
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e"},
+ {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4"},
+]
+
+[[package]]
+name = "nvidia-cuda-nvrtc-cu12"
+version = "12.1.105"
+description = "NVRTC native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2"},
+ {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed"},
+]
+
+[[package]]
+name = "nvidia-cuda-runtime-cu12"
+version = "12.1.105"
+description = "CUDA Runtime native Libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40"},
+ {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344"},
+]
+
+[[package]]
+name = "nvidia-cudnn-cu12"
+version = "8.9.2.26"
+description = "cuDNN runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl", hash = "sha256:5ccb288774fdfb07a7e7025ffec286971c06d8d7b4fb162525334616d7629ff9"},
+]
+
+[package.dependencies]
+nvidia-cublas-cu12 = "*"
+
+[[package]]
+name = "nvidia-cufft-cu12"
+version = "11.0.2.54"
+description = "CUFFT native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl", hash = "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56"},
+ {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-win_amd64.whl", hash = "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253"},
+]
+
+[[package]]
+name = "nvidia-curand-cu12"
+version = "10.3.2.106"
+description = "CURAND native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0"},
+ {file = "nvidia_curand_cu12-10.3.2.106-py3-none-win_amd64.whl", hash = "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a"},
+]
+
+[[package]]
+name = "nvidia-cusolver-cu12"
+version = "11.4.5.107"
+description = "CUDA solver native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd"},
+ {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-win_amd64.whl", hash = "sha256:74e0c3a24c78612192a74fcd90dd117f1cf21dea4822e66d89e8ea80e3cd2da5"},
+]
+
+[package.dependencies]
+nvidia-cublas-cu12 = "*"
+nvidia-cusparse-cu12 = "*"
+nvidia-nvjitlink-cu12 = "*"
+
+[[package]]
+name = "nvidia-cusparse-cu12"
+version = "12.1.0.106"
+description = "CUSPARSE native runtime libraries"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c"},
+ {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-win_amd64.whl", hash = "sha256:b798237e81b9719373e8fae8d4f091b70a0cf09d9d85c95a557e11df2d8e9a5a"},
+]
+
+[package.dependencies]
+nvidia-nvjitlink-cu12 = "*"
+
+[[package]]
+name = "nvidia-nccl-cu12"
+version = "2.20.5"
+description = "NVIDIA Collective Communication Library (NCCL) Runtime"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1fc150d5c3250b170b29410ba682384b14581db722b2531b0d8d33c595f33d01"},
+ {file = "nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:057f6bf9685f75215d0c53bf3ac4a10b3e6578351de307abad9e18a99182af56"},
+]
+
+[[package]]
+name = "nvidia-nvjitlink-cu12"
+version = "12.4.127"
+description = "Nvidia JIT LTO Library"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl", hash = "sha256:06b3b9b25bf3f8af351d664978ca26a16d2c5127dbd53c0497e28d1fb9611d57"},
+ {file = "nvidia_nvjitlink_cu12-12.4.127-py3-none-win_amd64.whl", hash = "sha256:fd9020c501d27d135f983c6d3e244b197a7ccad769e34df53a42e276b0e25fa1"},
+]
+
+[[package]]
+name = "nvidia-nvtx-cu12"
+version = "12.1.105"
+description = "NVIDIA Tools Extension"
+optional = false
+python-versions = ">=3"
+files = [
+ {file = "nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5"},
+ {file = "nvidia_nvtx_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82"},
+]
+
+[[package]]
+name = "onnx"
+version = "1.16.0"
+description = "Open Neural Network Exchange"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "onnx-1.16.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:9eadbdce25b19d6216f426d6d99b8bc877a65ed92cbef9707751c6669190ba4f"},
+ {file = "onnx-1.16.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:034ae21a2aaa2e9c14119a840d2926d213c27aad29e5e3edaa30145a745048e1"},
+ {file = "onnx-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec22a43d74eb1f2303373e2fbe7fbcaa45fb225f4eb146edfed1356ada7a9aea"},
+ {file = "onnx-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:298f28a2b5ac09145fa958513d3d1e6b349ccf86a877dbdcccad57713fe360b3"},
+ {file = "onnx-1.16.0-cp310-cp310-win32.whl", hash = "sha256:66300197b52beca08bc6262d43c103289c5d45fde43fb51922ed1eb83658cf0c"},
+ {file = "onnx-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae0029f5e47bf70a1a62e7f88c80bca4ef39b844a89910039184221775df5e43"},
+ {file = "onnx-1.16.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:f51179d4af3372b4f3800c558d204b592c61e4b4a18b8f61e0eea7f46211221a"},
+ {file = "onnx-1.16.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:5202559070afec5144332db216c20f2fff8323cf7f6512b0ca11b215eacc5bf3"},
+ {file = "onnx-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77579e7c15b4df39d29465b216639a5f9b74026bdd9e4b6306cd19a32dcfe67c"},
+ {file = "onnx-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e60ca76ac24b65c25860d0f2d2cdd96d6320d062a01dd8ce87c5743603789b8"},
+ {file = "onnx-1.16.0-cp311-cp311-win32.whl", hash = "sha256:81b4ee01bc554e8a2b11ac6439882508a5377a1c6b452acd69a1eebb83571117"},
+ {file = "onnx-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:7449241e70b847b9c3eb8dae622df8c1b456d11032a9d7e26e0ee8a698d5bf86"},
+ {file = "onnx-1.16.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:03a627488b1a9975d95d6a55582af3e14c7f3bb87444725b999935ddd271d352"},
+ {file = "onnx-1.16.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:c392faeabd9283ee344ccb4b067d1fea9dfc614fa1f0de7c47589efd79e15e78"},
+ {file = "onnx-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0efeb46985de08f0efe758cb54ad3457e821a05c2eaf5ba2ccb8cd1602c08084"},
+ {file = "onnx-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf14a3d32234f23e44abb73a755cb96a423fac7f004e8f046f36b10214151ee"},
+ {file = "onnx-1.16.0-cp312-cp312-win32.whl", hash = "sha256:62a2e27ae8ba5fc9b4a2620301446a517b5ffaaf8566611de7a7c2160f5bcf4c"},
+ {file = "onnx-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:3e0860fea94efde777e81a6f68f65761ed5e5f3adea2e050d7fbe373a9ae05b3"},
+ {file = "onnx-1.16.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:70a90649318f3470985439ea078277c9fb2a2e6e2fd7c8f3f2b279402ad6c7e6"},
+ {file = "onnx-1.16.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:71839546b7f93be4fa807995b182ab4b4414c9dbf049fee11eaaced16fcf8df2"},
+ {file = "onnx-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7665217c45a61eb44718c8e9349d2ad004efa0cb9fbc4be5c6d5e18b9fe12b52"},
+ {file = "onnx-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5752bbbd5717304a7643643dba383a2fb31e8eb0682f4e7b7d141206328a73b"},
+ {file = "onnx-1.16.0-cp38-cp38-win32.whl", hash = "sha256:257858cbcb2055284f09fa2ae2b1cfd64f5850367da388d6e7e7b05920a40c90"},
+ {file = "onnx-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:209fe84995a28038e29ae8369edd35f33e0ef1ebc3bddbf6584629823469deb1"},
+ {file = "onnx-1.16.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:8cf3e518b1b1b960be542e7c62bed4e5219e04c85d540817b7027029537dec92"},
+ {file = "onnx-1.16.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:30f02beaf081c7d9fa3a8c566a912fc4408e28fc33b1452d58f890851691d364"},
+ {file = "onnx-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fb29a9a692b522deef1f6b8f2145da62c0c43ea1ed5b4c0f66f827fdc28847d"},
+ {file = "onnx-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7755cbd5f4e47952e37276ea5978a46fc8346684392315902b5ed4a719d87d06"},
+ {file = "onnx-1.16.0-cp39-cp39-win32.whl", hash = "sha256:7532343dc5b8b5e7c3e3efa441a3100552f7600155c4db9120acd7574f64ffbf"},
+ {file = "onnx-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:d7886c05aa6d583ec42f6287678923c1e343afc4350e49d5b36a0023772ffa22"},
+ {file = "onnx-1.16.0.tar.gz", hash = "sha256:237c6987c6c59d9f44b6136f5819af79574f8d96a760a1fa843bede11f3822f7"},
+]
+
+[package.dependencies]
+numpy = ">=1.20"
+protobuf = ">=3.20.2"
+
+[package.extras]
+reference = ["Pillow", "google-re2"]
+
+[[package]]
+name = "onnxruntime"
+version = "1.17.3"
+description = "ONNX Runtime is a runtime accelerator for Machine Learning models"
+optional = false
+python-versions = "*"
+files = [
+ {file = "onnxruntime-1.17.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:d86dde9c0bb435d709e51bd25991c9fe5b9a5b168df45ce119769edc4d198b15"},
+ {file = "onnxruntime-1.17.3-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9d87b68bf931ac527b2d3c094ead66bb4381bac4298b65f46c54fe4d1e255865"},
+ {file = "onnxruntime-1.17.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26e950cf0333cf114a155f9142e71da344d2b08dfe202763a403ae81cc02ebd1"},
+ {file = "onnxruntime-1.17.3-cp310-cp310-win32.whl", hash = "sha256:0962a4d0f5acebf62e1f0bf69b6e0adf16649115d8de854c1460e79972324d68"},
+ {file = "onnxruntime-1.17.3-cp310-cp310-win_amd64.whl", hash = "sha256:468ccb8a0faa25c681a41787b1594bf4448b0252d3efc8b62fd8b2411754340f"},
+ {file = "onnxruntime-1.17.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e8cd90c1c17d13d47b89ab076471e07fb85467c01dcd87a8b8b5cdfbcb40aa51"},
+ {file = "onnxruntime-1.17.3-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a058b39801baefe454eeb8acf3ada298c55a06a4896fafc224c02d79e9037f60"},
+ {file = "onnxruntime-1.17.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f823d5eb4807007f3da7b27ca972263df6a1836e6f327384eb266274c53d05d"},
+ {file = "onnxruntime-1.17.3-cp311-cp311-win32.whl", hash = "sha256:b66b23f9109e78ff2791628627a26f65cd335dcc5fbd67ff60162733a2f7aded"},
+ {file = "onnxruntime-1.17.3-cp311-cp311-win_amd64.whl", hash = "sha256:570760ca53a74cdd751ee49f13de70d1384dcf73d9888b8deac0917023ccda6d"},
+ {file = "onnxruntime-1.17.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:77c318178d9c16e9beadd9a4070d8aaa9f57382c3f509b01709f0f010e583b99"},
+ {file = "onnxruntime-1.17.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23da8469049b9759082e22c41a444f44a520a9c874b084711b6343672879f50b"},
+ {file = "onnxruntime-1.17.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2949730215af3f9289008b2e31e9bbef952012a77035b911c4977edea06f3f9e"},
+ {file = "onnxruntime-1.17.3-cp312-cp312-win32.whl", hash = "sha256:6c7555a49008f403fb3b19204671efb94187c5085976ae526cb625f6ede317bc"},
+ {file = "onnxruntime-1.17.3-cp312-cp312-win_amd64.whl", hash = "sha256:58672cf20293a1b8a277a5c6c55383359fcdf6119b2f14df6ce3b140f5001c39"},
+ {file = "onnxruntime-1.17.3-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:4395ba86e3c1e93c794a00619ef1aec597ab78f5a5039f3c6d2e9d0695c0a734"},
+ {file = "onnxruntime-1.17.3-cp38-cp38-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdf354c04344ec38564fc22394e1fe08aa6d70d790df00159205a0055c4a4d3f"},
+ {file = "onnxruntime-1.17.3-cp38-cp38-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a94b600b7af50e922d44b95a57981e3e35103c6e3693241a03d3ca204740bbda"},
+ {file = "onnxruntime-1.17.3-cp38-cp38-win32.whl", hash = "sha256:5a335c76f9c002a8586c7f38bc20fe4b3725ced21f8ead835c3e4e507e42b2ab"},
+ {file = "onnxruntime-1.17.3-cp38-cp38-win_amd64.whl", hash = "sha256:8f56a86fbd0ddc8f22696ddeda0677b041381f4168a2ca06f712ef6ec6050d6d"},
+ {file = "onnxruntime-1.17.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:e0ae39f5452278cd349520c296e7de3e90d62dc5b0157c6868e2748d7f28b871"},
+ {file = "onnxruntime-1.17.3-cp39-cp39-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ff2dc012bd930578aff5232afd2905bf16620815f36783a941aafabf94b3702"},
+ {file = "onnxruntime-1.17.3-cp39-cp39-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf6c37483782e4785019b56e26224a25e9b9a35b849d0169ce69189867a22bb1"},
+ {file = "onnxruntime-1.17.3-cp39-cp39-win32.whl", hash = "sha256:351bf5a1140dcc43bfb8d3d1a230928ee61fcd54b0ea664c8e9a889a8e3aa515"},
+ {file = "onnxruntime-1.17.3-cp39-cp39-win_amd64.whl", hash = "sha256:57a3de15778da8d6cc43fbf6cf038e1e746146300b5f0b1fbf01f6f795dc6440"},
+]
+
+[package.dependencies]
+coloredlogs = "*"
+flatbuffers = "*"
+numpy = ">=1.21.6"
+packaging = "*"
+protobuf = "*"
+sympy = "*"
+
+[[package]]
+name = "packaging"
+version = "24.0"
+description = "Core utilities for Python packages"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"},
+ {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"},
+]
+
+[[package]]
+name = "pandas"
+version = "2.2.2"
+description = "Powerful data structures for data analysis, time series, and statistics"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "pandas-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90c6fca2acf139569e74e8781709dccb6fe25940488755716d1d354d6bc58bce"},
+ {file = "pandas-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c7adfc142dac335d8c1e0dcbd37eb8617eac386596eb9e1a1b77791cf2498238"},
+ {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4abfe0be0d7221be4f12552995e58723c7422c80a659da13ca382697de830c08"},
+ {file = "pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0"},
+ {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:40ae1dffb3967a52203105a077415a86044a2bea011b5f321c6aa64b379a3f51"},
+ {file = "pandas-2.2.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e5a0b00e1e56a842f922e7fae8ae4077aee4af0acb5ae3622bd4b4c30aedf99"},
+ {file = "pandas-2.2.2-cp310-cp310-win_amd64.whl", hash = "sha256:ddf818e4e6c7c6f4f7c8a12709696d193976b591cc7dc50588d3d1a6b5dc8772"},
+ {file = "pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:696039430f7a562b74fa45f540aca068ea85fa34c244d0deee539cb6d70aa288"},
+ {file = "pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e90497254aacacbc4ea6ae5e7a8cd75629d6ad2b30025a4a8b09aa4faf55151"},
+ {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:58b84b91b0b9f4bafac2a0ac55002280c094dfc6402402332c0913a59654ab2b"},
+ {file = "pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2123dc9ad6a814bcdea0f099885276b31b24f7edf40f6cdbc0912672e22eee"},
+ {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:2925720037f06e89af896c70bca73459d7e6a4be96f9de79e2d440bd499fe0db"},
+ {file = "pandas-2.2.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0cace394b6ea70c01ca1595f839cf193df35d1575986e484ad35c4aeae7266c1"},
+ {file = "pandas-2.2.2-cp311-cp311-win_amd64.whl", hash = "sha256:873d13d177501a28b2756375d59816c365e42ed8417b41665f346289adc68d24"},
+ {file = "pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9dfde2a0ddef507a631dc9dc4af6a9489d5e2e740e226ad426a05cabfbd7c8ef"},
+ {file = "pandas-2.2.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b79011ff7a0f4b1d6da6a61aa1aa604fb312d6647de5bad20013682d1429ce"},
+ {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cb51fe389360f3b5a4d57dbd2848a5f033350336ca3b340d1c53a1fad33bcad"},
+ {file = "pandas-2.2.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eee3a87076c0756de40b05c5e9a6069c035ba43e8dd71c379e68cab2c20f16ad"},
+ {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3e374f59e440d4ab45ca2fffde54b81ac3834cf5ae2cdfa69c90bc03bde04d76"},
+ {file = "pandas-2.2.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:43498c0bdb43d55cb162cdc8c06fac328ccb5d2eabe3cadeb3529ae6f0517c32"},
+ {file = "pandas-2.2.2-cp312-cp312-win_amd64.whl", hash = "sha256:d187d355ecec3629624fccb01d104da7d7f391db0311145817525281e2804d23"},
+ {file = "pandas-2.2.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0ca6377b8fca51815f382bd0b697a0814c8bda55115678cbc94c30aacbb6eff2"},
+ {file = "pandas-2.2.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9057e6aa78a584bc93a13f0a9bf7e753a5e9770a30b4d758b8d5f2a62a9433cd"},
+ {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:001910ad31abc7bf06f49dcc903755d2f7f3a9186c0c040b827e522e9cef0863"},
+ {file = "pandas-2.2.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66b479b0bd07204e37583c191535505410daa8df638fd8e75ae1b383851fe921"},
+ {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a77e9d1c386196879aa5eb712e77461aaee433e54c68cf253053a73b7e49c33a"},
+ {file = "pandas-2.2.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92fd6b027924a7e178ac202cfbe25e53368db90d56872d20ffae94b96c7acc57"},
+ {file = "pandas-2.2.2-cp39-cp39-win_amd64.whl", hash = "sha256:640cef9aa381b60e296db324337a554aeeb883ead99dc8f6c18e81a93942f5f4"},
+ {file = "pandas-2.2.2.tar.gz", hash = "sha256:9e79019aba43cb4fda9e4d983f8e88ca0373adbb697ae9c6c43093218de28b54"},
+]
+
+[package.dependencies]
+numpy = [
+ {version = ">=1.23.2", markers = "python_version == \"3.11\""},
+ {version = ">=1.26.0", markers = "python_version >= \"3.12\""},
+]
+python-dateutil = ">=2.8.2"
+pytz = ">=2020.1"
+tzdata = ">=2022.7"
+
+[package.extras]
+all = ["PyQt5 (>=5.15.9)", "SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)", "beautifulsoup4 (>=4.11.2)", "bottleneck (>=1.3.6)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=2022.12.0)", "fsspec (>=2022.11.0)", "gcsfs (>=2022.11.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.9.2)", "matplotlib (>=3.6.3)", "numba (>=0.56.4)", "numexpr (>=2.8.4)", "odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "pandas-gbq (>=0.19.0)", "psycopg2 (>=2.9.6)", "pyarrow (>=10.0.1)", "pymysql (>=1.0.2)", "pyreadstat (>=1.2.0)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "qtpy (>=2.3.0)", "s3fs (>=2022.11.0)", "scipy (>=1.10.0)", "tables (>=3.8.0)", "tabulate (>=0.9.0)", "xarray (>=2022.12.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)", "zstandard (>=0.19.0)"]
+aws = ["s3fs (>=2022.11.0)"]
+clipboard = ["PyQt5 (>=5.15.9)", "qtpy (>=2.3.0)"]
+compression = ["zstandard (>=0.19.0)"]
+computation = ["scipy (>=1.10.0)", "xarray (>=2022.12.0)"]
+consortium-standard = ["dataframe-api-compat (>=0.1.7)"]
+excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.1.0)", "python-calamine (>=0.1.7)", "pyxlsb (>=1.0.10)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.5)"]
+feather = ["pyarrow (>=10.0.1)"]
+fss = ["fsspec (>=2022.11.0)"]
+gcp = ["gcsfs (>=2022.11.0)", "pandas-gbq (>=0.19.0)"]
+hdf5 = ["tables (>=3.8.0)"]
+html = ["beautifulsoup4 (>=4.11.2)", "html5lib (>=1.1)", "lxml (>=4.9.2)"]
+mysql = ["SQLAlchemy (>=2.0.0)", "pymysql (>=1.0.2)"]
+output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.9.0)"]
+parquet = ["pyarrow (>=10.0.1)"]
+performance = ["bottleneck (>=1.3.6)", "numba (>=0.56.4)", "numexpr (>=2.8.4)"]
+plot = ["matplotlib (>=3.6.3)"]
+postgresql = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "psycopg2 (>=2.9.6)"]
+pyarrow = ["pyarrow (>=10.0.1)"]
+spss = ["pyreadstat (>=1.2.0)"]
+sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-driver-sqlite (>=0.8.0)"]
+test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"]
+xml = ["lxml (>=4.9.2)"]
+
+[[package]]
+name = "pettingzoo"
+version = "1.24.3"
+description = "Gymnasium for multi-agent reinforcement learning."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pettingzoo-1.24.3-py3-none-any.whl", hash = "sha256:23ed90517d2e8a7098bdaf5e31234b3a7f7b73ca578d70d1ca7b9d0cb0e37982"},
+ {file = "pettingzoo-1.24.3.tar.gz", hash = "sha256:91f9094f18e06fb74b98f4099cd22e8ae4396125e51719d50b30c9f1c7ab07e6"},
+]
+
+[package.dependencies]
+gymnasium = ">=0.28.0"
+numpy = ">=1.21.0"
+
+[package.extras]
+all = ["box2d-py (==2.3.5)", "chess (==1.9.4)", "multi-agent-ale-py (==0.1.11)", "pillow (>=8.0.1)", "pygame (==2.3.0)", "pymunk (==6.2.0)", "rlcard (==1.0.5)", "scipy (>=1.4.1)", "shimmy[openspiel] (>=1.2.0)"]
+atari = ["multi-agent-ale-py (==0.1.11)", "pygame (==2.3.0)"]
+butterfly = ["pygame (==2.3.0)", "pymunk (==6.2.0)"]
+classic = ["chess (==1.9.4)", "pygame (==2.3.0)", "rlcard (==1.0.5)", "shimmy[openspiel] (>=1.2.0)"]
+mpe = ["pygame (==2.3.0)"]
+other = ["pillow (>=8.0.1)"]
+sisl = ["box2d-py (==2.3.5)", "pygame (==2.3.0)", "pymunk (==6.2.0)", "scipy (>=1.4.1)"]
+testing = ["AutoROM", "pre-commit", "pynput", "pytest", "pytest-cov", "pytest-markdown-docs", "pytest-xdist"]
+
+[[package]]
+name = "pillow"
+version = "10.3.0"
+description = "Python Imaging Library (Fork)"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"},
+ {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"},
+ {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"},
+ {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"},
+ {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"},
+ {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"},
+ {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"},
+ {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"},
+ {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"},
+ {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"},
+ {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"},
+ {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"},
+ {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"},
+ {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"},
+ {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"},
+ {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"},
+ {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"},
+ {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"},
+ {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"},
+ {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"},
+ {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"},
+ {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"},
+ {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"},
+ {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"},
+ {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"},
+ {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"},
+ {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"},
+ {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"},
+ {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"},
+ {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"},
+ {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"},
+ {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"},
+ {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"},
+ {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"},
+ {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"},
+ {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"},
+ {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"},
+ {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"},
+ {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"},
+ {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"},
+ {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"},
+ {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"},
+ {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"},
+ {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"},
+ {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"},
+ {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"},
+ {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"},
+ {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"},
+ {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"},
+ {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"},
+ {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"},
+ {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"},
+ {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"},
+ {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"},
+ {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"},
+ {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"},
+ {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"},
+]
+
+[package.extras]
+docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"]
+fpx = ["olefile"]
+mic = ["olefile"]
+tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"]
+typing = ["typing-extensions"]
+xmp = ["defusedxml"]
+
+[[package]]
+name = "protobuf"
+version = "5.26.1"
+description = ""
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "protobuf-5.26.1-cp310-abi3-win32.whl", hash = "sha256:3c388ea6ddfe735f8cf69e3f7dc7611e73107b60bdfcf5d0f024c3ccd3794e23"},
+ {file = "protobuf-5.26.1-cp310-abi3-win_amd64.whl", hash = "sha256:e6039957449cb918f331d32ffafa8eb9255769c96aa0560d9a5bf0b4e00a2a33"},
+ {file = "protobuf-5.26.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:38aa5f535721d5bb99861166c445c4105c4e285c765fbb2ac10f116e32dcd46d"},
+ {file = "protobuf-5.26.1-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:fbfe61e7ee8c1860855696e3ac6cfd1b01af5498facc6834fcc345c9684fb2ca"},
+ {file = "protobuf-5.26.1-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:f7417703f841167e5a27d48be13389d52ad705ec09eade63dfc3180a959215d7"},
+ {file = "protobuf-5.26.1-cp38-cp38-win32.whl", hash = "sha256:d693d2504ca96750d92d9de8a103102dd648fda04540495535f0fec7577ed8fc"},
+ {file = "protobuf-5.26.1-cp38-cp38-win_amd64.whl", hash = "sha256:9b557c317ebe6836835ec4ef74ec3e994ad0894ea424314ad3552bc6e8835b4e"},
+ {file = "protobuf-5.26.1-cp39-cp39-win32.whl", hash = "sha256:b9ba3ca83c2e31219ffbeb9d76b63aad35a3eb1544170c55336993d7a18ae72c"},
+ {file = "protobuf-5.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ee014c2c87582e101d6b54260af03b6596728505c79f17c8586e7523aaa8f8c"},
+ {file = "protobuf-5.26.1-py3-none-any.whl", hash = "sha256:da612f2720c0183417194eeaa2523215c4fcc1a1949772dc65f05047e08d5932"},
+ {file = "protobuf-5.26.1.tar.gz", hash = "sha256:8ca2a1d97c290ec7b16e4e5dff2e5ae150cc1582f55b5ab300d45cb0dfa90e51"},
+]
+
+[[package]]
+name = "pygments"
+version = "2.18.0"
+description = "Pygments is a syntax highlighting package written in Python."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
+ {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
+]
+
+[package.extras]
+windows-terminal = ["colorama (>=0.4.6)"]
+
+[[package]]
+name = "pyparsing"
+version = "3.1.2"
+description = "pyparsing module - Classes and methods to define and execute parsing grammars"
+optional = false
+python-versions = ">=3.6.8"
+files = [
+ {file = "pyparsing-3.1.2-py3-none-any.whl", hash = "sha256:f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742"},
+ {file = "pyparsing-3.1.2.tar.gz", hash = "sha256:a1bac0ce561155ecc3ed78ca94d3c9378656ad4c94c1270de543f621420f94ad"},
+]
+
+[package.extras]
+diagrams = ["jinja2", "railroad-diagrams"]
+
+[[package]]
+name = "pyreadline3"
+version = "3.4.1"
+description = "A python implementation of GNU readline."
+optional = false
+python-versions = "*"
+files = [
+ {file = "pyreadline3-3.4.1-py3-none-any.whl", hash = "sha256:b0efb6516fd4fb07b45949053826a62fa4cb353db5be2bbb4a7aa1fdd1e345fb"},
+ {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"},
+]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+description = "Extensions to the standard Python datetime module"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+files = [
+ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
+ {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
+]
+
+[package.dependencies]
+six = ">=1.5"
+
+[[package]]
+name = "pytz"
+version = "2024.1"
+description = "World timezone definitions, modern and historical"
+optional = false
+python-versions = "*"
+files = [
+ {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"},
+ {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"},
+]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.1"
+description = "YAML parser and emitter for Python"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
+ {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
+ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
+ {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
+ {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
+ {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
+ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
+ {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
+ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
+ {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
+ {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
+ {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
+ {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
+ {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
+ {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
+ {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
+ {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
+ {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
+ {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
+ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
+ {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
+ {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
+ {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
+ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
+ {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
+ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
+]
+
+[[package]]
+name = "requests"
+version = "2.31.0"
+description = "Python HTTP for Humans."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
+ {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
+]
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+charset-normalizer = ">=2,<4"
+idna = ">=2.5,<4"
+urllib3 = ">=1.21.1,<3"
+
+[package.extras]
+socks = ["PySocks (>=1.5.6,!=1.5.7)"]
+use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+
+[[package]]
+name = "rich"
+version = "13.7.1"
+description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
+optional = false
+python-versions = ">=3.7.0"
+files = [
+ {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"},
+ {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
+]
+
+[package.dependencies]
+markdown-it-py = ">=2.2.0"
+pygments = ">=2.13.0,<3.0.0"
+
+[package.extras]
+jupyter = ["ipywidgets (>=7.5.1,<9)"]
+
+[[package]]
+name = "scikit-image"
+version = "0.23.2"
+description = "Image processing in Python"
+optional = false
+python-versions = ">=3.10"
+files = [
+ {file = "scikit_image-0.23.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9a8db6c52f8d0e1474ea8320d7b8db442b4d6baa29dd0acbd02f8a49572f18a"},
+ {file = "scikit_image-0.23.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:524b51a7440e46ed2ebbde7bc288bf2dde1dee2caafdd9513b2aca38a48223b7"},
+ {file = "scikit_image-0.23.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b335c229170d787b3fb8c60d220f72049ccf862d5191a3cfda6ac84b995ac4e"},
+ {file = "scikit_image-0.23.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08b10781efbd6b084f3c847ff4049b657241ea866b9e331b14bf791dcb3e6661"},
+ {file = "scikit_image-0.23.2-cp310-cp310-win_amd64.whl", hash = "sha256:a207352e9a1956dda1424bbe872c7795345187138118e8be6a421aef3b988c2a"},
+ {file = "scikit_image-0.23.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee83fdb1843ee938eabdfeb9498623282935ea30aa20dffc5d5d16698efb4b2a"},
+ {file = "scikit_image-0.23.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:a158f50d3df4867bbd1c698520ede8bc493e430ad83f54ac1f0d8f57b328779b"},
+ {file = "scikit_image-0.23.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55de3326be124334b89314e9e04c8971ad98d6681e11a243f71bfb85ef9554b0"},
+ {file = "scikit_image-0.23.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fce619a6d84fe40c1208fa579b646e93ce13ef0afc3652a23e9782b2c183291a"},
+ {file = "scikit_image-0.23.2-cp311-cp311-win_amd64.whl", hash = "sha256:ee65669aa586e110346f567ed5c92d1bd63799a19e951cb83da3f54b0caf7c52"},
+ {file = "scikit_image-0.23.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:15bfb4e8d7bd90a967e6a3c3ab6be678063fc45e950b730684a8db46a02ff892"},
+ {file = "scikit_image-0.23.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:5736e66d01b11cd90988ec24ab929c80a03af28f690189c951886891ebf63154"},
+ {file = "scikit_image-0.23.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3597ac5d8f51dafbcb7433ef1fdefdefb535f50745b2002ae0a5d651df4f063b"},
+ {file = "scikit_image-0.23.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1978be2abe3c3c3189a99a411d48bbb1306f7c2debb3aefbf426e23947f26623"},
+ {file = "scikit_image-0.23.2-cp312-cp312-win_amd64.whl", hash = "sha256:ae32bf0cb02b672ed74d28880ca6f88928ae8dd794d67e04fa3ff4836feb9bd6"},
+ {file = "scikit_image-0.23.2.tar.gz", hash = "sha256:c9da4b2c3117e3e30364a3d14496ee5c72b09eb1a4ab1292b302416faa360590"},
+]
+
+[package.dependencies]
+imageio = ">=2.33"
+lazy-loader = ">=0.4"
+networkx = ">=2.8"
+numpy = ">=1.23"
+packaging = ">=21"
+pillow = ">=9.1"
+scipy = ">=1.9"
+tifffile = ">=2022.8.12"
+
+[package.extras]
+build = ["Cython (>=3.0.4)", "build", "meson-python (>=0.15)", "ninja", "numpy (>=2.0.0rc1)", "packaging (>=21)", "pythran", "setuptools (>=67)", "spin (==0.8)", "wheel"]
+data = ["pooch (>=1.6.0)"]
+developer = ["ipython", "pre-commit", "tomli"]
+docs = ["PyWavelets (>=1.1.1)", "dask[array] (>=2022.9.2)", "ipykernel", "ipywidgets", "kaleido", "matplotlib (>=3.6)", "myst-parser", "numpydoc (>=1.7)", "pandas (>=1.5)", "plotly (>=5.10)", "pooch (>=1.6)", "pydata-sphinx-theme (>=0.15.2)", "pytest-doctestplus", "pytest-runner", "scikit-learn (>=1.1)", "seaborn (>=0.11)", "sphinx (>=7.3)", "sphinx-copybutton", "sphinx-gallery (>=0.14)", "sphinx_design (>=0.5)", "tifffile (>=2022.8.12)"]
+optional = ["PyWavelets (>=1.1.1)", "SimpleITK", "astropy (>=5.0)", "cloudpickle (>=0.2.1)", "dask[array] (>=2021.1.0)", "matplotlib (>=3.6)", "pooch (>=1.6.0)", "pyamg", "scikit-learn (>=1.1)"]
+test = ["asv", "numpydoc (>=1.7)", "pooch (>=1.6.0)", "pytest (>=7.0)", "pytest-cov (>=2.11.0)", "pytest-doctestplus", "pytest-faulthandler", "pytest-localserver"]
+
+[[package]]
+name = "scipy"
+version = "1.13.0"
+description = "Fundamental algorithms for scientific computing in Python"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "scipy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba419578ab343a4e0a77c0ef82f088238a93eef141b2b8017e46149776dfad4d"},
+ {file = "scipy-1.13.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:22789b56a999265431c417d462e5b7f2b487e831ca7bef5edeb56efe4c93f86e"},
+ {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05f1432ba070e90d42d7fd836462c50bf98bd08bed0aa616c359eed8a04e3922"},
+ {file = "scipy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8434f6f3fa49f631fae84afee424e2483289dfc30a47755b4b4e6b07b2633a4"},
+ {file = "scipy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:dcbb9ea49b0167de4167c40eeee6e167caeef11effb0670b554d10b1e693a8b9"},
+ {file = "scipy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:1d2f7bb14c178f8b13ebae93f67e42b0a6b0fc50eba1cd8021c9b6e08e8fb1cd"},
+ {file = "scipy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0fbcf8abaf5aa2dc8d6400566c1a727aed338b5fe880cde64907596a89d576fa"},
+ {file = "scipy-1.13.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5e4a756355522eb60fcd61f8372ac2549073c8788f6114449b37e9e8104f15a5"},
+ {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5acd8e1dbd8dbe38d0004b1497019b2dbbc3d70691e65d69615f8a7292865d7"},
+ {file = "scipy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ff7dad5d24a8045d836671e082a490848e8639cabb3dbdacb29f943a678683d"},
+ {file = "scipy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4dca18c3ffee287ddd3bc8f1dabaf45f5305c5afc9f8ab9cbfab855e70b2df5c"},
+ {file = "scipy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:a2f471de4d01200718b2b8927f7d76b5d9bde18047ea0fa8bd15c5ba3f26a1d6"},
+ {file = "scipy-1.13.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d0de696f589681c2802f9090fff730c218f7c51ff49bf252b6a97ec4a5d19e8b"},
+ {file = "scipy-1.13.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:b2a3ff461ec4756b7e8e42e1c681077349a038f0686132d623fa404c0bee2551"},
+ {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf9fe63e7a4bf01d3645b13ff2aa6dea023d38993f42aaac81a18b1bda7a82a"},
+ {file = "scipy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e7626dfd91cdea5714f343ce1176b6c4745155d234f1033584154f60ef1ff42"},
+ {file = "scipy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:109d391d720fcebf2fbe008621952b08e52907cf4c8c7efc7376822151820820"},
+ {file = "scipy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8930ae3ea371d6b91c203b1032b9600d69c568e537b7988a3073dfe4d4774f21"},
+ {file = "scipy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5407708195cb38d70fd2d6bb04b1b9dd5c92297d86e9f9daae1576bd9e06f602"},
+ {file = "scipy-1.13.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:ac38c4c92951ac0f729c4c48c9e13eb3675d9986cc0c83943784d7390d540c78"},
+ {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c74543c4fbeb67af6ce457f6a6a28e5d3739a87f62412e4a16e46f164f0ae5"},
+ {file = "scipy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28e286bf9ac422d6beb559bc61312c348ca9b0f0dae0d7c5afde7f722d6ea13d"},
+ {file = "scipy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33fde20efc380bd23a78a4d26d59fc8704e9b5fd9b08841693eb46716ba13d86"},
+ {file = "scipy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:45c08bec71d3546d606989ba6e7daa6f0992918171e2a6f7fbedfa7361c2de1e"},
+ {file = "scipy-1.13.0.tar.gz", hash = "sha256:58569af537ea29d3f78e5abd18398459f195546bb3be23d16677fb26616cc11e"},
+]
+
+[package.dependencies]
+numpy = ">=1.22.4,<2.3"
+
+[package.extras]
+dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"]
+doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"]
+test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
+
+[[package]]
+name = "setuptools"
+version = "69.5.1"
+description = "Easily download, build, install, upgrade, and uninstall Python packages"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "setuptools-69.5.1-py3-none-any.whl", hash = "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"},
+ {file = "setuptools-69.5.1.tar.gz", hash = "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987"},
+]
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+testing = ["build[virtualenv]", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "mypy (==1.9)", "packaging (>=23.2)", "pip (>=19.1)", "pytest (>=6,!=8.1.1)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.2.1)", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.2)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
+
+[[package]]
+name = "shellingham"
+version = "1.5.4"
+description = "Tool to Detect Surrounding Shell"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"},
+ {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
+]
+
+[[package]]
+name = "six"
+version = "1.16.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+files = [
+ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+
+[[package]]
+name = "stable-baselines3"
+version = "2.3.2"
+description = "Pytorch version of Stable Baselines, implementations of reinforcement learning algorithms."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "stable_baselines3-2.3.2-py3-none-any.whl", hash = "sha256:a1cafff6ec23bd4e8f4f20dd829008dc1af58ec2d5d8fc0cd0929b4b4544c9b2"},
+ {file = "stable_baselines3-2.3.2.tar.gz", hash = "sha256:2f8188916e607571c4c24f88a9ff6f84edafb2cf22d5d24f9c199563c12ff168"},
+]
+
+[package.dependencies]
+cloudpickle = "*"
+gymnasium = ">=0.28.1,<0.30"
+matplotlib = "*"
+numpy = ">=1.20"
+pandas = "*"
+torch = ">=1.13"
+
+[package.extras]
+docs = ["sphinx (>=5,<8)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-rtd-theme (>=1.3.0)", "sphinxcontrib.spelling"]
+extra = ["autorom[accept-rom-license] (>=0.6.1,<0.7.0)", "opencv-python", "pillow", "psutil", "pygame", "rich", "shimmy[atari] (>=1.3.0,<1.4.0)", "tensorboard (>=2.9.1)", "tqdm"]
+extra-no-roms = ["opencv-python", "pillow", "psutil", "pygame", "rich", "shimmy[atari] (>=1.3.0,<1.4.0)", "tensorboard (>=2.9.1)", "tqdm"]
+tests = ["black (>=24.2.0,<25)", "mypy", "pytest", "pytest-cov", "pytest-env", "pytest-xdist", "ruff (>=0.3.1)"]
+
+[[package]]
+name = "sympy"
+version = "1.12"
+description = "Computer algebra system (CAS) in Python"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"},
+ {file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"},
+]
+
+[package.dependencies]
+mpmath = ">=0.19"
+
+[[package]]
+name = "tbb"
+version = "2021.12.0"
+description = "Intel® oneAPI Threading Building Blocks (oneTBB)"
+optional = false
+python-versions = "*"
+files = [
+ {file = "tbb-2021.12.0-py2.py3-none-manylinux1_i686.whl", hash = "sha256:f2cc9a7f8ababaa506cbff796ce97c3bf91062ba521e15054394f773375d81d8"},
+ {file = "tbb-2021.12.0-py2.py3-none-manylinux1_x86_64.whl", hash = "sha256:a925e9a7c77d3a46ae31c34b0bb7f801c4118e857d137b68f68a8e458fcf2bd7"},
+ {file = "tbb-2021.12.0-py3-none-win32.whl", hash = "sha256:b1725b30c174048edc8be70bd43bb95473f396ce895d91151a474d0fa9f450a8"},
+ {file = "tbb-2021.12.0-py3-none-win_amd64.whl", hash = "sha256:fc2772d850229f2f3df85f1109c4844c495a2db7433d38200959ee9265b34789"},
+]
+
+[[package]]
+name = "tensorboard"
+version = "2.16.2"
+description = "TensorBoard lets you watch Tensors Flow"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "tensorboard-2.16.2-py3-none-any.whl", hash = "sha256:9f2b4e7dad86667615c0e5cd072f1ea8403fc032a299f0072d6f74855775cc45"},
+]
+
+[package.dependencies]
+absl-py = ">=0.4"
+grpcio = ">=1.48.2"
+markdown = ">=2.6.8"
+numpy = ">=1.12.0"
+protobuf = ">=3.19.6,<4.24.0 || >4.24.0"
+setuptools = ">=41.0.0"
+six = ">1.9"
+tensorboard-data-server = ">=0.7.0,<0.8.0"
+werkzeug = ">=1.0.1"
+
+[[package]]
+name = "tensorboard-data-server"
+version = "0.7.2"
+description = "Fast data loading for TensorBoard"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tensorboard_data_server-0.7.2-py3-none-any.whl", hash = "sha256:7e0610d205889588983836ec05dc098e80f97b7e7bbff7e994ebb78f578d0ddb"},
+ {file = "tensorboard_data_server-0.7.2-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9fe5d24221b29625dbc7328b0436ca7fc1c23de4acf4d272f1180856e32f9f60"},
+ {file = "tensorboard_data_server-0.7.2-py3-none-manylinux_2_31_x86_64.whl", hash = "sha256:ef687163c24185ae9754ed5650eb5bc4d84ff257aabdc33f0cc6f74d8ba54530"},
+]
+
+[[package]]
+name = "tifffile"
+version = "2024.5.10"
+description = "Read and write TIFF files"
+optional = false
+python-versions = ">=3.9"
+files = [
+ {file = "tifffile-2024.5.10-py3-none-any.whl", hash = "sha256:4154f091aa24d4e75bfad9ab2d5424a68c70e67b8220188066dc61946d4551bd"},
+ {file = "tifffile-2024.5.10.tar.gz", hash = "sha256:aa1e1b12be952ab20717d6848bd6d4a5ee88d2aa319f1152bff4354ad728ec86"},
+]
+
+[package.dependencies]
+numpy = "*"
+
+[package.extras]
+all = ["defusedxml", "fsspec", "imagecodecs (>=2023.8.12)", "lxml", "matplotlib", "zarr"]
+
+[[package]]
+name = "torch"
+version = "2.3.0"
+description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration"
+optional = false
+python-versions = ">=3.8.0"
+files = [
+ {file = "torch-2.3.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:d8ea5a465dbfd8501f33c937d1f693176c9aef9d1c1b0ca1d44ed7b0a18c52ac"},
+ {file = "torch-2.3.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:09c81c5859a5b819956c6925a405ef1cdda393c9d8a01ce3851453f699d3358c"},
+ {file = "torch-2.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:1bf023aa20902586f614f7682fedfa463e773e26c58820b74158a72470259459"},
+ {file = "torch-2.3.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:758ef938de87a2653bba74b91f703458c15569f1562bf4b6c63c62d9c5a0c1f5"},
+ {file = "torch-2.3.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:493d54ee2f9df100b5ce1d18c96dbb8d14908721f76351e908c9d2622773a788"},
+ {file = "torch-2.3.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:bce43af735c3da16cc14c7de2be7ad038e2fbf75654c2e274e575c6c05772ace"},
+ {file = "torch-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:729804e97b7cf19ae9ab4181f91f5e612af07956f35c8b2c8e9d9f3596a8e877"},
+ {file = "torch-2.3.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:d24e328226d8e2af7cf80fcb1d2f1d108e0de32777fab4aaa2b37b9765d8be73"},
+ {file = "torch-2.3.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:b0de2bdc0486ea7b14fc47ff805172df44e421a7318b7c4d92ef589a75d27410"},
+ {file = "torch-2.3.0-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:a306c87a3eead1ed47457822c01dfbd459fe2920f2d38cbdf90de18f23f72542"},
+ {file = "torch-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:f9b98bf1a3c8af2d4c41f0bf1433920900896c446d1ddc128290ff146d1eb4bd"},
+ {file = "torch-2.3.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:dca986214267b34065a79000cee54232e62b41dff1ec2cab9abc3fc8b3dee0ad"},
+ {file = "torch-2.3.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:20572f426965dd8a04e92a473d7e445fa579e09943cc0354f3e6fef6130ce061"},
+ {file = "torch-2.3.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:e65ba85ae292909cde0dde6369826d51165a3fc8823dc1854cd9432d7f79b932"},
+ {file = "torch-2.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:5515503a193781fd1b3f5c474e89c9dfa2faaa782b2795cc4a7ab7e67de923f6"},
+ {file = "torch-2.3.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:6ae9f64b09516baa4ef890af0672dc981c20b1f0d829ce115d4420a247e88fba"},
+ {file = "torch-2.3.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cd0dc498b961ab19cb3f8dbf0c6c50e244f2f37dbfa05754ab44ea057c944ef9"},
+ {file = "torch-2.3.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:e05f836559251e4096f3786ee99f4a8cbe67bc7fbedba8ad5e799681e47c5e80"},
+ {file = "torch-2.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:4fb27b35dbb32303c2927da86e27b54a92209ddfb7234afb1949ea2b3effffea"},
+ {file = "torch-2.3.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:760f8bedff506ce9e6e103498f9b1e9e15809e008368594c3a66bf74a8a51380"},
+]
+
+[package.dependencies]
+filelock = "*"
+fsspec = "*"
+jinja2 = "*"
+mkl = {version = ">=2021.1.1,<=2021.4.0", markers = "platform_system == \"Windows\""}
+networkx = "*"
+nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cudnn-cu12 = {version = "8.9.2.26", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-nccl-cu12 = {version = "2.20.5", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
+sympy = "*"
+triton = {version = "2.3.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\" and python_version < \"3.12\""}
+typing-extensions = ">=4.8.0"
+
+[package.extras]
+opt-einsum = ["opt-einsum (>=3.3)"]
+optree = ["optree (>=0.9.1)"]
+
+[[package]]
+name = "tqdm"
+version = "4.66.4"
+description = "Fast, Extensible Progress Meter"
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "tqdm-4.66.4-py3-none-any.whl", hash = "sha256:b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644"},
+ {file = "tqdm-4.66.4.tar.gz", hash = "sha256:e4d936c9de8727928f3be6079590e97d9abfe8d39a590be678eb5919ffc186bb"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[package.extras]
+dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"]
+notebook = ["ipywidgets (>=6)"]
+slack = ["slack-sdk"]
+telegram = ["requests"]
+
+[[package]]
+name = "triton"
+version = "2.3.0"
+description = "A language and compiler for custom Deep Learning operations"
+optional = false
+python-versions = "*"
+files = [
+ {file = "triton-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ce4b8ff70c48e47274c66f269cce8861cf1dc347ceeb7a67414ca151b1822d8"},
+ {file = "triton-2.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c3d9607f85103afdb279938fc1dd2a66e4f5999a58eb48a346bd42738f986dd"},
+ {file = "triton-2.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:218d742e67480d9581bafb73ed598416cc8a56f6316152e5562ee65e33de01c0"},
+ {file = "triton-2.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381ec6b3dac06922d3e4099cfc943ef032893b25415de295e82b1a82b0359d2c"},
+ {file = "triton-2.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:038e06a09c06a164fef9c48de3af1e13a63dc1ba3c792871e61a8e79720ea440"},
+ {file = "triton-2.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8f636e0341ac348899a47a057c3daea99ea7db31528a225a3ba4ded28ccc65"},
+]
+
+[package.dependencies]
+filelock = "*"
+
+[package.extras]
+build = ["cmake (>=3.20)", "lit"]
+tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)", "torch"]
+tutorials = ["matplotlib", "pandas", "tabulate", "torch"]
+
+[[package]]
+name = "typer"
+version = "0.12.3"
+description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
+optional = false
+python-versions = ">=3.7"
+files = [
+ {file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"},
+ {file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"},
+]
+
+[package.dependencies]
+click = ">=8.0.0"
+rich = ">=10.11.0"
+shellingham = ">=1.3.0"
+typing-extensions = ">=3.7.4.3"
+
+[[package]]
+name = "typing-extensions"
+version = "4.11.0"
+description = "Backported and Experimental Type Hints for Python 3.8+"
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"},
+ {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"},
+]
+
+[[package]]
+name = "tzdata"
+version = "2024.1"
+description = "Provider of IANA time zone data"
+optional = false
+python-versions = ">=2"
+files = [
+ {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"},
+ {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"},
+]
+
+[[package]]
+name = "urllib3"
+version = "2.2.1"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"},
+ {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"},
+]
+
+[package.extras]
+brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
+h2 = ["h2 (>=4,<5)"]
+socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
+zstd = ["zstandard (>=0.18.0)"]
+
+[[package]]
+name = "wasabi"
+version = "1.1.2"
+description = "A lightweight console printing and formatting toolkit"
+optional = false
+python-versions = ">=3.6"
+files = [
+ {file = "wasabi-1.1.2-py3-none-any.whl", hash = "sha256:0a3f933c4bf0ed3f93071132c1b87549733256d6c8de6473c5f7ed2e171b5cf9"},
+ {file = "wasabi-1.1.2.tar.gz", hash = "sha256:1aaef3aceaa32edb9c91330d29d3936c0c39fdb965743549c173cb54b16c30b5"},
+]
+
+[package.dependencies]
+colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\" and python_version >= \"3.7\""}
+
+[[package]]
+name = "werkzeug"
+version = "3.0.3"
+description = "The comprehensive WSGI web application library."
+optional = false
+python-versions = ">=3.8"
+files = [
+ {file = "werkzeug-3.0.3-py3-none-any.whl", hash = "sha256:fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8"},
+ {file = "werkzeug-3.0.3.tar.gz", hash = "sha256:097e5bfda9f0aba8da6b8545146def481d06aa7d3266e7448e2cccf67dd8bd18"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=2.1.1"
+
+[package.extras]
+watchdog = ["watchdog (>=2.3)"]
+
+[[package]]
+name = "wget"
+version = "3.2"
+description = "pure python download utility"
+optional = false
+python-versions = "*"
+files = [
+ {file = "wget-3.2.zip", hash = "sha256:35e630eca2aa50ce998b9b1a127bb26b30dfee573702782aa982f875e3f16061"},
+]
+
+[metadata]
+lock-version = "2.0"
+python-versions = "^3.11"
+content-hash = "2d575ca622be4eb61953716f1811accd9330cdbd4ad0ceee31700058e486e7e6"
diff --git a/policy.py b/policy.py
new file mode 100644
index 0000000..de39514
--- /dev/null
+++ b/policy.py
@@ -0,0 +1,131 @@
+import torch as T
+import torch.nn as nn
+
+policy_small=dict(
+ net_arch=dict(
+ pi=[256],
+ vf=[256]
+ )
+)
+
+policy_small_optim=dict(
+ net_arch=dict(
+ pi=[256],
+ vf=[256]
+ ),
+ optimizer_kwargs=dict(
+ betas=(0.9, 0.9),
+ eps=1e-5,
+ ),
+)
+
+policy_small_tanh=dict(
+ activation_fn=nn.Tanh,
+ net_arch=dict(
+ pi=[256],
+ vf=[256]
+ )
+)
+
+policy_small_optim_tanh=dict(
+ net_arch=dict(
+ pi=[256],
+ vf=[256]
+ ),
+ optimizer_class=T.optim.Adam,
+ optimizer_kwargs=dict(
+ betas=(0.9, 0.9),
+ eps=1e-5,
+ ),
+)
+
+policy_mid=dict(
+ net_arch=dict(
+ pi=[512],
+ vf=[2048, 2048]
+ )
+)
+
+policy_mid_tanh=dict(
+ activation_fn=nn.Tanh,
+ net_arch=dict(
+ pi=[512],
+ vf=[2048, 2048]
+ )
+)
+
+policy_mid_optim=dict(
+ net_arch=dict(
+ pi=[512],
+ vf=[2048, 2048]
+ ),
+ optimizer_kwargs=dict(
+ betas=(0.9,0.9),
+ eps=1e-5
+ )
+)
+
+policy_mid_optim_tanh=dict(
+ activation_fn=nn.Tanh,
+ net_arch=dict(
+ pi=[512],
+ vf=[2048, 2048]
+ ),
+ optimizer_kwargs=dict(
+ betas=(0.9,0.9),
+ eps=1e-5
+ )
+)
+
+policy_big=dict(
+ net_arch=dict(
+ pi=[1024, 1024],
+ vf=[4096, 4096, 4096, 4096]
+ )
+)
+
+policy_big_tanh=dict(
+ activation_fn=nn.Tanh,
+ net_arch=dict(
+ pi=[1024, 1024],
+ vf=[4096, 4096, 4096, 4096]
+ )
+)
+
+policy_big_optim=dict(
+ net_arch=dict(
+ pi=[1024, 1024],
+ vf=[4096, 4096, 4096, 4096]
+ ),
+ optimizer_kwargs=dict(
+ betas=(0.9, 0.9),
+ eps=1e-5,
+ ),
+)
+
+policy_big_optim_tanh = dict(
+ activation_fn=nn.Tanh,
+ net_arch=dict(
+ pi=[1024, 1024],
+ vf=[4096, 4096, 4096, 4096],
+ ),
+ optimizer_kwargs=dict(
+ betas=(0.9, 0.9),
+ eps=1e-5,
+ ),
+)
+
+policies={
+ "policy_small": policy_small,
+ "policy_small_optim": policy_small_optim,
+ "policy_small_tanh": policy_small_tanh,
+ "policy_small_optim_tanh": policy_small_optim_tanh,
+ "policy_mid": policy_mid,
+ "policy_mid_optim": policy_mid_optim,
+ "policy_mid_tanh": policy_mid_tanh,
+ "policy_mid_optim_tanh": policy_mid_optim_tanh,
+ "policy_big": policy_big,
+ "policy_big_optim": policy_big_optim,
+ "policy_big_tanh": policy_big_tanh,
+ "policy_big_optim_tanh": policy_big_optim_tanh,
+}
diff --git a/project.godot b/project.godot
new file mode 100644
index 0000000..896b36d
--- /dev/null
+++ b/project.godot
@@ -0,0 +1,70 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="Pneuma"
+run/main_scene="res://scenes/main.tscn"
+config/features=PackedStringArray("4.2", "Forward Plus")
+config/icon="res://icon.svg"
+
+[dotnet]
+
+project/assembly_name="Pneuma"
+
+[editor_plugins]
+
+enabled=PackedStringArray("res://addons/Todo_Manager/plugin.cfg", "res://addons/godot_rl_agents/plugin.cfg")
+
+[input]
+
+move_left={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+move_right={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+move_up={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+move_down={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+attack={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"echo":false,"script":null)
+]
+}
+cast_magic={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":81,"key_label":0,"unicode":113,"echo":false,"script":null)
+]
+}
+reset_camera={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+
+[rendering]
+
+textures/canvas_textures/default_texture_filter=0
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..d49e673
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,22 @@
+[tool.poetry]
+name = "pneumarl"
+version = "0.1.0"
+description = "Godot training env for MARL"
+authors = ["Vasilis Valatsos "]
+readme = "README.md"
+package-mode = false
+
+[tool.poetry.dependencies]
+python = "^3.11"
+dm-tree = "^0.1.8"
+typer = "^0.12.3"
+scikit-image = "^0.23.2"
+lz4 = "^4.3.3"
+godot-rl = {url = "https://github.com/edbeeching/godot_rl_agents/archive/refs/heads/main.zip"}
+pettingzoo = "^1.24.3"
+tensorboard = "^2.16.2"
+
+
+[build-system]
+requires = ["poetry-core"]
+build-backend = "poetry.core.masonry.api"
diff --git a/rllib_config.yaml b/rllib_config.yaml
new file mode 100644
index 0000000..c105612
--- /dev/null
+++ b/rllib_config.yaml
@@ -0,0 +1,60 @@
+algorithm: PPO
+
+# Multi-agent-env setting:
+# If true:
+# - Any AIController with done = true will receive zeroes as action values until all AIControllers are done, an episode ends at that point.
+# - ai_controller.needs_reset will also be set to true every time a new episode begins (but you can ignore it in your env if needed).
+# If false:
+# - AIControllers auto-reset in Godot and will receive actions after setting done = true.
+# - Each AIController has its own episodes that can end/reset at any point.
+# Set to false if you have a single policy name for all agents set in AIControllers
+env_is_multiagent: false
+
+checkpoint_frequency: 20
+
+# You can set one or more stopping criteria
+stop:
+ #episode_reward_mean: 0
+ #training_iteration: 1000
+ #timesteps_total: 10000
+ time_total_s: 10000000
+
+config:
+ env: godot
+ env_config:
+ env_path: '/home/valapeos/Projects/pneumarl/pneuma.x86_64' # Set your env path here (exported executable from Godot) - e.g. env_path: 'env_path.exe' on Windows
+ action_repeat: null # Doesn't need to be set here, you can set this in sync node in Godot editor as well
+ show_window: true # Displays game window while training. Might be faster when false in some cases, turning off also reduces GPU usage if you don't need rendering.
+ speedup: 30 # Speeds up Godot physics
+
+ framework: torch # ONNX models exported with torch are compatible with the current Godot RL Agents Plugin
+
+ lr: 0.0003
+ lambda: 0.95
+ gamma: 0.99
+
+ vf_loss_coeff: 0.5
+ vf_clip_param: .inf
+ #clip_param: 0.2
+ entropy_coeff: 0.0001
+ entropy_coeff_schedule: null
+ #grad_clip: 0.5
+
+ normalize_actions: False
+ clip_actions: True # During onnx inference we simply clip the actions to [-1.0, 1.0] range, set here to match
+
+ rollout_fragment_length: 32
+ sgd_minibatch_size: 128
+ num_workers: 4
+ num_envs_per_worker: 1 # This will be set automatically if not multi-agent. If multi-agent, changing this changes how many envs to launch per worker.
+ # The value below needs changing per env
+ # Basic calculation for this value can be rollout_fragment_length * num_workers * num_envs_per_worker (how many AIControllers you have if not multi_agent, otherwise the value you set)
+ train_batch_size: 2048
+
+ num_sgd_iter: 4
+ batch_mode: truncate_episodes
+
+ num_gpus: 0
+ model:
+ vf_share_layers: False
+ fcnet_hiddens: [64, 64]
diff --git a/run_tests.sh b/run_tests.sh
new file mode 100755
index 0000000..e6597f2
--- /dev/null
+++ b/run_tests.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+python main.py --env_path="/home/valapeos/Projects/thesis/Godot/pneuma.x86_64" --speedup=200 --n_parallel=4 --exper_dir="logs/sb3_full_1" &&
+
+python main.py --env_path="/home/valapeos/Projects/thesis/Godot/pneuma.x86_64" --speedup=200 --n_parallel=4 --exper_dir="logs/sb3_full_2" &&
+
+python main.py --env_path="/home/valapeos/Projects/thesis/Godot/pneuma.x86_64" --speedup=200 --n_parallel=4 --exper_dir="logs/sb3_full_3" &&
+
+python main.py --env_path="/home/valapeos/Projects/thesis/Godot/pneuma.x86_64" --speedup=200 --n_parallel=4 --exper_dir="logs/sb3_full_4"
diff --git a/scenes/attack.tscn b/scenes/attack.tscn
new file mode 100644
index 0000000..616dc07
--- /dev/null
+++ b/scenes/attack.tscn
@@ -0,0 +1,4 @@
+[gd_scene format=3 uid="uid://c1i0nirxfagfh"]
+
+[node name="Attack" type="Area2D"]
+collision_mask = 2
diff --git a/scenes/bamboo.tscn b/scenes/bamboo.tscn
new file mode 100644
index 0000000..348bf2c
--- /dev/null
+++ b/scenes/bamboo.tscn
@@ -0,0 +1,249 @@
+[gd_scene load_steps=20 format=3 uid="uid://bsjy4oejfrg81"]
+
+[ext_resource type="Texture2D" uid="uid://d4d34das0e3j0" path="res://assets/graphics/monsters/bamboo/idle/0.png" id="1_em175"]
+[ext_resource type="Texture2D" uid="uid://l0bk7j8xiqur" path="res://assets/graphics/monsters/bamboo/idle/1.png" id="2_i1h6v"]
+[ext_resource type="Texture2D" uid="uid://bwe7pi6shcc2x" path="res://assets/graphics/monsters/bamboo/attack/0.png" id="2_tihvn"]
+[ext_resource type="Texture2D" uid="uid://damt0mr2bvcjv" path="res://assets/graphics/monsters/bamboo/idle/2.png" id="3_5ekod"]
+[ext_resource type="Texture2D" uid="uid://b11yb3x6h5oas" path="res://assets/graphics/monsters/bamboo/idle/3.png" id="4_0fhpn"]
+[ext_resource type="Script" path="res://code/bamboo.gd" id="5_ib85v"]
+[ext_resource type="Texture2D" uid="uid://q8yev438ec6r" path="res://assets/graphics/monsters/bamboo/move/0.png" id="7_8n247"]
+[ext_resource type="Texture2D" uid="uid://dqr075ilm3tu8" path="res://assets/graphics/monsters/bamboo/move/1.png" id="8_c5akp"]
+[ext_resource type="Texture2D" uid="uid://hcm2s3v12pkw" path="res://assets/graphics/monsters/bamboo/move/2.png" id="9_t18yx"]
+[ext_resource type="Texture2D" uid="uid://dqa5hvprf3kdp" path="res://assets/graphics/monsters/bamboo/move/3.png" id="10_gsrg3"]
+[ext_resource type="PackedScene" uid="uid://dxwjan054vgw0" path="res://scenes/notice.tscn" id="11_d502u"]
+[ext_resource type="PackedScene" uid="uid://c1i0nirxfagfh" path="res://scenes/attack.tscn" id="12_27c4n"]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_iyhjt"]
+size = Vector2(24, 50)
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_wx6w8"]
+radius = 300.0
+
+[sub_resource type="CircleShape2D" id="CircleShape2D_crbjt"]
+radius = 40.0
+
+[sub_resource type="SpriteFrames" id="SpriteFrames_2w0pn"]
+animations = [{
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("2_tihvn")
+}],
+"loop": true,
+"name": &"attack",
+"speed": 7.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("1_em175")
+}, {
+"duration": 1.0,
+"texture": ExtResource("2_i1h6v")
+}, {
+"duration": 1.0,
+"texture": ExtResource("3_5ekod")
+}, {
+"duration": 1.0,
+"texture": ExtResource("4_0fhpn")
+}],
+"loop": true,
+"name": &"idle",
+"speed": 7.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("7_8n247")
+}, {
+"duration": 1.0,
+"texture": ExtResource("8_c5akp")
+}, {
+"duration": 1.0,
+"texture": ExtResource("9_t18yx")
+}, {
+"duration": 1.0,
+"texture": ExtResource("10_gsrg3")
+}],
+"loop": true,
+"name": &"move",
+"speed": 7.0
+}]
+
+[sub_resource type="Animation" id="Animation_lrur3"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("CollisionShape2D:disabled")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:visible")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [true]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Attack:monitoring")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [true]
+}
+tracks/3/type = "value"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("Notice:monitoring")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [true]
+}
+tracks/4/type = "value"
+tracks/4/imported = false
+tracks/4/enabled = true
+tracks/4/path = NodePath(".:collision_mask")
+tracks/4/interp = 1
+tracks/4/loop_wrap = true
+tracks/4/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [6]
+}
+
+[sub_resource type="Animation" id="Animation_3xlxe"]
+resource_name = "death"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("CollisionShape2D:disabled")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [true]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath(".:visible")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/2/type = "value"
+tracks/2/imported = false
+tracks/2/enabled = true
+tracks/2/path = NodePath("Attack:monitoring")
+tracks/2/interp = 1
+tracks/2/loop_wrap = true
+tracks/2/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/3/type = "value"
+tracks/3/imported = false
+tracks/3/enabled = true
+tracks/3/path = NodePath("Notice:monitoring")
+tracks/3/interp = 1
+tracks/3/loop_wrap = true
+tracks/3/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/4/type = "value"
+tracks/4/imported = false
+tracks/4/enabled = true
+tracks/4/path = NodePath(".:collision_mask")
+tracks/4/interp = 1
+tracks/4/loop_wrap = true
+tracks/4/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [0]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_ftwl3"]
+_data = {
+"RESET": SubResource("Animation_lrur3"),
+"death": SubResource("Animation_3xlxe")
+}
+
+[node name="Bamboo" type="CharacterBody2D"]
+z_index = 5
+y_sort_enabled = true
+position = Vector2(0, -33)
+collision_layer = 4
+collision_mask = 6
+script = ExtResource("5_ib85v")
+health = 40
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(0, 2)
+shape = SubResource("RectangleShape2D_iyhjt")
+
+[node name="Notice" parent="." instance=ExtResource("11_d502u")]
+position = Vector2(0, 7)
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Notice"]
+shape = SubResource("CircleShape2D_wx6w8")
+
+[node name="Attack" parent="." instance=ExtResource("12_27c4n")]
+position = Vector2(0, 5)
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Attack"]
+shape = SubResource("CircleShape2D_crbjt")
+
+[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
+sprite_frames = SubResource("SpriteFrames_2w0pn")
+animation = &"idle"
+autoplay = "idle"
+
+[node name="AttackTimer" type="Timer" parent="."]
+
+[node name="KnockbackTimer" type="Timer" parent="."]
+wait_time = 0.5
+one_shot = true
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+libraries = {
+"": SubResource("AnimationLibrary_ftwl3")
+}
+
+[connection signal="death" from="." to="." method="_on_death"]
+[connection signal="body_entered" from="Notice" to="." method="_on_notice_body_entered"]
+[connection signal="body_exited" from="Notice" to="." method="_on_notice_body_exited"]
+[connection signal="body_entered" from="Attack" to="." method="_on_attack_body_entered"]
+[connection signal="body_exited" from="Attack" to="." method="_on_attack_body_exited"]
+[connection signal="timeout" from="AttackTimer" to="." method="_on_attack_timer_timeout"]
+[connection signal="timeout" from="KnockbackTimer" to="." method="_on_knockback_timer_timeout"]
diff --git a/scenes/camera.tscn b/scenes/camera.tscn
new file mode 100644
index 0000000..5526776
--- /dev/null
+++ b/scenes/camera.tscn
@@ -0,0 +1,51 @@
+[gd_scene load_steps=3 format=3 uid="uid://bj4ap7bw0imhy"]
+
+[ext_resource type="FontFile" uid="uid://bbe5csaxy5g3c" path="res://assets/graphics/font/joystix.ttf" id="1_kqyoj"]
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_0lqnv"]
+bg_color = Color(0, 0, 0, 1)
+border_width_left = 4
+border_width_top = 4
+border_width_right = 4
+border_width_bottom = 4
+border_color = Color(1, 1, 1, 1)
+
+[node name="Camera" type="Camera2D"]
+
+[node name="ExpPanel" type="PanelContainer" parent="."]
+offset_left = 187.0
+offset_top = 227.0
+offset_right = 568.0
+offset_bottom = 316.0
+theme_override_styles/panel = SubResource("StyleBoxFlat_0lqnv")
+
+[node name="ExpLabel" type="Label" parent="ExpPanel"]
+layout_mode = 2
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 8
+theme_override_fonts/font = ExtResource("1_kqyoj")
+theme_override_font_sizes/font_size = 32
+text = "EXP POINTS
+ "
+horizontal_alignment = 1
+vertical_alignment = 1
+max_lines_visible = 2
+
+[node name="HPPanel" type="PanelContainer" parent="."]
+offset_left = -569.0
+offset_top = 223.0
+offset_right = -188.0
+offset_bottom = 318.0
+theme_override_styles/panel = SubResource("StyleBoxFlat_0lqnv")
+
+[node name="HPLabel" type="Label" parent="HPPanel"]
+layout_mode = 2
+theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
+theme_override_constants/outline_size = 8
+theme_override_fonts/font = ExtResource("1_kqyoj")
+theme_override_font_sizes/font_size = 32
+text = "HEALTH
+"
+horizontal_alignment = 1
+vertical_alignment = 1
+max_lines_visible = 2
diff --git a/scenes/killzone.tscn b/scenes/killzone.tscn
new file mode 100644
index 0000000..d88fa05
--- /dev/null
+++ b/scenes/killzone.tscn
@@ -0,0 +1,13 @@
+[gd_scene load_steps=2 format=3 uid="uid://cuvs5tobahf0x"]
+
+[ext_resource type="Script" path="res://code/killzone.gd" id="1_nmw5v"]
+
+[node name="Killzone" type="Area2D"]
+script = ExtResource("1_nmw5v")
+
+[node name="Timer" type="Timer" parent="."]
+wait_time = 0.6
+one_shot = true
+
+[connection signal="body_entered" from="." to="." method="_on_body_entered"]
+[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
diff --git a/scenes/main.tscn b/scenes/main.tscn
new file mode 100644
index 0000000..c7acd44
--- /dev/null
+++ b/scenes/main.tscn
@@ -0,0 +1,1406 @@
+[gd_scene load_steps=16 format=3 uid="uid://ldrqgub8ip13"]
+
+[ext_resource type="Script" path="res://code/main.gd" id="1_l8nqt"]
+[ext_resource type="PackedScene" uid="uid://c7rps714eqdg5" path="res://scenes/player.tscn" id="1_ykwem"]
+[ext_resource type="Texture2D" uid="uid://bd03f5p0dd3em" path="res://assets/graphics/tilemap/Floor.png" id="2_2lxw0"]
+[ext_resource type="Texture2D" uid="uid://b5qncrso5bd14" path="res://assets/graphics/tilemap/details.png" id="3_72u1m"]
+[ext_resource type="PackedScene" uid="uid://bsjy4oejfrg81" path="res://scenes/bamboo.tscn" id="4_8jerw"]
+[ext_resource type="PackedScene" uid="uid://cuvs5tobahf0x" path="res://scenes/killzone.tscn" id="5_3xrri"]
+[ext_resource type="Script" path="res://addons/godot_rl_agents/sync.gd" id="7_c27o5"]
+
+[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_auqfk"]
+texture = ExtResource("2_2lxw0")
+texture_region_size = Vector2i(64, 64)
+0:0/0 = 0
+0:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:0/0/physics_layer_0/angular_velocity = 0.0
+1:0/0 = 0
+1:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:0/0/physics_layer_0/angular_velocity = 0.0
+2:0/0 = 0
+2:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:0/0/physics_layer_0/angular_velocity = 0.0
+3:0/0 = 0
+3:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:0/0/physics_layer_0/angular_velocity = 0.0
+4:0/0 = 0
+4:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:0/0/physics_layer_0/angular_velocity = 0.0
+5:0/0 = 0
+5:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:0/0/physics_layer_0/angular_velocity = 0.0
+6:0/0 = 0
+6:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:0/0/physics_layer_0/angular_velocity = 0.0
+7:0/0 = 0
+7:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:0/0/physics_layer_0/angular_velocity = 0.0
+8:0/0 = 0
+8:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:0/0/physics_layer_0/angular_velocity = 0.0
+9:0/0 = 0
+9:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:0/0/physics_layer_0/angular_velocity = 0.0
+11:0/0 = 0
+11:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+11:0/0/physics_layer_0/angular_velocity = 0.0
+11:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+12:0/0 = 0
+12:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+12:0/0/physics_layer_0/angular_velocity = 0.0
+12:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+13:0/0 = 0
+13:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:0/0/physics_layer_0/angular_velocity = 0.0
+13:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+14:0/0 = 0
+14:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:0/0/physics_layer_0/angular_velocity = 0.0
+15:0/0 = 0
+15:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:0/0/physics_layer_0/angular_velocity = 0.0
+16:0/0 = 0
+16:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:0/0/physics_layer_0/angular_velocity = 0.0
+17:0/0 = 0
+17:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:0/0/physics_layer_0/angular_velocity = 0.0
+18:0/0 = 0
+18:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:0/0/physics_layer_0/angular_velocity = 0.0
+19:0/0 = 0
+19:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:0/0/physics_layer_0/angular_velocity = 0.0
+20:0/0 = 0
+20:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:0/0/physics_layer_0/angular_velocity = 0.0
+0:1/0 = 0
+0:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:1/0/physics_layer_0/angular_velocity = 0.0
+1:1/0 = 0
+1:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:1/0/physics_layer_0/angular_velocity = 0.0
+2:1/0 = 0
+2:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:1/0/physics_layer_0/angular_velocity = 0.0
+3:1/0 = 0
+3:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:1/0/physics_layer_0/angular_velocity = 0.0
+4:1/0 = 0
+4:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:1/0/physics_layer_0/angular_velocity = 0.0
+5:1/0 = 0
+5:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:1/0/physics_layer_0/angular_velocity = 0.0
+6:1/0 = 0
+6:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:1/0/physics_layer_0/angular_velocity = 0.0
+7:1/0 = 0
+7:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:1/0/physics_layer_0/angular_velocity = 0.0
+8:1/0 = 0
+8:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:1/0/physics_layer_0/angular_velocity = 0.0
+9:1/0 = 0
+9:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:1/0/physics_layer_0/angular_velocity = 0.0
+11:1/0 = 0
+11:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+11:1/0/physics_layer_0/angular_velocity = 0.0
+11:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+12:1/0 = 0
+12:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+12:1/0/physics_layer_0/angular_velocity = 0.0
+13:1/0 = 0
+13:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:1/0/physics_layer_0/angular_velocity = 0.0
+13:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+14:1/0 = 0
+14:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:1/0/physics_layer_0/angular_velocity = 0.0
+15:1/0 = 0
+15:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:1/0/physics_layer_0/angular_velocity = 0.0
+16:1/0 = 0
+16:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:1/0/physics_layer_0/angular_velocity = 0.0
+16:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+17:1/0 = 0
+17:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:1/0/physics_layer_0/angular_velocity = 0.0
+17:1/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+18:1/0 = 0
+18:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:1/0/physics_layer_0/angular_velocity = 0.0
+19:1/0 = 0
+19:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:1/0/physics_layer_0/angular_velocity = 0.0
+20:1/0 = 0
+20:1/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:1/0/physics_layer_0/angular_velocity = 0.0
+0:2/0 = 0
+0:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:2/0/physics_layer_0/angular_velocity = 0.0
+1:2/0 = 0
+1:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:2/0/physics_layer_0/angular_velocity = 0.0
+2:2/0 = 0
+2:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:2/0/physics_layer_0/angular_velocity = 0.0
+3:2/0 = 0
+3:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:2/0/physics_layer_0/angular_velocity = 0.0
+4:2/0 = 0
+4:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:2/0/physics_layer_0/angular_velocity = 0.0
+5:2/0 = 0
+5:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:2/0/physics_layer_0/angular_velocity = 0.0
+6:2/0 = 0
+6:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:2/0/physics_layer_0/angular_velocity = 0.0
+7:2/0 = 0
+7:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:2/0/physics_layer_0/angular_velocity = 0.0
+8:2/0 = 0
+8:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:2/0/physics_layer_0/angular_velocity = 0.0
+9:2/0 = 0
+9:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:2/0/physics_layer_0/angular_velocity = 0.0
+10:2/0 = 0
+10:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:2/0/physics_layer_0/angular_velocity = 0.0
+11:2/0 = 0
+11:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+11:2/0/physics_layer_0/angular_velocity = 0.0
+11:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+12:2/0 = 0
+12:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+12:2/0/physics_layer_0/angular_velocity = 0.0
+12:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+13:2/0 = 0
+13:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:2/0/physics_layer_0/angular_velocity = 0.0
+13:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+14:2/0 = 0
+14:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:2/0/physics_layer_0/angular_velocity = 0.0
+15:2/0 = 0
+15:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:2/0/physics_layer_0/angular_velocity = 0.0
+16:2/0 = 0
+16:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:2/0/physics_layer_0/angular_velocity = 0.0
+16:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+17:2/0 = 0
+17:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:2/0/physics_layer_0/angular_velocity = 0.0
+17:2/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+18:2/0 = 0
+18:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:2/0/physics_layer_0/angular_velocity = 0.0
+19:2/0 = 0
+19:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:2/0/physics_layer_0/angular_velocity = 0.0
+20:2/0 = 0
+20:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:2/0/physics_layer_0/angular_velocity = 0.0
+21:2/0 = 0
+21:2/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:2/0/physics_layer_0/angular_velocity = 0.0
+0:3/0 = 0
+0:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:3/0/physics_layer_0/angular_velocity = 0.0
+1:3/0 = 0
+1:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:3/0/physics_layer_0/angular_velocity = 0.0
+2:3/0 = 0
+2:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:3/0/physics_layer_0/angular_velocity = 0.0
+3:3/0 = 0
+3:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:3/0/physics_layer_0/angular_velocity = 0.0
+4:3/0 = 0
+4:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:3/0/physics_layer_0/angular_velocity = 0.0
+5:3/0 = 0
+5:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:3/0/physics_layer_0/angular_velocity = 0.0
+6:3/0 = 0
+6:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:3/0/physics_layer_0/angular_velocity = 0.0
+7:3/0 = 0
+7:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:3/0/physics_layer_0/angular_velocity = 0.0
+8:3/0 = 0
+8:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:3/0/physics_layer_0/angular_velocity = 0.0
+9:3/0 = 0
+9:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:3/0/physics_layer_0/angular_velocity = 0.0
+10:3/0 = 0
+10:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:3/0/physics_layer_0/angular_velocity = 0.0
+11:3/0 = 0
+11:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+11:3/0/physics_layer_0/angular_velocity = 0.0
+12:3/0 = 0
+12:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+12:3/0/physics_layer_0/angular_velocity = 0.0
+13:3/0 = 0
+13:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:3/0/physics_layer_0/angular_velocity = 0.0
+14:3/0 = 0
+14:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:3/0/physics_layer_0/angular_velocity = 0.0
+15:3/0 = 0
+15:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:3/0/physics_layer_0/angular_velocity = 0.0
+16:3/0 = 0
+16:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:3/0/physics_layer_0/angular_velocity = 0.0
+17:3/0 = 0
+17:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:3/0/physics_layer_0/angular_velocity = 0.0
+18:3/0 = 0
+18:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:3/0/physics_layer_0/angular_velocity = 0.0
+19:3/0 = 0
+19:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:3/0/physics_layer_0/angular_velocity = 0.0
+20:3/0 = 0
+20:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:3/0/physics_layer_0/angular_velocity = 0.0
+21:3/0 = 0
+21:3/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:3/0/physics_layer_0/angular_velocity = 0.0
+0:4/0 = 0
+0:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:4/0/physics_layer_0/angular_velocity = 0.0
+1:4/0 = 0
+1:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:4/0/physics_layer_0/angular_velocity = 0.0
+4:4/0 = 0
+4:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:4/0/physics_layer_0/angular_velocity = 0.0
+5:4/0 = 0
+5:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:4/0/physics_layer_0/angular_velocity = 0.0
+6:4/0 = 0
+6:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:4/0/physics_layer_0/angular_velocity = 0.0
+7:4/0 = 0
+7:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:4/0/physics_layer_0/angular_velocity = 0.0
+8:4/0 = 0
+8:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:4/0/physics_layer_0/angular_velocity = 0.0
+15:4/0 = 0
+15:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:4/0/physics_layer_0/angular_velocity = 0.0
+16:4/0 = 0
+16:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:4/0/physics_layer_0/angular_velocity = 0.0
+17:4/0 = 0
+17:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:4/0/physics_layer_0/angular_velocity = 0.0
+18:4/0 = 0
+18:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:4/0/physics_layer_0/angular_velocity = 0.0
+19:4/0 = 0
+19:4/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:4/0/physics_layer_0/angular_velocity = 0.0
+0:5/0 = 0
+0:5/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:5/0/physics_layer_0/angular_velocity = 0.0
+1:5/0 = 0
+1:5/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:5/0/physics_layer_0/angular_velocity = 0.0
+2:5/0 = 0
+2:5/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:5/0/physics_layer_0/angular_velocity = 0.0
+3:5/0 = 0
+3:5/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:5/0/physics_layer_0/angular_velocity = 0.0
+4:5/0 = 0
+4:5/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:5/0/physics_layer_0/angular_velocity = 0.0
+11:5/0 = 0
+11:5/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+11:5/0/physics_layer_0/angular_velocity = 0.0
+0:6/0 = 0
+0:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:6/0/physics_layer_0/angular_velocity = 0.0
+1:6/0 = 0
+1:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:6/0/physics_layer_0/angular_velocity = 0.0
+2:6/0 = 0
+2:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:6/0/physics_layer_0/angular_velocity = 0.0
+3:6/0 = 0
+3:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:6/0/physics_layer_0/angular_velocity = 0.0
+4:6/0 = 0
+4:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:6/0/physics_layer_0/angular_velocity = 0.0
+5:6/0 = 0
+5:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:6/0/physics_layer_0/angular_velocity = 0.0
+11:6/0 = 0
+11:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+11:6/0/physics_layer_0/angular_velocity = 0.0
+11:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+12:6/0 = 0
+12:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+12:6/0/physics_layer_0/angular_velocity = 0.0
+12:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+13:6/0 = 0
+13:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:6/0/physics_layer_0/angular_velocity = 0.0
+13:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+14:6/0 = 0
+14:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:6/0/physics_layer_0/angular_velocity = 0.0
+15:6/0 = 0
+15:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:6/0/physics_layer_0/angular_velocity = 0.0
+16:6/0 = 0
+16:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:6/0/physics_layer_0/angular_velocity = 0.0
+17:6/0 = 0
+17:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:6/0/physics_layer_0/angular_velocity = 0.0
+18:6/0 = 0
+18:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:6/0/physics_layer_0/angular_velocity = 0.0
+19:6/0 = 0
+19:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:6/0/physics_layer_0/angular_velocity = 0.0
+20:6/0 = 0
+20:6/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:6/0/physics_layer_0/angular_velocity = 0.0
+0:7/0 = 0
+0:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:7/0/physics_layer_0/angular_velocity = 0.0
+1:7/0 = 0
+1:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:7/0/physics_layer_0/angular_velocity = 0.0
+2:7/0 = 0
+2:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:7/0/physics_layer_0/angular_velocity = 0.0
+3:7/0 = 0
+3:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:7/0/physics_layer_0/angular_velocity = 0.0
+4:7/0 = 0
+4:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:7/0/physics_layer_0/angular_velocity = 0.0
+5:7/0 = 0
+5:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:7/0/physics_layer_0/angular_velocity = 0.0
+6:7/0 = 0
+6:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:7/0/physics_layer_0/angular_velocity = 0.0
+7:7/0 = 0
+7:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:7/0/physics_layer_0/angular_velocity = 0.0
+8:7/0 = 0
+8:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:7/0/physics_layer_0/angular_velocity = 0.0
+9:7/0 = 0
+9:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:7/0/physics_layer_0/angular_velocity = 0.0
+11:7/0 = 0
+11:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+11:7/0/physics_layer_0/angular_velocity = 0.0
+11:7/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+12:7/0 = 0
+12:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+12:7/0/physics_layer_0/angular_velocity = 0.0
+13:7/0 = 0
+13:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:7/0/physics_layer_0/angular_velocity = 0.0
+13:7/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+14:7/0 = 0
+14:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:7/0/physics_layer_0/angular_velocity = 0.0
+15:7/0 = 0
+15:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:7/0/physics_layer_0/angular_velocity = 0.0
+16:7/0 = 0
+16:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:7/0/physics_layer_0/angular_velocity = 0.0
+16:7/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+17:7/0 = 0
+17:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:7/0/physics_layer_0/angular_velocity = 0.0
+17:7/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+18:7/0 = 0
+18:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:7/0/physics_layer_0/angular_velocity = 0.0
+19:7/0 = 0
+19:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:7/0/physics_layer_0/angular_velocity = 0.0
+20:7/0 = 0
+20:7/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:7/0/physics_layer_0/angular_velocity = 0.0
+0:8/0 = 0
+0:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:8/0/physics_layer_0/angular_velocity = 0.0
+1:8/0 = 0
+1:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:8/0/physics_layer_0/angular_velocity = 0.0
+2:8/0 = 0
+2:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:8/0/physics_layer_0/angular_velocity = 0.0
+3:8/0 = 0
+3:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:8/0/physics_layer_0/angular_velocity = 0.0
+4:8/0 = 0
+4:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:8/0/physics_layer_0/angular_velocity = 0.0
+5:8/0 = 0
+5:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:8/0/physics_layer_0/angular_velocity = 0.0
+6:8/0 = 0
+6:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:8/0/physics_layer_0/angular_velocity = 0.0
+7:8/0 = 0
+7:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:8/0/physics_layer_0/angular_velocity = 0.0
+8:8/0 = 0
+8:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:8/0/physics_layer_0/angular_velocity = 0.0
+9:8/0 = 0
+9:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:8/0/physics_layer_0/angular_velocity = 0.0
+11:8/0 = 0
+11:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+11:8/0/physics_layer_0/angular_velocity = 0.0
+11:8/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+12:8/0 = 0
+12:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+12:8/0/physics_layer_0/angular_velocity = 0.0
+12:8/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+13:8/0 = 0
+13:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:8/0/physics_layer_0/angular_velocity = 0.0
+13:8/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+14:8/0 = 0
+14:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:8/0/physics_layer_0/angular_velocity = 0.0
+15:8/0 = 0
+15:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:8/0/physics_layer_0/angular_velocity = 0.0
+16:8/0 = 0
+16:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:8/0/physics_layer_0/angular_velocity = 0.0
+16:8/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+17:8/0 = 0
+17:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:8/0/physics_layer_0/angular_velocity = 0.0
+17:8/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+18:8/0 = 0
+18:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:8/0/physics_layer_0/angular_velocity = 0.0
+19:8/0 = 0
+19:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:8/0/physics_layer_0/angular_velocity = 0.0
+20:8/0 = 0
+20:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:8/0/physics_layer_0/angular_velocity = 0.0
+21:8/0 = 0
+21:8/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:8/0/physics_layer_0/angular_velocity = 0.0
+0:9/0 = 0
+0:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:9/0/physics_layer_0/angular_velocity = 0.0
+1:9/0 = 0
+1:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:9/0/physics_layer_0/angular_velocity = 0.0
+2:9/0 = 0
+2:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:9/0/physics_layer_0/angular_velocity = 0.0
+3:9/0 = 0
+3:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:9/0/physics_layer_0/angular_velocity = 0.0
+4:9/0 = 0
+4:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:9/0/physics_layer_0/angular_velocity = 0.0
+5:9/0 = 0
+5:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:9/0/physics_layer_0/angular_velocity = 0.0
+6:9/0 = 0
+6:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:9/0/physics_layer_0/angular_velocity = 0.0
+7:9/0 = 0
+7:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:9/0/physics_layer_0/angular_velocity = 0.0
+8:9/0 = 0
+8:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:9/0/physics_layer_0/angular_velocity = 0.0
+9:9/0 = 0
+9:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:9/0/physics_layer_0/angular_velocity = 0.0
+10:9/0 = 0
+10:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:9/0/physics_layer_0/angular_velocity = 0.0
+11:9/0 = 0
+11:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+11:9/0/physics_layer_0/angular_velocity = 0.0
+12:9/0 = 0
+12:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+12:9/0/physics_layer_0/angular_velocity = 0.0
+13:9/0 = 0
+13:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:9/0/physics_layer_0/angular_velocity = 0.0
+14:9/0 = 0
+14:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:9/0/physics_layer_0/angular_velocity = 0.0
+15:9/0 = 0
+15:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:9/0/physics_layer_0/angular_velocity = 0.0
+16:9/0 = 0
+16:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:9/0/physics_layer_0/angular_velocity = 0.0
+17:9/0 = 0
+17:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:9/0/physics_layer_0/angular_velocity = 0.0
+18:9/0 = 0
+18:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:9/0/physics_layer_0/angular_velocity = 0.0
+19:9/0 = 0
+19:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:9/0/physics_layer_0/angular_velocity = 0.0
+20:9/0 = 0
+20:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:9/0/physics_layer_0/angular_velocity = 0.0
+21:9/0 = 0
+21:9/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:9/0/physics_layer_0/angular_velocity = 0.0
+0:10/0 = 0
+0:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:10/0/physics_layer_0/angular_velocity = 0.0
+1:10/0 = 0
+1:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:10/0/physics_layer_0/angular_velocity = 0.0
+2:10/0 = 0
+2:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:10/0/physics_layer_0/angular_velocity = 0.0
+3:10/0 = 0
+3:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:10/0/physics_layer_0/angular_velocity = 0.0
+4:10/0 = 0
+4:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:10/0/physics_layer_0/angular_velocity = 0.0
+5:10/0 = 0
+5:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:10/0/physics_layer_0/angular_velocity = 0.0
+6:10/0 = 0
+6:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:10/0/physics_layer_0/angular_velocity = 0.0
+7:10/0 = 0
+7:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:10/0/physics_layer_0/angular_velocity = 0.0
+8:10/0 = 0
+8:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:10/0/physics_layer_0/angular_velocity = 0.0
+9:10/0 = 0
+9:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:10/0/physics_layer_0/angular_velocity = 0.0
+10:10/0 = 0
+10:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:10/0/physics_layer_0/angular_velocity = 0.0
+15:10/0 = 0
+15:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:10/0/physics_layer_0/angular_velocity = 0.0
+16:10/0 = 0
+16:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:10/0/physics_layer_0/angular_velocity = 0.0
+17:10/0 = 0
+17:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:10/0/physics_layer_0/angular_velocity = 0.0
+18:10/0 = 0
+18:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:10/0/physics_layer_0/angular_velocity = 0.0
+19:10/0 = 0
+19:10/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:10/0/physics_layer_0/angular_velocity = 0.0
+0:11/0 = 0
+0:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:11/0/physics_layer_0/angular_velocity = 0.0
+1:11/0 = 0
+1:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:11/0/physics_layer_0/angular_velocity = 0.0
+2:11/0 = 0
+2:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:11/0/physics_layer_0/angular_velocity = 0.0
+3:11/0 = 0
+3:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:11/0/physics_layer_0/angular_velocity = 0.0
+4:11/0 = 0
+4:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:11/0/physics_layer_0/angular_velocity = 0.0
+5:11/0 = 0
+5:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:11/0/physics_layer_0/angular_velocity = 0.0
+6:11/0 = 0
+6:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:11/0/physics_layer_0/angular_velocity = 0.0
+7:11/0 = 0
+7:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:11/0/physics_layer_0/angular_velocity = 0.0
+8:11/0 = 0
+8:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:11/0/physics_layer_0/angular_velocity = 0.0
+9:11/0 = 0
+9:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:11/0/physics_layer_0/angular_velocity = 0.0
+10:11/0 = 0
+10:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:11/0/physics_layer_0/angular_velocity = 0.0
+19:11/0 = 0
+19:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:11/0/physics_layer_0/angular_velocity = 0.0
+20:11/0 = 0
+20:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:11/0/physics_layer_0/angular_velocity = 0.0
+21:11/0 = 0
+21:11/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:11/0/physics_layer_0/angular_velocity = 0.0
+0:12/0 = 0
+0:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:12/0/physics_layer_0/angular_velocity = 0.0
+1:12/0 = 0
+1:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:12/0/physics_layer_0/angular_velocity = 0.0
+2:12/0 = 0
+2:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:12/0/physics_layer_0/angular_velocity = 0.0
+3:12/0 = 0
+3:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:12/0/physics_layer_0/angular_velocity = 0.0
+4:12/0 = 0
+4:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:12/0/physics_layer_0/angular_velocity = 0.0
+6:12/0 = 0
+6:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:12/0/physics_layer_0/angular_velocity = 0.0
+7:12/0 = 0
+7:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:12/0/physics_layer_0/angular_velocity = 0.0
+8:12/0 = 0
+8:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:12/0/physics_layer_0/angular_velocity = 0.0
+9:12/0 = 0
+9:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:12/0/physics_layer_0/angular_velocity = 0.0
+10:12/0 = 0
+10:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:12/0/physics_layer_0/angular_velocity = 0.0
+19:12/0 = 0
+19:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:12/0/physics_layer_0/angular_velocity = 0.0
+20:12/0 = 0
+20:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:12/0/physics_layer_0/angular_velocity = 0.0
+21:12/0 = 0
+21:12/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:12/0/physics_layer_0/angular_velocity = 0.0
+0:13/0 = 0
+0:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:13/0/physics_layer_0/angular_velocity = 0.0
+0:13/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, -20.5, -32, -20, 32, -32, 32)
+1:13/0 = 0
+1:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:13/0/physics_layer_0/angular_velocity = 0.0
+2:13/0 = 0
+2:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:13/0/physics_layer_0/angular_velocity = 0.0
+2:13/0/physics_layer_0/polygon_0/points = PackedVector2Array(20.5, -32, 32, -32, 32, 32, 20.5, 32)
+3:13/0 = 0
+3:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:13/0/physics_layer_0/angular_velocity = 0.0
+4:13/0 = 0
+4:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:13/0/physics_layer_0/angular_velocity = 0.0
+5:13/0 = 0
+5:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:13/0/physics_layer_0/angular_velocity = 0.0
+6:13/0 = 0
+6:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:13/0/physics_layer_0/angular_velocity = 0.0
+7:13/0 = 0
+7:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:13/0/physics_layer_0/angular_velocity = 0.0
+8:13/0 = 0
+8:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:13/0/physics_layer_0/angular_velocity = 0.0
+9:13/0 = 0
+9:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:13/0/physics_layer_0/angular_velocity = 0.0
+19:13/0 = 0
+19:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:13/0/physics_layer_0/angular_velocity = 0.0
+20:13/0 = 0
+20:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:13/0/physics_layer_0/angular_velocity = 0.0
+21:13/0 = 0
+21:13/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:13/0/physics_layer_0/angular_velocity = 0.0
+0:14/0 = 0
+0:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:14/0/physics_layer_0/angular_velocity = 0.0
+0:14/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, -20.5, -32, -20, 32, -32, 32)
+1:14/0 = 0
+1:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:14/0/physics_layer_0/angular_velocity = 0.0
+2:14/0 = 0
+2:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:14/0/physics_layer_0/angular_velocity = 0.0
+2:14/0/physics_layer_0/polygon_0/points = PackedVector2Array(20.5, -32, 32, -32, 32, 32, 20.5, 32)
+3:14/0 = 0
+3:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:14/0/physics_layer_0/angular_velocity = 0.0
+4:14/0 = 0
+4:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:14/0/physics_layer_0/angular_velocity = 0.0
+5:14/0 = 0
+5:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:14/0/physics_layer_0/angular_velocity = 0.0
+6:14/0 = 0
+6:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:14/0/physics_layer_0/angular_velocity = 0.0
+7:14/0 = 0
+7:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:14/0/physics_layer_0/angular_velocity = 0.0
+8:14/0 = 0
+8:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:14/0/physics_layer_0/angular_velocity = 0.0
+9:14/0 = 0
+9:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:14/0/physics_layer_0/angular_velocity = 0.0
+19:14/0 = 0
+19:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:14/0/physics_layer_0/angular_velocity = 0.0
+20:14/0 = 0
+20:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:14/0/physics_layer_0/angular_velocity = 0.0
+21:14/0 = 0
+21:14/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:14/0/physics_layer_0/angular_velocity = 0.0
+0:15/0 = 0
+0:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:15/0/physics_layer_0/angular_velocity = 0.0
+0:15/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, -20.5, -32, -20, 32, -32, 32)
+1:15/0 = 0
+1:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:15/0/physics_layer_0/angular_velocity = 0.0
+2:15/0 = 0
+2:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:15/0/physics_layer_0/angular_velocity = 0.0
+2:15/0/physics_layer_0/polygon_0/points = PackedVector2Array(20.5, -32, 32, -32, 32, 32, 20.5, 32)
+3:15/0 = 0
+3:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:15/0/physics_layer_0/angular_velocity = 0.0
+4:15/0 = 0
+4:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:15/0/physics_layer_0/angular_velocity = 0.0
+5:15/0 = 0
+5:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:15/0/physics_layer_0/angular_velocity = 0.0
+6:15/0 = 0
+6:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:15/0/physics_layer_0/angular_velocity = 0.0
+7:15/0 = 0
+7:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:15/0/physics_layer_0/angular_velocity = 0.0
+8:15/0 = 0
+8:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:15/0/physics_layer_0/angular_velocity = 0.0
+9:15/0 = 0
+9:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:15/0/physics_layer_0/angular_velocity = 0.0
+10:15/0 = 0
+10:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:15/0/physics_layer_0/angular_velocity = 0.0
+19:15/0 = 0
+19:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:15/0/physics_layer_0/angular_velocity = 0.0
+20:15/0 = 0
+20:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:15/0/physics_layer_0/angular_velocity = 0.0
+21:15/0 = 0
+21:15/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:15/0/physics_layer_0/angular_velocity = 0.0
+0:16/0 = 0
+0:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:16/0/physics_layer_0/angular_velocity = 0.0
+1:16/0 = 0
+1:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:16/0/physics_layer_0/angular_velocity = 0.0
+2:16/0 = 0
+2:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:16/0/physics_layer_0/angular_velocity = 0.0
+3:16/0 = 0
+3:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:16/0/physics_layer_0/angular_velocity = 0.0
+4:16/0 = 0
+4:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:16/0/physics_layer_0/angular_velocity = 0.0
+5:16/0 = 0
+5:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:16/0/physics_layer_0/angular_velocity = 0.0
+6:16/0 = 0
+6:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:16/0/physics_layer_0/angular_velocity = 0.0
+7:16/0 = 0
+7:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:16/0/physics_layer_0/angular_velocity = 0.0
+8:16/0 = 0
+8:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:16/0/physics_layer_0/angular_velocity = 0.0
+9:16/0 = 0
+9:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:16/0/physics_layer_0/angular_velocity = 0.0
+10:16/0 = 0
+10:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:16/0/physics_layer_0/angular_velocity = 0.0
+19:16/0 = 0
+19:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:16/0/physics_layer_0/angular_velocity = 0.0
+20:16/0 = 0
+20:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:16/0/physics_layer_0/angular_velocity = 0.0
+21:16/0 = 0
+21:16/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:16/0/physics_layer_0/angular_velocity = 0.0
+0:17/0 = 0
+0:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:17/0/physics_layer_0/angular_velocity = 0.0
+1:17/0 = 0
+1:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:17/0/physics_layer_0/angular_velocity = 0.0
+2:17/0 = 0
+2:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:17/0/physics_layer_0/angular_velocity = 0.0
+3:17/0 = 0
+3:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:17/0/physics_layer_0/angular_velocity = 0.0
+4:17/0 = 0
+4:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:17/0/physics_layer_0/angular_velocity = 0.0
+5:17/0 = 0
+5:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:17/0/physics_layer_0/angular_velocity = 0.0
+6:17/0 = 0
+6:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:17/0/physics_layer_0/angular_velocity = 0.0
+7:17/0 = 0
+7:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:17/0/physics_layer_0/angular_velocity = 0.0
+8:17/0 = 0
+8:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:17/0/physics_layer_0/angular_velocity = 0.0
+16:17/0 = 0
+16:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:17/0/physics_layer_0/angular_velocity = 0.0
+17:17/0 = 0
+17:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:17/0/physics_layer_0/angular_velocity = 0.0
+18:17/0 = 0
+18:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:17/0/physics_layer_0/angular_velocity = 0.0
+19:17/0 = 0
+19:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:17/0/physics_layer_0/angular_velocity = 0.0
+20:17/0 = 0
+20:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:17/0/physics_layer_0/angular_velocity = 0.0
+21:17/0 = 0
+21:17/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:17/0/physics_layer_0/angular_velocity = 0.0
+0:18/0 = 0
+0:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:18/0/physics_layer_0/angular_velocity = 0.0
+1:18/0 = 0
+1:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:18/0/physics_layer_0/angular_velocity = 0.0
+2:18/0 = 0
+2:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:18/0/physics_layer_0/angular_velocity = 0.0
+3:18/0 = 0
+3:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:18/0/physics_layer_0/angular_velocity = 0.0
+4:18/0 = 0
+4:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:18/0/physics_layer_0/angular_velocity = 0.0
+5:18/0 = 0
+5:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:18/0/physics_layer_0/angular_velocity = 0.0
+6:18/0 = 0
+6:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:18/0/physics_layer_0/angular_velocity = 0.0
+7:18/0 = 0
+7:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:18/0/physics_layer_0/angular_velocity = 0.0
+8:18/0 = 0
+8:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:18/0/physics_layer_0/angular_velocity = 0.0
+9:18/0 = 0
+9:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:18/0/physics_layer_0/angular_velocity = 0.0
+13:18/0 = 0
+13:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:18/0/physics_layer_0/angular_velocity = 0.0
+14:18/0 = 0
+14:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:18/0/physics_layer_0/angular_velocity = 0.0
+14:18/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+15:18/0 = 0
+15:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:18/0/physics_layer_0/angular_velocity = 0.0
+15:18/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+16:18/0 = 0
+16:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:18/0/physics_layer_0/angular_velocity = 0.0
+16:18/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+17:18/0 = 0
+17:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:18/0/physics_layer_0/angular_velocity = 0.0
+17:18/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+18:18/0 = 0
+18:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:18/0/physics_layer_0/angular_velocity = 0.0
+18:18/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+19:18/0 = 0
+19:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:18/0/physics_layer_0/angular_velocity = 0.0
+19:18/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+20:18/0 = 0
+20:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:18/0/physics_layer_0/angular_velocity = 0.0
+21:18/0 = 0
+21:18/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:18/0/physics_layer_0/angular_velocity = 0.0
+21:18/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+0:19/0 = 0
+0:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:19/0/physics_layer_0/angular_velocity = 0.0
+1:19/0 = 0
+1:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:19/0/physics_layer_0/angular_velocity = 0.0
+2:19/0 = 0
+2:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:19/0/physics_layer_0/angular_velocity = 0.0
+3:19/0 = 0
+3:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:19/0/physics_layer_0/angular_velocity = 0.0
+4:19/0 = 0
+4:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:19/0/physics_layer_0/angular_velocity = 0.0
+5:19/0 = 0
+5:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:19/0/physics_layer_0/angular_velocity = 0.0
+6:19/0 = 0
+6:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:19/0/physics_layer_0/angular_velocity = 0.0
+7:19/0 = 0
+7:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:19/0/physics_layer_0/angular_velocity = 0.0
+8:19/0 = 0
+8:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:19/0/physics_layer_0/angular_velocity = 0.0
+9:19/0 = 0
+9:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:19/0/physics_layer_0/angular_velocity = 0.0
+13:19/0 = 0
+13:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:19/0/physics_layer_0/angular_velocity = 0.0
+14:19/0 = 0
+14:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:19/0/physics_layer_0/angular_velocity = 0.0
+14:19/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+15:19/0 = 0
+15:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:19/0/physics_layer_0/angular_velocity = 0.0
+16:19/0 = 0
+16:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:19/0/physics_layer_0/angular_velocity = 0.0
+16:19/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+17:19/0 = 0
+17:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:19/0/physics_layer_0/angular_velocity = 0.0
+17:19/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+18:19/0 = 0
+18:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:19/0/physics_layer_0/angular_velocity = 0.0
+18:19/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+19:19/0 = 0
+19:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:19/0/physics_layer_0/angular_velocity = 0.0
+19:19/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+20:19/0 = 0
+20:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:19/0/physics_layer_0/angular_velocity = 0.0
+21:19/0 = 0
+21:19/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:19/0/physics_layer_0/angular_velocity = 0.0
+21:19/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+0:20/0 = 0
+0:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:20/0/physics_layer_0/angular_velocity = 0.0
+1:20/0 = 0
+1:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:20/0/physics_layer_0/angular_velocity = 0.0
+2:20/0 = 0
+2:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:20/0/physics_layer_0/angular_velocity = 0.0
+3:20/0 = 0
+3:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:20/0/physics_layer_0/angular_velocity = 0.0
+4:20/0 = 0
+4:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:20/0/physics_layer_0/angular_velocity = 0.0
+5:20/0 = 0
+5:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:20/0/physics_layer_0/angular_velocity = 0.0
+6:20/0 = 0
+6:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:20/0/physics_layer_0/angular_velocity = 0.0
+7:20/0 = 0
+7:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:20/0/physics_layer_0/angular_velocity = 0.0
+8:20/0 = 0
+8:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:20/0/physics_layer_0/angular_velocity = 0.0
+9:20/0 = 0
+9:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:20/0/physics_layer_0/angular_velocity = 0.0
+10:20/0 = 0
+10:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:20/0/physics_layer_0/angular_velocity = 0.0
+13:20/0 = 0
+13:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:20/0/physics_layer_0/angular_velocity = 0.0
+14:20/0 = 0
+14:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:20/0/physics_layer_0/angular_velocity = 0.0
+14:20/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+15:20/0 = 0
+15:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:20/0/physics_layer_0/angular_velocity = 0.0
+15:20/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+16:20/0 = 0
+16:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:20/0/physics_layer_0/angular_velocity = 0.0
+16:20/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+17:20/0 = 0
+17:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:20/0/physics_layer_0/angular_velocity = 0.0
+17:20/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+18:20/0 = 0
+18:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:20/0/physics_layer_0/angular_velocity = 0.0
+18:20/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+19:20/0 = 0
+19:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:20/0/physics_layer_0/angular_velocity = 0.0
+19:20/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+20:20/0 = 0
+20:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+20:20/0/physics_layer_0/angular_velocity = 0.0
+21:20/0 = 0
+21:20/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+21:20/0/physics_layer_0/angular_velocity = 0.0
+21:20/0/physics_layer_0/polygon_0/points = PackedVector2Array(-32, -32, 32, -32, 32, 32, -32, 32)
+0:21/0 = 0
+0:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:21/0/physics_layer_0/angular_velocity = 0.0
+1:21/0 = 0
+1:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:21/0/physics_layer_0/angular_velocity = 0.0
+2:21/0 = 0
+2:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:21/0/physics_layer_0/angular_velocity = 0.0
+3:21/0 = 0
+3:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:21/0/physics_layer_0/angular_velocity = 0.0
+4:21/0 = 0
+4:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:21/0/physics_layer_0/angular_velocity = 0.0
+5:21/0 = 0
+5:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:21/0/physics_layer_0/angular_velocity = 0.0
+6:21/0 = 0
+6:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:21/0/physics_layer_0/angular_velocity = 0.0
+7:21/0 = 0
+7:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:21/0/physics_layer_0/angular_velocity = 0.0
+8:21/0 = 0
+8:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:21/0/physics_layer_0/angular_velocity = 0.0
+9:21/0 = 0
+9:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+9:21/0/physics_layer_0/angular_velocity = 0.0
+10:21/0 = 0
+10:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+10:21/0/physics_layer_0/angular_velocity = 0.0
+13:21/0 = 0
+13:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:21/0/physics_layer_0/angular_velocity = 0.0
+14:21/0 = 0
+14:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:21/0/physics_layer_0/angular_velocity = 0.0
+15:21/0 = 0
+15:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:21/0/physics_layer_0/angular_velocity = 0.0
+16:21/0 = 0
+16:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:21/0/physics_layer_0/angular_velocity = 0.0
+17:21/0 = 0
+17:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:21/0/physics_layer_0/angular_velocity = 0.0
+18:21/0 = 0
+18:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:21/0/physics_layer_0/angular_velocity = 0.0
+19:21/0 = 0
+19:21/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+19:21/0/physics_layer_0/angular_velocity = 0.0
+0:22/0 = 0
+0:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:22/0/physics_layer_0/angular_velocity = 0.0
+1:22/0 = 0
+1:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:22/0/physics_layer_0/angular_velocity = 0.0
+3:22/0 = 0
+3:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:22/0/physics_layer_0/angular_velocity = 0.0
+4:22/0 = 0
+4:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:22/0/physics_layer_0/angular_velocity = 0.0
+5:22/0 = 0
+5:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:22/0/physics_layer_0/angular_velocity = 0.0
+6:22/0 = 0
+6:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+6:22/0/physics_layer_0/angular_velocity = 0.0
+7:22/0 = 0
+7:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+7:22/0/physics_layer_0/angular_velocity = 0.0
+8:22/0 = 0
+8:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+8:22/0/physics_layer_0/angular_velocity = 0.0
+13:22/0 = 0
+13:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+13:22/0/physics_layer_0/angular_velocity = 0.0
+14:22/0 = 0
+14:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+14:22/0/physics_layer_0/angular_velocity = 0.0
+15:22/0 = 0
+15:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+15:22/0/physics_layer_0/angular_velocity = 0.0
+16:22/0 = 0
+16:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+16:22/0/physics_layer_0/angular_velocity = 0.0
+17:22/0 = 0
+17:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+17:22/0/physics_layer_0/angular_velocity = 0.0
+18:22/0 = 0
+18:22/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+18:22/0/physics_layer_0/angular_velocity = 0.0
+0:23/0 = 0
+0:23/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:23/0/physics_layer_0/angular_velocity = 0.0
+1:23/0 = 0
+1:23/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:23/0/physics_layer_0/angular_velocity = 0.0
+2:23/0 = 0
+2:23/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:23/0/physics_layer_0/angular_velocity = 0.0
+3:23/0 = 0
+3:23/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:23/0/physics_layer_0/angular_velocity = 0.0
+4:23/0 = 0
+4:23/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:23/0/physics_layer_0/angular_velocity = 0.0
+0:24/0 = 0
+0:24/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+0:24/0/physics_layer_0/angular_velocity = 0.0
+1:24/0 = 0
+1:24/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+1:24/0/physics_layer_0/angular_velocity = 0.0
+2:24/0 = 0
+2:24/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+2:24/0/physics_layer_0/angular_velocity = 0.0
+3:24/0 = 0
+3:24/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+3:24/0/physics_layer_0/angular_velocity = 0.0
+4:24/0 = 0
+4:24/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+4:24/0/physics_layer_0/angular_velocity = 0.0
+5:24/0 = 0
+5:24/0/physics_layer_0/linear_velocity = Vector2(0, 0)
+5:24/0/physics_layer_0/angular_velocity = 0.0
+
+[sub_resource type="TileSet" id="TileSet_xdu0j"]
+tile_size = Vector2i(64, 64)
+physics_layer_0/collision_layer = 1
+physics_layer_0/collision_mask = 6
+sources/0 = SubResource("TileSetAtlasSource_auqfk")
+
+[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_m24ei"]
+texture = ExtResource("3_72u1m")
+texture_region_size = Vector2i(64, 64)
+0:3/0 = 0
+1:3/0 = 0
+2:3/0 = 0
+3:3/0 = 0
+4:3/0 = 0
+5:3/0 = 0
+6:3/0 = 0
+7:3/0 = 0
+7:2/0 = 0
+6:2/0 = 0
+5:2/0 = 0
+4:2/0 = 0
+3:2/0 = 0
+2:2/0 = 0
+1:2/0 = 0
+0:2/0 = 0
+0:1/0 = 0
+0:0/0 = 0
+1:0/0 = 0
+2:0/0 = 0
+3:0/0 = 0
+4:0/0 = 0
+5:0/0 = 0
+6:0/0 = 0
+7:0/0 = 0
+8:0/0 = 0
+9:0/0 = 0
+10:0/0 = 0
+11:0/0 = 0
+12:0/0 = 0
+13:0/0 = 0
+14:0/0 = 0
+15:0/0 = 0
+
+[sub_resource type="TileSet" id="TileSet_orc4v"]
+tile_size = Vector2i(64, 64)
+sources/0 = SubResource("TileSetAtlasSource_m24ei")
+
+[sub_resource type="WorldBoundaryShape2D" id="WorldBoundaryShape2D_5dw0q"]
+distance = -250.0
+
+[sub_resource type="WorldBoundaryShape2D" id="WorldBoundaryShape2D_7ioaa"]
+normal = Vector2(-1, 0)
+distance = -1724.0
+
+[sub_resource type="WorldBoundaryShape2D" id="WorldBoundaryShape2D_fq7i5"]
+normal = Vector2(0, 1)
+distance = -1727.0
+
+[sub_resource type="WorldBoundaryShape2D" id="WorldBoundaryShape2D_kp00i"]
+normal = Vector2(1, 0)
+distance = -1921.0
+
+[node name="Main" type="Node2D"]
+script = ExtResource("1_l8nqt")
+
+[node name="Map" type="Node" parent="."]
+
+[node name="Terrain" type="TileMap" parent="Map"]
+position = Vector2(0, 1)
+tile_set = SubResource("TileSet_xdu0j")
+rendering_quadrant_size = 64
+format = 2
+layer_0/tile_data = PackedInt32Array(458760, 131072, 13, 458759, 0, 13, 524295, 0, 14, 589831, 0, 14, 655367, 0, 14, 720903, 0, 15, 720904, 131072, 15, 655368, 131072, 14, 589832, 131072, 14, 524296, 131072, 14, 720900, 1048576, 1, 655372, 1048576, 1, 851971, 1048576, 1, 917506, 1048576, 1, 983041, 1048576, 1, 851972, 851968, 2, 720908, 851968, 2, 655374, 851968, 2, 589840, 851968, 2, 720901, 786432, 2, 720902, 786432, 2, 720905, 786432, 2, 720906, 786432, 2, 720907, 786432, 2, 655373, 786432, 2, 589839, 786432, 2, 786436, 851968, 1, 917507, 851968, 2, 983042, 851968, 2, 1048577, 851968, 2, 1114112, 851968, 2, 1048576, 1048576, 1, 1179647, 1048576, 1, 1245183, 851968, 1, 1310719, 1048576, 2, 1245184, 786432, 0, 1245185, 786432, 0, 1245186, 786432, 0, 1245187, 786432, 0, 1245188, 851968, 0, 1310725, 786432, 0, 1310726, 786432, 0, 1310724, 1048576, 2, 1310727, 1114112, 2, 1245191, 720896, 0, 1245192, 786432, 0, 1245193, 851968, 0, 1310729, 1048576, 2, 1310730, 786432, 0, 1310731, 786432, 0, 1310732, 786432, 0, 1310733, 786432, 0, 1310734, 786432, 0, 1310735, 786432, 0, 1310736, 786432, 0, 1310737, 851968, 0, 1376273, 1048576, 2, 1376274, 786432, 0, 1376275, 1114112, 2, 1310739, 720896, 0, 1310740, 1114112, 2, 1245204, 720896, 1, 1179668, 720896, 0, 1179669, 1114112, 2, 1114133, 720896, 1, 1048597, 720896, 1, 983061, 720896, 0, 983062, 1114112, 2, 917526, 720896, 1, 851990, 720896, 1, 720917, 720896, 1, 655381, 720896, 1, 589845, 720896, 1, 524309, 720896, 1, 458773, 720896, 1, 393237, 720896, 1, 786453, 720896, 2, 786454, 1114112, 1, 327701, 1114112, 1, 327700, 786432, 2, 327699, 1048576, 1, 393234, 1048576, 1, 458769, 1048576, 1, 524304, 1048576, 1, 589838, 1048576, 1, 524305, 851968, 2, 458770, 851968, 2, 393235, 851968, 2, 1245206, 655360, 11, 1245205, 655360, 12, 1310741, 655360, 12, 1376277, 655360, 12, 1441813, 655360, 12, 1441814, 655360, 12, 1441815, 655360, 12, 1441816, 655360, 12, 1441817, 655360, 12, 1441818, 655360, 12, 1376282, 655360, 12, 1310746, 655360, 12, 1245210, 655360, 12, 1179674, 655360, 12, 1048602, 655360, 12, 983066, 655360, 12, 917530, 655360, 12, 786458, 655360, 12, 720922, 655360, 12, 524314, 655360, 12, 458778, 655360, 12, 327706, 655360, 12, 262170, 655360, 12, 196634, 655360, 12, 65562, 655360, 12, -65510, 655360, 12, -131046, 655360, 12, -196582, 655360, 12, -262118, 655360, 12, -327654, 655360, 12, -393190, 655360, 12, -524262, 655360, 12, -589798, 655360, 12, -655334, 655360, 12, -720870, 589824, 12, -786406, 655360, 12, -851942, 655360, 12, -917478, 655360, 12, -983014, 655360, 12, -1179622, 655360, 12, -1441766, 655360, 12, -1507302, 655360, 12, -1703910, 655360, 12, -1769446, 655360, 12, -1769447, 655360, 12, -1769448, 655360, 12, -1769449, 655360, 12, -1769450, 655360, 12, -1769451, 655360, 12, -1769452, 655360, 12, -1769453, 655360, 12, -1769454, 655360, 12, -1769455, 655360, 12, -1769456, 655360, 12, -1769457, 655360, 12, -1769458, 655360, 12, -1769459, 655360, 12, -1769460, 655360, 12, -1769461, 655360, 12, -1769462, 655360, 12, -1769463, 458752, 12, -1769464, 655360, 12, -1769465, 458752, 12, -1769466, 655360, 12, -1769467, 655360, 12, -1638374, 655360, 12, -1572838, 655360, 12, -1376230, 655360, 12, -1310694, 655360, 12, -1245158, 655360, 12, -1048550, 655360, 12, -1114086, 655360, 12, -458726, 655360, 12, 26, 589824, 12, 131098, 655360, 12, 393242, 655360, 12, 589850, 655360, 12, 655386, 655360, 12, 851994, 655360, 12, 1114138, 655360, 12, 1441812, 655360, 12, 1441811, 655360, 12, 1441810, 655360, 12, 1441809, 458752, 12, 1441808, 655360, 12, 1441807, 655360, 12, 1441806, 655360, 12, 1441805, 655360, 12, 1441804, 655360, 12, 1441803, 655360, 12, 1441802, 655360, 12, 1441801, 655360, 12, 1441800, 655360, 12, 1441799, 655360, 12, 1441798, 655360, 12, 1441797, 458752, 12, 1441796, 655360, 12, 1441795, 655360, 12, 1441794, 655360, 12, 1441793, 655360, 12, 1507324, 655360, 12, 1507325, 655360, 12, 1507326, 655360, 12, 1507327, 655360, 12, 1441792, 655360, 12, 1507322, 655360, 12, 1507321, 655360, 12, 1507320, 655360, 12, 1507319, 655360, 12, 1507318, 655360, 12, 1507317, 589824, 12, 1507316, 655360, 12, 1507315, 655360, 12, 1507314, 655360, 12, 1507313, 655360, 12, 1507312, 655360, 12, 1507311, 655360, 12, 1507310, 589824, 12, 1507309, 655360, 12, 1507308, 655360, 12, 1507307, 655360, 12, 1507306, 655360, 12, 1507305, 655360, 12, 1507304, 655360, 12, 1507303, 655360, 12, 1507302, 655360, 12, 1507301, 655360, 12, 1507300, 655360, 12, 1507299, 655360, 12, 1507298, 655360, 12, 1441762, 655360, 12, 1376226, 655360, 12, 1310690, 655360, 12, 1245154, 655360, 12, 1179618, 655360, 12, 1114082, 655360, 12, 1048546, 655360, 12, 983010, 655360, 12, 917474, 655360, 12, 851938, 655360, 12, 786402, 655360, 12, 720866, 655360, 12, 655330, 655360, 12, 589794, 655360, 12, 524258, 655360, 12, 458722, 655360, 12, 393186, 655360, 12, 327650, 655360, 12, 262114, 655360, 12, 196578, 655360, 12, 131042, 655360, 12, 65506, 655360, 12, -30, 589824, 12, -65566, 655360, 12, -131102, 655360, 12, -196638, 655360, 12, -262174, 655360, 12, -327710, 655360, 12, -393246, 655360, 12, -458782, 655360, 12, -524318, 655360, 12, -589854, 655360, 12, -655390, 655360, 12, -720926, 655360, 12, -786462, 655360, 12, -851998, 655360, 12, -917534, 655360, 12, -983070, 655360, 12, -1048606, 655360, 12, -1114142, 655360, 12, -1179678, 655360, 12, -1245214, 655360, 12, -1310750, 655360, 12, -1376286, 655360, 12, -1441822, 655360, 12, -1507358, 458752, 12, -1572894, 655360, 12, -1638430, 655360, 12, -1703966, 655360, 12, -1703965, 655360, 12, -1703964, 655360, 12, -1703963, 655360, 12, -1703962, 655360, 12, -1703961, 655360, 12, -1703960, 655360, 12, -1703959, 655360, 12, -1703958, 655360, 12, -1703957, 655360, 12, -1703956, 655360, 12, -1703955, 655360, 12, -1703954, 655360, 12, -1703953, 655360, 12, -1703952, 655360, 12, -1703951, 655360, 12, -1703949, 655360, 12, -1703948, 655360, 12, -1703947, 655360, 12, -1703946, 655360, 12, -1703945, 655360, 12, -1703944, 655360, 12, -1703943, 655360, 12, -1703942, 655360, 12, -1703941, 655360, 12, -1703940, 655360, 12, -1703939, 655360, 12, -1703938, 655360, 12, -1703937, 655360, 12, -1769472, 655360, 12, -1769470, 655360, 12, -1769469, 655360, 12, -1769468, 655360, 12, 917517, 720896, 5, 851981, 720896, 5, 786445, 720896, 5, 720909, 720896, 5, 720910, 720896, 5, 786446, 720896, 5, 851982, 720896, 5, 917518, 327680, 1, 983054, 131072, 2, 983053, 65536, 2, 983052, 327680, 1, 917516, 720896, 5, 851980, 720896, 5, 786444, 720896, 5, 786443, 720896, 5, 786442, 393216, 1, 786441, 0, 2, 786440, 262144, 5, 786439, 131072, 5, 786438, 131072, 2, 786437, 327680, 1, 851973, 131072, 1, 917509, 131072, 1, 917508, 720896, 5, 983044, 720896, 5, 983043, 720896, 5, 1048579, 720896, 5, 1048578, 720896, 5, 1114114, 720896, 5, 1114113, 720896, 5, 1179649, 720896, 5, 1179648, 720896, 5, 1179650, 720896, 5, 1179651, 720896, 5, 1114115, 720896, 5, 1114116, 720896, 5, 1048580, 720896, 5, 1048581, 720896, 5, 983045, 327680, 2, 983046, 131072, 0, 917510, 0, 5, 851974, 131072, 5, 851975, 0, 5, 917511, 65536, 5, 983047, 262144, 5, 1048583, 65536, 0, 1048582, 327680, 2, 1114118, 720896, 5, 1114117, 720896, 5, 1179653, 720896, 5, 1179652, 720896, 5, 1245189, 720896, 5, 1245190, 720896, 5, 1179654, 720896, 5, 1179655, 720896, 5, 1114119, 720896, 5, 1114120, 720896, 5, 1048584, 393216, 2, 983048, 0, 0, 917512, 0, 5, 851976, 196608, 5, 851977, 0, 5, 917513, 0, 0, 983049, 393216, 2, 1048585, 720896, 5, 1114121, 720896, 5, 1179657, 720896, 5, 1179656, 720896, 5, 1179658, 720896, 5, 1114122, 720896, 5, 1048586, 720896, 5, 983050, 720896, 5, 917514, 393216, 2, 851978, 0, 1, 851979, 720896, 5, 917515, 720896, 5, 983051, 720896, 5, 1048587, 720896, 5, 1114123, 720896, 5, 1179659, 720896, 5, 1245195, 720896, 5, 1245194, 720896, 5, 1245196, 720896, 5, 1179660, 720896, 5, 1114124, 327680, 2, 1048588, 131072, 1, 1048589, 0, 5, 1114125, 131072, 0, 1179661, 327680, 2, 1245197, 720896, 5, 1245198, 720896, 5, 1179662, 65536, 0, 1114126, 0, 5, 1048590, 131072, 5, 1048591, 262144, 5, 983055, 0, 5, 917519, 65536, 2, 851983, 720896, 5, 786447, 720896, 5, 720911, 720896, 5, 655375, 720896, 5, 655376, 720896, 5, 720912, 720896, 5, 786448, 720896, 5, 851984, 720896, 5, 917520, 65536, 2, 983056, 262144, 5, 1048592, 262144, 5, 1114128, 65536, 5, 1114127, 131072, 5, 1179663, 65536, 0, 1245199, 720896, 5, 1245200, 720896, 5, 1179664, 65536, 0, 1179665, 393216, 2, 1114129, 0, 0, 1048593, 131072, 5, 983057, 0, 2, 917521, 393216, 1, 851985, 720896, 5, 786449, 720896, 5, 720913, 720896, 5, 655377, 720896, 5, 589841, 720896, 5, 589842, 720896, 5, 524306, 720896, 5, 524307, 720896, 5, 458771, 720896, 5, 458772, 720896, 5, 393236, 720896, 5, 524308, 720896, 5, 589844, 720896, 5, 589843, 720896, 5, 655379, 720896, 5, 655378, 720896, 5, 720914, 720896, 5, 786450, 720896, 5, 851986, 720896, 5, 917522, 720896, 5, 983058, 393216, 1, 1048594, 0, 1, 1114130, 393216, 2, 1179666, 720896, 5, 1245202, 720896, 5, 1245201, 720896, 5, 1310738, 720896, 5, 1245203, 720896, 5, 1179667, 720896, 5, 1114131, 720896, 5, 1048595, 720896, 5, 983059, 720896, 5, 917523, 720896, 5, 851987, 720896, 5, 786451, 720896, 5, 720915, 720896, 5, 720916, 720896, 5, 655380, 720896, 5, 786452, 720896, 5, 851988, 720896, 5, 917524, 720896, 5, 983060, 720896, 5, 1048596, 720896, 5, 1114132, 720896, 5, 917525, 720896, 5, 851989, 720896, 5, 1376263, 655360, 11, 1376245, 655360, 11, 655364, 655360, 11, 524299, 655360, 11, 589847, 655360, 11, 65557, 655360, 11, -786415, 655360, 11, 1441782, 655360, 12, 1441783, 655360, 12, 1441784, 655360, 12, 1441785, 655360, 12, 1441786, 655360, 12, 1441787, 655360, 12, 1441788, 655360, 12, 1441789, 655360, 12, 1441790, 655360, 12, 1441791, 655360, 12, 1376256, 655360, 12, 1376257, 655360, 12, 1376258, 655360, 12, 1376259, 655360, 12, 1376260, 655360, 12, 1376261, 589824, 12, 1376262, 655360, 12, 1376264, 655360, 12, 1376265, 655360, 12, 1376266, 655360, 12, 1376267, 655360, 12, 1376268, 655360, 12, 1376269, 655360, 12, 1376270, 655360, 12, 1376271, 655360, 12, 1376272, 655360, 12, 1376276, 655360, 12, 1376278, 655360, 12, 1376279, 655360, 12, 1376280, 655360, 12, 1376281, 655360, 12, 1310745, 655360, 12, 1245209, 655360, 12, 1179673, 655360, 12, 1114137, 655360, 12, 1048601, 655360, 12, 983065, 655360, 12, 917529, 655360, 12, 851993, 655360, 12, 786457, 655360, 12, 720921, 655360, 12, 655385, 655360, 12, 589849, 655360, 12, 524313, 655360, 12, 458777, 655360, 12, 393241, 655360, 12, 327705, 655360, 12, 262169, 655360, 12, 196633, 655360, 12, 131097, 655360, 12, -983040, 1310720, 13, -983039, 1310720, 13, -1048575, 1310720, 12, -1048576, 1310720, 12, -1114112, 1310720, 11, -1114111, 1310720, 11, -1048577, 1245184, 18, -983041, 1245184, 19, -917505, 1245184, 20, -1048578, 1179648, 18, -983042, 1179648, 19, -917506, 1179648, 20, -1048579, 1179648, 18, -983043, 1179648, 19, -917507, 1179648, 20, -1048580, 1179648, 18, -983044, 1179648, 19, -917508, 1179648, 20, -1048581, 1179648, 18, -983045, 1179648, 19, -917509, 1179648, 20, -1048582, 1179648, 18, -983046, 1179648, 19, -917510, 1179648, 20, -1048583, 1179648, 18, -983047, 1179648, 19, -917511, 1179648, 20, -1114109, 1179648, 18, -1048573, 1179648, 19, -983037, 1179648, 20, -1114108, 1179648, 18, -1048572, 1179648, 19, -983036, 1179648, 20, -1114107, 1179648, 18, -1048571, 1179648, 19, -983035, 1179648, 20, -1114106, 1179648, 18, -1048570, 1179648, 19, -983034, 1179648, 20, -1114105, 1179648, 18, -1048569, 1179648, 19, -983033, 1179648, 20, -1114104, 1179648, 18, -1048568, 1179648, 19, -983032, 1179648, 20, -1114103, 1245184, 18, -1048567, 1245184, 19, -983031, 1245184, 20, -1048584, 1114112, 18, -983048, 1114112, 19, -917512, 1114112, 20, -1114110, 1114112, 18, -1048574, 1114112, 19, -983038, 1114112, 20, -1114120, 917504, 19, -1179656, 917504, 19, -1245192, 917504, 19, -1310728, 917504, 19, -1376264, 917504, 19, -1441800, 917504, 19, -1507336, 917504, 18, -1572871, 917504, 18, -1638406, 917504, 18, -1703936, 1048576, 18, -1638397, 1048576, 18, -1572860, 1048576, 18, -1507321, 1048576, 18, -1441783, 1048576, 18, -1441784, 983040, 18, -1507323, 983040, 18, -1507322, 983040, 18, -1638398, 983040, 18, -1638399, 983040, 18, -1638401, 983040, 18, -1638402, 983040, 18, -1638403, 983040, 18, -1638404, 983040, 18, -1638405, 983040, 18, -1507335, 851968, 21, -1572870, 851968, 21, -1638400, 917504, 21, -1572861, 917504, 21, -1507324, 917504, 21, -1441785, 917504, 21, -1376247, 1048576, 19, -1310711, 1048576, 19, -1245175, 1048576, 19, -1179639, 1048576, 19, -1310718, 65536, 20, -1376254, 65536, 19, -1441790, 65536, 19, -1507326, 327680, 20, -1572862, 131072, 18, -1572863, 65536, 18, -1572864, 65536, 18, -1507329, 327680, 20, -1572865, 131072, 18, -1572866, 65536, 18, -1572867, 65536, 18, -1572868, 65536, 18, -1572869, 0, 18, -1507333, 393216, 20, -1507334, 0, 18, -1441798, 393216, 20, -1441799, 0, 18, -1376263, 0, 19, -1310727, 0, 19, -1245191, 0, 20, -1179655, 0, 23, -1114119, 131072, 23, -1114118, 0, 23, -1179654, 0, 20, -1245190, 393216, 19, -1310726, 65536, 19, -1376262, 65536, 19, -1376261, 65536, 19, -1441797, 65536, 19, -1441796, 65536, 19, -1507332, 65536, 19, -1507331, 65536, 19, -1441795, 65536, 19, -1376259, 65536, 19, -1376260, 65536, 19, -1310724, 65536, 19, -1310725, 65536, 19, -1245189, 65536, 19, -1179653, 65536, 20, -1114117, 0, 23, -1114116, 0, 23, -1179652, 65536, 20, -1245188, 65536, 19, -1245187, 65536, 19, -1310723, 65536, 22, -1310722, 65536, 19, -1376258, 65536, 19, -1441794, 65536, 19, -1507330, 65536, 19, -1441793, 65536, 19, -1376257, 65536, 19, -1310721, 65536, 19, -1245185, 65536, 19, -1245186, 65536, 19, -1179650, 65536, 20, -1179651, 65536, 20, -1114115, 0, 23, -1114114, 0, 23, -1114113, 0, 23, -1179649, 65536, 20, -1245184, 65536, 20, -1310720, 65536, 19, -1376256, 65536, 19, -1441792, 65536, 19, -1507328, 65536, 19, -1507327, 65536, 19, -1441791, 65536, 19, -1376255, 65536, 19, -1310719, 327680, 19, -1245183, 131072, 20, -1179647, 196608, 23, -1179648, 0, 23, -1179646, 0, 23, -1245182, 0, 23, -1245181, 0, 23, -1310717, 65536, 20, -1376253, 65536, 19, -1441789, 327680, 20, -1507325, 131072, 18, -1441788, 65536, 18, -1376252, 65536, 19, -1310716, 65536, 20, -1245180, 262144, 23, -1179644, 0, 23, -1179645, 0, 23, -1179643, 0, 23, -1245179, 0, 23, -1310715, 131072, 20, -1376251, 131072, 19, -1441787, 131072, 18, -1441786, 262144, 23, -1376250, 0, 23, -1310714, 0, 23, -1245178, 0, 23, -1179642, 0, 23, -1179641, 0, 23, -1245177, 0, 23, -1310713, 65536, 23, -1376249, 0, 23, -1376248, 0, 23, -1310712, 0, 23, -1245176, 196608, 23, -1179640, 0, 23, -917513, 786432, 8, -917514, 786432, 8, -917515, 786432, 8, -917516, 786432, 8, -917517, 720896, 8, -983053, 720896, 7, -1048589, 720896, 6, -1048588, 1114112, 8, -1114124, 720896, 6, -1114123, 1114112, 8, -1179659, 720896, 7, -1245195, 720896, 7, -1310731, 720896, 7, -1376267, 1114112, 7, -1376268, 720896, 8, -1441804, 720896, 7, -1507340, 1114112, 7, -1507341, 786432, 8, -1507342, 786432, 8, -1507343, 720896, 8, -1572879, 1114112, 7, -1572880, 786432, 8, -1572881, 786432, 8, -1507347, 786432, 8, -1441813, 786432, 8, -1441814, 786432, 8, -1441815, 786432, 8, -1441816, 786432, 8, -720917, 786432, 8, -589806, 786432, 8, -983025, 786432, 8, -983026, 786432, 8, -983027, 786432, 8, -983028, 786432, 8, -983029, 786432, 8, -983030, 786432, 8, -983024, 1114112, 7, -589805, 1114112, 7, -655343, 1114112, 7, -720880, 1114112, 7, -1572882, 1048576, 7, -1507348, 1048576, 7, -1441817, 1048576, 7, -851988, 1048576, 7, -720918, 1048576, 7, -589847, 1048576, 7, -458776, 1048576, 7, -393241, 1048576, 7, -262170, 1048576, 7, -917488, 1114112, 8, -65517, 1114112, 8, 131090, 1114112, 8, 196625, 1114112, 8, 262160, 1114112, 8, 327694, 1114112, 8, 393229, 1114112, 8, 458764, 1114112, 8, 524292, 1114112, 8, 589826, 1114112, 8, 655361, 1114112, 8, 786432, 1114112, 8, 917503, 1114112, 8, 983038, 1114112, 8, 1114107, 1114112, 8, -1376281, 851968, 7, -1310745, 851968, 7, -917523, 851968, 7, -786452, 851968, 7, -655382, 851968, 7, -524311, 851968, 7, -196634, 851968, 7, -131098, 851968, 7, -65562, 851968, 7, -26, 851968, 7, 65510, 851968, 7, -327705, 851968, 7, 196583, 851968, 7, 262119, 851968, 7, 327655, 851968, 7, 720879, 851968, 7, 786415, 851968, 7, 851951, 851968, 7, 1048571, 720896, 7, 720896, 720896, 7, 18, 720896, 7, 65554, 720896, 7, -131053, 720896, 7, -196589, 720896, 7, -262125, 720896, 7, -327661, 720896, 7, -393197, 720896, 7, -458733, 720896, 7, -524269, 720896, 7, -786417, 720896, 7, -851953, 720896, 7, -720881, 0, 12, -655344, 720896, 8, -589807, 720896, 8, -917489, 720896, 6, -65518, 720896, 6, 131089, 720896, 6, 196624, 720896, 6, 262158, 720896, 6, 327693, 720896, 6, 393228, 720896, 6, 458756, 720896, 6, 524290, 720896, 6, 589825, 720896, 6, 655360, 720896, 6, 851967, 720896, 6, 917502, 720896, 6, 983035, 720896, 6, 983036, 786432, 6, 983037, 786432, 6, 655342, 786432, 6, 1114099, 786432, 6, 1114100, 786432, 6, 1114101, 786432, 6, 1114102, 786432, 6, 1114103, 786432, 6, 1114104, 786432, 6, 1114105, 786432, 6, 1114106, 786432, 6, 393192, 786432, 6, -1179671, 786432, 6, -1179670, 786432, 6, -1245209, 1048576, 8, -1179672, 1048576, 8, 131046, 1048576, 8, 393191, 1048576, 8, 458729, 1048576, 8, 524266, 1048576, 8, 589803, 1048576, 8, 655341, 1048576, 8, 917487, 1048576, 8, 1114098, 1048576, 8, 1048561, 1048576, 8, 983024, 1048576, 8, 589804, 786432, 6, 589805, 851968, 6, 655343, 851968, 6, 393193, 851968, 6, 458730, 851968, 6, 524267, 851968, 6, 131047, 851968, 6, -1179669, 851968, 6, -1114132, 851968, 6, -983059, 851968, 6, -1048596, 851968, 7, -1114133, 1048576, 8, -983060, 1048576, 8, -1245208, 851968, 6, -1441812, 851968, 8, -1507346, 851968, 8, 458757, 786432, 6, 458758, 786432, 6, 458761, 786432, 6, 458762, 786432, 6, 458763, 786432, 6, 262159, 786432, 6, 524291, 786432, 6, 983025, 851968, 6, 1048562, 851968, 6, 917488, 851968, 6, 393205, 131072, 11, 327669, 262144, 10, 262133, 196608, 8, 196597, 196608, 8, 131061, 196608, 8, 65525, 196608, 8, -11, 196608, 8, -65547, 196608, 8, -131083, 196608, 8, -196619, 196608, 8, -262155, 262144, 7, -327691, 131072, 12, -393227, 262144, 12, -458763, 262144, 12, -524299, 131072, 11, -589835, 0, 12, -655371, 262144, 12, -720907, 196608, 12, -786443, 131072, 11, -851979, 196608, 11, -851980, 196608, 11, -851981, 196608, 11, -851982, 131072, 11, -917518, 196608, 11, -983054, 262144, 12, -1048590, 262144, 12, -1114126, 196608, 11, -1179662, 196608, 11, -1245198, 262144, 12, -1310734, 262144, 12, -1376270, 131072, 11, -1441806, 65536, 12, -1441807, 131072, 12, -1441808, 262144, 12, -1507344, 196608, 11, -1507345, 262144, 12, -1441809, 262144, 12, -1441810, 262144, 12, -1441811, 65536, 12, -1376275, 262144, 12, -1376276, 262144, 12, -1376277, 196608, 12, -1376278, 131072, 11, -1376279, 262144, 12, -1376280, 196608, 12, -1310744, 131072, 12, -1310743, 262144, 12, -1245207, 196608, 12, -1245206, 131072, 12, -1310742, 262144, 12, -1310741, 262144, 12, -1245205, 262144, 12, -1245204, 196608, 12, -1310740, 65536, 12, -1310739, 131072, 11, -1245203, 196608, 12, -1179667, 131072, 11, -1179668, 131072, 12, -1114131, 131072, 11, -1048595, 196608, 11, -1048594, 131072, 12, -1114130, 65536, 12, -1179666, 131072, 12, -1245202, 196608, 12, -1310738, 262144, 12, -1376274, 196608, 12, -1376273, 131072, 11, -1310737, 131072, 11, -1245201, 196608, 11, -1179665, 262144, 12, -1114129, 0, 12, -1048593, 262144, 12, -983057, 262144, 12, -983058, 131072, 11, -917522, 196608, 11, -851986, 196608, 11, -851987, 851968, 8, -786451, 196608, 11, -720915, 262144, 12, -720916, 851968, 8, -655380, 131072, 11, -655381, 65536, 12, -589845, 65536, 12, -589846, 851968, 8, -524310, 262144, 12, -458774, 196608, 12, -458775, 851968, 8, -393239, 262144, 12, -393240, 851968, 8, -327704, 131072, 12, -262168, 196608, 11, -262169, 851968, 8, -196633, 262144, 12, -131097, 196608, 12, -65561, 65536, 12, -25, 196608, 11, 65511, 196608, 11, 65512, 0, 12, -24, 196608, 11, -65560, 262144, 12, -131096, 196608, 11, -196632, 196608, 11, -196631, 131072, 12, -262167, 262144, 12, -327703, 196608, 11, -327702, 65536, 12, -393238, 131072, 12, -393237, 196608, 11, -458773, 196608, 11, -524309, 196608, 11, -524308, 196608, 12, -589844, 65536, 12, -589843, 262144, 12, -655379, 131072, 12, -655378, 196608, 12, -720914, 0, 12, -786450, 262144, 12, -786449, 131072, 12, -851985, 196608, 11, -917521, 131072, 12, -917520, 262144, 12, -983056, 196608, 11, -1048592, 262144, 12, -1114128, 131072, 12, -1179664, 196608, 11, -1245200, 131072, 11, -1310736, 196608, 11, -1376272, 65536, 12, -1376271, 0, 12, -1310735, 0, 12, -1245199, 262144, 12, -1179663, 131072, 12, -1114127, 262144, 12, -1048591, 131072, 11, -983055, 0, 12, -917519, 0, 12, -851983, 262144, 12, -851984, 262144, 12, -786448, 131072, 11, -720912, 65536, 12, -720913, 196608, 11, -655377, 262144, 12, -589841, 262144, 12, -589842, 262144, 12, -524306, 262144, 12, -524307, 262144, 12, -458771, 131072, 11, -458772, 196608, 12, -393236, 196608, 11, -327700, 0, 12, -327701, 131072, 12, -262165, 196608, 11, -262166, 0, 12, -196630, 65536, 12, -131094, 131072, 12, -131095, 0, 12, -65559, 131072, 12, -23, 262144, 12, 65513, 131072, 11, 131049, 131072, 11, 131048, 196608, 12, 196584, 196608, 12, 262120, 196608, 11, 327656, 262144, 12, 327657, 196608, 11, 262121, 196608, 12, 196585, 262144, 12, 196586, 262144, 12, 131050, 131072, 11, 65514, 131072, 12, -22, 196608, 11, -65558, 262144, 12, -65557, 0, 12, -131093, 262144, 12, -196629, 0, 12, -196628, 65536, 12, -262164, 131072, 11, -262163, 262144, 12, -327699, 0, 12, -393235, 131072, 11, -393234, 65536, 12, -458770, 262144, 12, -458769, 0, 12, -524305, 0, 12, -524304, 196608, 11, -589840, 0, 12, -655376, 131072, 11, -655375, 196608, 11, -720911, 131072, 11, -786447, 196608, 11, -786446, 196608, 11, -720910, 196608, 11, -655374, 262144, 12, -589838, 196608, 11, -589839, 262144, 12, -524303, 131072, 12, -458767, 262144, 12, -458768, 262144, 12, -393232, 262144, 12, -393233, 131072, 11, -327697, 262144, 12, -327698, 196608, 12, -262162, 131072, 12, -196626, 196608, 12, -196627, 262144, 12, -131091, 262144, 12, -131092, 196608, 11, -65556, 196608, 11, -20, 262144, 12, -21, 131072, 11, 65515, 65536, 12, 131051, 131072, 11, 196587, 262144, 12, 262123, 131072, 11, 262122, 196608, 11, 327658, 0, 12, 393194, 262144, 12, 393195, 262144, 12, 327659, 262144, 12, 327660, 262144, 12, 262124, 65536, 12, 196588, 262144, 12, 131052, 0, 12, 65516, 196608, 11, 65517, 196608, 11, -19, 262144, 12, -65555, 262144, 12, -65554, 0, 12, -131090, 131072, 11, -131089, 196608, 11, -196625, 262144, 12, -262161, 196608, 12, -262160, 131072, 11, -327696, 65536, 12, -327695, 196608, 12, -393231, 196608, 11, -393230, 0, 12, -458766, 65536, 12, -524302, 65536, 12, -524301, 65536, 12, -589837, 65536, 12, -655373, 131072, 11, -720909, 131072, 11, -786445, 131072, 12, -786444, 131072, 12, -720908, 196608, 11, -655372, 196608, 11, -589836, 196608, 12, -524300, 196608, 11, -458764, 131072, 11, -458765, 196608, 11, -393229, 196608, 12, -327693, 131072, 12, -327694, 196608, 12, -262158, 196608, 12, -262159, 131072, 11, -196623, 131072, 12, -196624, 196608, 12, -131088, 0, 12, -65552, 131072, 11, -65553, 262144, 12, -17, 131072, 12, -18, 196608, 11, 65518, 131072, 12, 131054, 0, 12, 131053, 262144, 12, 196589, 196608, 12, 262125, 131072, 12, 327661, 0, 12, 393197, 131072, 11, 393196, 196608, 11, 458732, 196608, 11, 458731, 131072, 11, 524268, 196608, 11, 524269, 196608, 11, 458733, 131072, 12, 458734, 262144, 12, 393198, 196608, 11, 327662, 196608, 11, 262126, 0, 12, 196590, 196608, 12, 196591, 262144, 12, 131055, 262144, 12, 65519, 0, 12, 65520, 196608, 12, -16, 196608, 12, -15, 262144, 12, -65551, 0, 12, -131087, 131072, 12, -131086, 0, 12, -196622, 262144, 12, -196621, 0, 12, -262157, 262144, 12, -262156, 131072, 12, -327692, 196608, 11, -393228, 196608, 11, -196620, 65536, 12, -131084, 262144, 12, -131085, 131072, 12, -65549, 0, 12, -65550, 262144, 12, -14, 65536, 12, 65522, 65536, 12, 65521, 65536, 12, 131057, 131072, 12, 131056, 196608, 11, 196592, 262144, 12, 262128, 131072, 12, 262127, 196608, 12, 327663, 262144, 12, 393199, 262144, 12, 458735, 65536, 12, 524271, 131072, 12, 524270, 262144, 12, 589806, 131072, 11, 589807, 262144, 12, 589808, 196608, 12, 524272, 196608, 11, 458736, 262144, 12, 393200, 131072, 11, 327664, 262144, 12, 327665, 131072, 11, 262129, 262144, 12, 196593, 65536, 12, 196594, 262144, 12, 131058, 196608, 11, 131059, 0, 12, 65523, 131072, 11, -13, 262144, 12, -12, 196608, 12, -65548, 196608, 11, 65524, 196608, 12, 131060, 65536, 12, 196596, 196608, 11, 196595, 131072, 11, 262131, 131072, 12, 262130, 65536, 12, 327666, 262144, 12, 393202, 131072, 11, 393201, 196608, 11, 458737, 0, 12, 524273, 196608, 11, 589809, 65536, 12, 655345, 131072, 11, 655344, 262144, 12, 720880, 131072, 11, 786416, 196608, 11, 851952, 0, 12, 851953, 0, 12, 786417, 262144, 12, 720881, 131072, 12, 720882, 196608, 11, 655346, 131072, 11, 589810, 196608, 11, 524274, 0, 12, 458738, 131072, 12, 458739, 131072, 12, 393203, 262144, 12, 327667, 262144, 12, 327668, 131072, 12, 262132, 196608, 11, 393204, 262144, 12, 458740, 0, 12, 524276, 196608, 11, 524275, 196608, 12, 589811, 262144, 12, 655347, 0, 12, 720883, 196608, 11, 786419, 0, 12, 786418, 262144, 12, 851954, 262144, 12, 917490, 131072, 11, 917489, 0, 12, 983026, 0, 12, 983027, 196608, 12, 917491, 131072, 12, 851955, 131072, 11, 851956, 131072, 11, 786420, 262144, 12, 720884, 262144, 12, 655348, 0, 12, 589812, 0, 12, 589813, 0, 12, 524277, 0, 12, 458741, 65536, 12, 458742, 0, 12, 393206, 196608, 12, 327670, 131072, 10, 262134, 262144, 12, 196598, 0, 12, 131062, 196608, 12, 65526, 262144, 12, -10, 131072, 11, -65546, 262144, 12, -131082, 196608, 11, -196618, 262144, 12, -262154, 458752, 10, -327690, 196608, 8, -393226, 262144, 7, -458762, 196608, 11, -524298, 131072, 11, -589834, 262144, 12, -655370, 131072, 12, -720906, 262144, 12, -786442, 65536, 12, -851978, 196608, 11, -851977, 131072, 12, -786441, 131072, 12, -720905, 196608, 12, -655369, 262144, 12, -589833, 196608, 12, -524297, 0, 12, -458761, 262144, 12, -393225, 65536, 10, -327689, 262144, 12, -262153, 65536, 12, -196617, 131072, 11, -131081, 131072, 12, -65545, 131072, 11, -9, 262144, 12, 65527, 262144, 12, 131063, 131072, 12, 196599, 262144, 12, 262135, 262144, 12, 327671, 196608, 11, 393207, 262144, 12, 458743, 131072, 11, 524279, 262144, 12, 524278, 262144, 12, 589814, 131072, 11, 655350, 131072, 11, 655349, 196608, 11, 720885, 0, 12, 786421, 65536, 12, 851957, 131072, 12, 917493, 65536, 12, 917492, 131072, 12, 983028, 131072, 11, 1048564, 131072, 11, 1048563, 0, 12, 1048565, 262144, 12, 983029, 131072, 12, 983030, 0, 12, 917494, 0, 12, 851958, 196608, 12, 786422, 262144, 12, 720886, 0, 12, 720887, 65536, 12, 655351, 196608, 11, 589815, 65536, 12, 589816, 131072, 12, 524280, 262144, 12, 458744, 196608, 12, 393208, 262144, 12, 327672, 131072, 12, 262136, 0, 12, 196600, 131072, 11, 131064, 262144, 12, 65528, 196608, 11, -8, 262144, 12, -65544, 262144, 12, -131080, 196608, 12, -196616, 131072, 12, -262152, 196608, 11, -327688, 65536, 12, -393224, 65536, 10, -458760, 196608, 11, -524296, 65536, 12, -589832, 131072, 11, -655368, 196608, 11, -720904, 196608, 11, -786440, 262144, 12, -851976, 131072, 11, -851975, 0, 12, -786439, 65536, 12, -720903, 131072, 11, -655367, 0, 12, -589831, 262144, 12, -524295, 131072, 12, -458759, 65536, 12, -393223, 65536, 10, -327687, 0, 12, -262151, 196608, 11, -196615, 262144, 12, -131079, 131072, 12, -65543, 196608, 11, -7, 65536, 12, 65529, 65536, 12, 131065, 196608, 12, 196601, 131072, 11, 262137, 131072, 11, 327673, 65536, 12, 393209, 262144, 12, 458745, 196608, 12, 524281, 262144, 12, 589817, 262144, 12, 655353, 0, 12, 655352, 262144, 12, 720888, 0, 12, 786424, 196608, 12, 786423, 196608, 11, 851959, 65536, 12, 917495, 196608, 11, 983031, 196608, 11, 1048567, 131072, 12, 1048566, 196608, 11, 1048568, 0, 12, 983032, 65536, 12, 917496, 0, 12, 851960, 196608, 12, 851961, 0, 12, 786425, 196608, 12, 720889, 0, 12, 720890, 131072, 12, 655354, 131072, 11, 589818, 131072, 12, 524282, 262144, 12, 458746, 65536, 12, 393210, 262144, 12, 327674, 196608, 11, 262138, 262144, 12, 196602, 65536, 12, 131066, 262144, 12, 65530, 0, 12, -6, 131072, 11, -65542, 196608, 12, -131078, 196608, 11, -196614, 196608, 12, -262150, 131072, 12, -327686, 262144, 12, -393222, 65536, 10, -458758, 65536, 12, -524294, 196608, 11, -589830, 262144, 12, -655366, 262144, 12, -720902, 262144, 12, -786438, 131072, 11, -851974, 131072, 12, -851973, 262144, 12, -786437, 196608, 11, -720901, 131072, 12, -655365, 65536, 12, -589829, 262144, 12, -524293, 262144, 12, -458757, 131072, 12, -393221, 65536, 10, -327685, 196608, 12, -262149, 131072, 12, -196613, 131072, 11, -131077, 196608, 12, -65541, 262144, 12, -5, 0, 12, 65531, 131072, 12, 131067, 65536, 12, 196603, 262144, 12, 262139, 262144, 12, 327675, 196608, 11, 393211, 262144, 12, 458747, 262144, 12, 524283, 131072, 11, 589819, 65536, 12, 655355, 262144, 12, 720891, 0, 12, 786427, 0, 12, 786426, 262144, 12, 851962, 0, 12, 917498, 262144, 12, 917497, 65536, 12, 983033, 196608, 12, 1048569, 65536, 12, 1048570, 131072, 12, 983034, 196608, 12, 917499, 262144, 12, 851963, 262144, 12, 851964, 0, 12, 786428, 262144, 12, 720892, 0, 12, 655356, 196608, 12, 589820, 131072, 11, 524284, 196608, 12, 458748, 131072, 11, 393212, 196608, 11, 327676, 0, 12, 262140, 196608, 12, 196604, 196608, 12, 131068, 262144, 12, 65532, 196608, 11, -4, 262144, 12, -65540, 65536, 12, -131076, 65536, 12, -196612, 262144, 12, -262148, 262144, 12, -327684, 196608, 11, -393220, 65536, 10, -458756, 0, 12, -524292, 65536, 12, -589828, 0, 12, -655364, 262144, 12, -720900, 196608, 11, -786436, 0, 12, -851972, 131072, 11, -851971, 262144, 12, -786435, 131072, 11, -720899, 262144, 12, -655363, 196608, 12, -589827, 131072, 12, -524291, 0, 12, -458755, 131072, 11, -393219, 65536, 10, -327683, 131072, 11, -262147, 131072, 12, -196611, 262144, 12, -131075, 262144, 12, -65539, 196608, 11, -3, 131072, 12, 65533, 262144, 12, 131069, 196608, 11, 196605, 65536, 12, 262141, 0, 12, 327677, 196608, 11, 393213, 131072, 11, 458749, 262144, 12, 524285, 262144, 12, 589821, 262144, 12, 655357, 262144, 12, 720893, 131072, 11, 786429, 65536, 12, 851965, 65536, 12, 917501, 196608, 11, 917500, 196608, 12, 851966, 131072, 12, 786430, 65536, 12, 720894, 0, 12, 655358, 131072, 11, 589822, 65536, 12, 524286, 131072, 12, 458750, 196608, 11, 393214, 131072, 12, 327678, 131072, 12, 262142, 196608, 11, 196606, 262144, 12, 131070, 196608, 11, 65534, 0, 12, -2, 196608, 12, -65538, 196608, 12, -131074, 65536, 12, -196610, 262144, 12, -262146, 131072, 12, -327682, 196608, 11, -393218, 65536, 10, -458754, 262144, 12, -524290, 262144, 12, -589826, 262144, 12, -655362, 262144, 12, -720898, 131072, 12, -786434, 0, 12, -851970, 65536, 12, -851969, 196608, 11, -786433, 196608, 12, -720897, 131072, 11, -655361, 65536, 12, -589825, 262144, 12, -524289, 65536, 12, -458753, 262144, 12, -393217, 65536, 10, -327681, 196608, 11, -262145, 196608, 12, -196609, 0, 12, -131073, 196608, 12, -65537, 262144, 12, -1, 262144, 12, 65535, 0, 12, 131071, 131072, 12, 196607, 196608, 11, 262143, 65536, 12, 327679, 131072, 11, 393215, 0, 12, 458751, 131072, 11, 524287, 131072, 12, 589823, 131072, 11, 655359, 131072, 12, 720895, 196608, 11, 786431, 131072, 12, 589824, 196608, 11, 524288, 0, 12, 458752, 131072, 11, 393216, 196608, 12, 327680, 196608, 12, 262144, 131072, 11, 196608, 262144, 12, 131072, 131072, 11, 65536, 0, 12, 0, 196608, 12, -65536, 196608, 11, -131072, 131072, 11, -196608, 131072, 11, -262144, 0, 9, -327680, 0, 8, -393216, 0, 8, -458752, 393216, 11, -524288, 0, 8, -589824, 0, 8, -655360, 0, 8, -720896, 0, 8, -786432, 0, 8, -851968, 0, 8, -917504, 0, 7, -917503, 131072, 7, -851967, 131072, 8, -786431, 131072, 8, -720895, 131072, 8, -655359, 131072, 8, -589823, 131072, 8, -524287, 131072, 8, -458751, 131072, 8, -393215, 131072, 8, -327679, 327680, 9, -262143, 65536, 9, -196607, 262144, 12, -131071, 131072, 12, -65535, 196608, 12, 1, 262144, 12, 65537, 196608, 11, 131073, 131072, 11, 196609, 196608, 11, 262145, 131072, 11, 327681, 262144, 12, 393217, 131072, 11, 458753, 196608, 11, 524289, 262144, 12, 458754, 65536, 12, 393218, 196608, 12, 327682, 131072, 12, 262146, 262144, 12, 196610, 262144, 12, 131074, 196608, 11, 65538, 65536, 12, 2, 65536, 12, -65534, 65536, 12, -131070, 262144, 12, -196606, 262144, 12, -262142, 65536, 9, -327678, 65536, 7, -393214, 196608, 11, -458750, 131072, 11, -524286, 65536, 12, -589822, 131072, 12, -655358, 65536, 12, -720894, 262144, 12, -786430, 262144, 12, -851966, 196608, 11, -917502, 65536, 12, -917501, 262144, 12, -851965, 196608, 11, -786429, 65536, 12, -720893, 196608, 12, -655357, 196608, 12, -589821, 196608, 11, -524285, 196608, 11, -458749, 262144, 12, -393213, 65536, 12, -327677, 65536, 7, -262141, 65536, 9, -196605, 196608, 12, -131069, 262144, 12, -65533, 262144, 12, 3, 262144, 12, 65539, 131072, 11, 131075, 196608, 12, 196611, 262144, 12, 262147, 196608, 11, 327683, 65536, 12, 393219, 131072, 12, 458755, 262144, 12, 393220, 196608, 11, 327684, 262144, 12, 262148, 196608, 11, 196612, 0, 12, 131076, 65536, 12, 65540, 131072, 12, 4, 196608, 11, -65532, 131072, 11, -131068, 262144, 12, -196604, 262144, 12, -262140, 65536, 9, -327676, 65536, 7, -393212, 196608, 11, -458748, 262144, 12, -524284, 196608, 11, -589820, 131072, 12, -655356, 262144, 12, -720892, 196608, 11, -786428, 65536, 12, -851964, 262144, 12, -917500, 262144, 12, -917499, 0, 12, -851963, 196608, 11, -786427, 131072, 12, -720891, 0, 12, -655355, 0, 12, -589819, 196608, 11, -524283, 262144, 12, -458747, 0, 12, -393211, 0, 12, -327675, 65536, 7, -262139, 393216, 8, -196603, 0, 8, -131067, 0, 8, -65531, 0, 8, 5, 0, 8, 65541, 0, 9, 131077, 65536, 12, 196613, 262144, 12, 262149, 262144, 12, 327685, 131072, 11, 393221, 131072, 11, 393222, 131072, 12, 327686, 262144, 12, 262150, 262144, 12, 196614, 0, 12, 131078, 131072, 11, 65542, 65536, 9, 6, 327680, 9, -65530, 131072, 8, -131066, 131072, 8, -196602, 131072, 8, -262138, 131072, 8, -327674, 131072, 7, -393210, 0, 12, -458746, 262144, 12, -524282, 262144, 12, -589818, 131072, 12, -655354, 262144, 12, -720890, 131072, 11, -786426, 131072, 11, -851962, 262144, 12, -917498, 196608, 11, -917497, 262144, 12, -851961, 0, 12, -786425, 196608, 12, -720889, 65536, 12, -655353, 262144, 12, -589817, 0, 12, -524281, 131072, 11, -458745, 262144, 12, -393209, 131072, 11, -327673, 131072, 11, -262137, 0, 12, -196601, 262144, 12, -131065, 196608, 11, -65529, 196608, 11, 7, 65536, 7, 65543, 393216, 8, 131079, 0, 8, 196615, 0, 8, 262151, 0, 8, 327687, 0, 8, 393223, 0, 9, 393224, 131072, 9, 327688, 131072, 8, 262152, 131072, 8, 196616, 131072, 8, 131080, 131072, 8, 65544, 131072, 8, 8, 131072, 7, -65528, 196608, 11, -131064, 65536, 12, -196600, 131072, 12, -262136, 196608, 12, -327672, 196608, 11, -393208, 262144, 12, -458744, 262144, 12, -524280, 0, 12, -589816, 262144, 12, -655352, 0, 12, -720888, 65536, 12, -786424, 131072, 11, -851960, 196608, 11, -917496, 196608, 11, -917495, 131072, 12, -851959, 131072, 11, -786423, 196608, 12, -720887, 131072, 11, -655351, 196608, 12, -589815, 196608, 11, -524279, 0, 12, -458743, 196608, 11, -393207, 65536, 12, -327671, 196608, 11, -262135, 131072, 11, -196599, 196608, 12, -131063, 65536, 12, -65527, 65536, 12, 9, 262144, 12, 65545, 196608, 12, 131081, 262144, 12, 196617, 262144, 12, 262153, 131072, 12, 327689, 262144, 12, 393225, 131072, 11, 393226, 196608, 11, 327690, 131072, 11, 262154, 196608, 11, 196618, 196608, 11, 131082, 131072, 12, 65546, 262144, 12, 10, 131072, 11, -65526, 196608, 11, -131062, 196608, 11, -196598, 262144, 12, -262134, 0, 12, -327670, 0, 12, -393206, 131072, 12, -458742, 131072, 12, -524278, 65536, 12, -589814, 131072, 11, -655350, 262144, 12, -720886, 131072, 11, -786422, 0, 12, -851958, 262144, 12, -917494, 131072, 11, -917493, 131072, 12, -851957, 196608, 11, -786421, 131072, 12, -720885, 196608, 11, -655349, 262144, 12, -589813, 131072, 12, -524277, 0, 12, -458741, 196608, 11, -393205, 131072, 11, -327669, 131072, 12, -262133, 196608, 12, -196597, 262144, 12, -131061, 65536, 12, -65525, 262144, 12, 11, 262144, 12, 65547, 262144, 12, 131083, 262144, 12, 196619, 196608, 11, 262155, 131072, 12, 327691, 131072, 12, 393227, 65536, 12, 327692, 196608, 11, 262156, 131072, 11, 196620, 131072, 12, 131084, 131072, 11, 65548, 131072, 12, 12, 262144, 12, -65524, 262144, 12, -131060, 131072, 12, -196596, 196608, 11, -262132, 131072, 11, -327668, 262144, 12, -393204, 196608, 11, -458740, 262144, 12, -524276, 0, 12, -589812, 262144, 12, -655348, 65536, 12, -720884, 65536, 12, -786420, 0, 12, -851956, 131072, 11, -917492, 65536, 12, -917491, 262144, 12, -851955, 0, 12, -786419, 0, 12, -720883, 65536, 12, -655347, 262144, 12, -589811, 262144, 12, -524275, 262144, 12, -458739, 196608, 11, -393203, 196608, 11, -327667, 65536, 12, -262131, 262144, 12, -196595, 196608, 11, -131059, 131072, 12, -65523, 262144, 12, 13, 0, 12, 65549, 131072, 12, 131085, 131072, 12, 196621, 196608, 11, 262157, 131072, 11, 196622, 65536, 12, 131086, 65536, 12, 65550, 131072, 11, 14, 131072, 12, -65522, 131072, 11, -131058, 196608, 12, -196594, 262144, 12, -262130, 196608, 11, -327666, 131072, 11, -393202, 131072, 12, -458738, 0, 12, -524274, 196608, 11, -589810, 0, 12, -655346, 262144, 12, -720882, 196608, 11, -786418, 131072, 12, -851954, 196608, 12, -917490, 196608, 11, -655345, 0, 12, -589809, 0, 12, -524273, 262144, 12, -458737, 131072, 11, -393201, 262144, 12, -327665, 196608, 11, -262129, 196608, 12, -196593, 262144, 12, -131057, 196608, 11, -65521, 262144, 12, 15, 262144, 12, 65551, 131072, 11, 131087, 196608, 11, 196623, 65536, 12, 131088, 196608, 12, 65552, 0, 12, 16, 65536, 12, -65520, 196608, 11, -131056, 131072, 11, -196592, 262144, 12, -262128, 131072, 12, -327664, 65536, 12, -393200, 262144, 12, -458736, 65536, 12, -524272, 196608, 11, -589808, 0, 12, -524271, 262144, 12, -458735, 262144, 12, -393199, 262144, 12, -327663, 262144, 12, -262127, 196608, 11, -196591, 65536, 12, -131055, 196608, 12, -65519, 131072, 12, 17, 262144, 12, 65553, 196608, 11, -131054, 131072, 12, -196590, 65536, 12, -262126, 131072, 11, -327662, 262144, 12, -393198, 0, 12, -458734, 196608, 11, -524270, 262144, 12, -1441805, 262144, 12, -1376269, 131072, 11, -1310733, 262144, 12, -1245197, 262144, 12, -1179661, 262144, 12, -1114125, 262144, 12, -1179660, 0, 12, -1245196, 262144, 12, -1310732, 262144, 12, 917480, 655360, 12, 851944, 655360, 12, 786408, 655360, 12, 720872, 655360, 12, 655336, 655360, 12, 589800, 655360, 12, 524264, 655360, 12, 458728, 655360, 12, 458727, 655360, 12, 458726, 655360, 12, 393190, 655360, 12, 327654, 655360, 12, 262118, 655360, 12, 196582, 655360, 12, 196581, 655360, 12, 131045, 655360, 12, 65509, 655360, 12, -27, 655360, 12, -65563, 655360, 12, -131099, 655360, 12, -196635, 655360, 12, -262171, 655360, 12, -327707, 655360, 12, -393243, 655360, 12, -458779, 655360, 12, -524315, 655360, 12, -589851, 655360, 12, -655387, 655360, 12, -720923, 655360, 12, -786459, 655360, 12, -851995, 655360, 12, -917531, 655360, 12, -983067, 655360, 12, -1048603, 655360, 12, -1114139, 655360, 12, -1179675, 655360, 12, -1245211, 655360, 12, -1310747, 655360, 12, -1376283, 655360, 12, -1441819, 655360, 12, -1507355, 655360, 12, -1572891, 655360, 12, -1638427, 655360, 12, -1638428, 655360, 12, -1638429, 655360, 12, -1572893, 655360, 12, -1507357, 655360, 12, -1441821, 655360, 12, -1376285, 655360, 12, -1310749, 655360, 12, -1245213, 655360, 12, -1179677, 655360, 12, -1114141, 655360, 12, -1048605, 655360, 12, -983069, 655360, 12, -917533, 655360, 12, -851997, 655360, 12, -786461, 655360, 12, -720925, 655360, 12, -655389, 589824, 12, -589853, 655360, 12, -524317, 655360, 12, -458781, 458752, 12, -393245, 655360, 12, -327709, 655360, 12, -262173, 655360, 12, -196637, 655360, 12, -131101, 655360, 12, -65565, 655360, 12, -29, 655360, 12, 65507, 655360, 12, 131043, 655360, 12, 196579, 655360, 12, 262115, 655360, 12, 327651, 655360, 12, 393187, 655360, 12, 458723, 589824, 12, 524259, 655360, 12, 589795, 458752, 12, 655331, 655360, 12, 720867, 655360, 12, 786403, 655360, 12, 851939, 655360, 12, 917475, 655360, 12, 983011, 655360, 12, 1048547, 655360, 12, 1114083, 655360, 12, 1179619, 655360, 12, 1245155, 589824, 12, 1310691, 655360, 12, 1376227, 655360, 12, 1441763, 655360, 12, 1441764, 458752, 12, 1376228, 589824, 12, 1310692, 589824, 12, 1245156, 655360, 12, 1179620, 655360, 12, 1114084, 655360, 12, 1048548, 655360, 12, 983012, 655360, 12, 917476, 655360, 12, 851940, 655360, 12, 786404, 655360, 12, 720868, 655360, 12, 655332, 655360, 12, 589796, 655360, 12, 524260, 655360, 12, 458724, 655360, 12, 393188, 655360, 12, 327652, 655360, 12, 262116, 655360, 12, 196580, 655360, 12, 131044, 655360, 12, 65508, 655360, 12, -28, 655360, 12, -65564, 655360, 12, -131100, 655360, 12, -196636, 655360, 12, -262172, 655360, 12, -327708, 655360, 12, -393244, 655360, 12, -458780, 655360, 12, -524316, 655360, 12, -589852, 655360, 12, -655388, 655360, 12, -720924, 655360, 12, -786460, 655360, 12, -851996, 655360, 12, -917532, 655360, 12, -983068, 655360, 12, -1048604, 655360, 12, -1114140, 655360, 12, -1179676, 655360, 12, -1245212, 655360, 12, -1310748, 655360, 12, -1376284, 655360, 12, -1441820, 655360, 12, -1507356, 655360, 12, -1572892, 655360, 12, 262117, 655360, 12, 327653, 655360, 12, 393189, 655360, 12, 458725, 655360, 12, 524261, 458752, 12, 589797, 655360, 12, 655333, 655360, 12, 720869, 655360, 12, 786405, 655360, 12, 851941, 655360, 12, 917477, 655360, 12, 983013, 655360, 12, 1048549, 655360, 12, 1114085, 655360, 12, 1179621, 655360, 12, 1245157, 655360, 12, 1310693, 655360, 12, 1376229, 655360, 12, 1441765, 655360, 12, 1441766, 655360, 12, 1376230, 458752, 12, 1310694, 655360, 12, 1245158, 655360, 12, 1179622, 655360, 12, 1114086, 655360, 12, 1048550, 655360, 12, 983014, 655360, 12, 917478, 655360, 12, 851942, 655360, 12, 786406, 655360, 12, 720870, 655360, 12, 655334, 655360, 12, 589798, 655360, 12, 524262, 655360, 12, 524263, 655360, 12, 589799, 655360, 12, 655335, 655360, 12, 720871, 655360, 12, 786407, 655360, 12, 851943, 655360, 12, 917479, 655360, 12, 983015, 655360, 12, 1048551, 655360, 12, 1114087, 655360, 12, 1179623, 655360, 12, 1245159, 655360, 12, 1310695, 655360, 12, 1376231, 655360, 12, 1441767, 655360, 12, 1441768, 655360, 12, 1376232, 655360, 12, 1310696, 655360, 12, 1245160, 655360, 12, 1179624, 655360, 12, 1114088, 458752, 12, 1048552, 655360, 12, 983016, 655360, 12, 983017, 655360, 12, 917481, 655360, 12, 851945, 655360, 12, 786409, 655360, 12, 720873, 655360, 12, 655337, 655360, 12, 589801, 655360, 12, 524265, 655360, 12, 589802, 589824, 12, 655338, 655360, 12, 720874, 655360, 12, 786410, 655360, 12, 851946, 655360, 12, 917482, 655360, 12, 983018, 655360, 12, 1048554, 655360, 12, 1048553, 655360, 12, 1114089, 589824, 12, 1179625, 655360, 12, 1245161, 655360, 12, 1310697, 655360, 12, 1376233, 655360, 12, 1441769, 655360, 12, 1441770, 655360, 12, 1376234, 655360, 12, 1310698, 655360, 12, 1245162, 655360, 12, 1179626, 655360, 12, 1114090, 655360, 12, 1114091, 655360, 12, 1048555, 655360, 12, 983019, 655360, 12, 917483, 655360, 12, 851947, 655360, 12, 786411, 655360, 12, 720875, 655360, 12, 655339, 655360, 12, 655340, 458752, 12, 720876, 655360, 12, 786412, 655360, 12, 851948, 655360, 12, 917484, 655360, 12, 983020, 655360, 12, 1048556, 655360, 12, 1114092, 655360, 12, 1179628, 655360, 12, 1179627, 655360, 12, 1245163, 655360, 12, 1310699, 655360, 12, 1376235, 655360, 12, 1441771, 655360, 12, 1441772, 655360, 12, 1376236, 655360, 12, 1310700, 655360, 12, 1245164, 655360, 12, 1245165, 655360, 12, 1179629, 655360, 12, 1114093, 655360, 12, 1048557, 655360, 12, 983021, 655360, 12, 917485, 655360, 12, 851949, 655360, 12, 786413, 655360, 12, 720877, 655360, 12, 720878, 655360, 12, 786414, 655360, 12, 851950, 655360, 12, 917486, 655360, 12, 983022, 655360, 12, 1048558, 655360, 12, 1114094, 655360, 12, 1179630, 655360, 12, 1245166, 655360, 12, 1310702, 655360, 12, 1310701, 655360, 12, 1376237, 655360, 12, 1441773, 655360, 12, 1441774, 655360, 12, 1376238, 655360, 12, 1376239, 655360, 12, 1310703, 655360, 12, 1245167, 655360, 12, 1179631, 655360, 12, 1114095, 655360, 12, 1048559, 655360, 12, 983023, 655360, 12, 1048560, 655360, 12, 1114096, 589824, 12, 1179632, 655360, 12, 1245168, 655360, 12, 1310704, 655360, 12, 1376240, 655360, 12, 1441776, 655360, 12, 1441775, 655360, 12, 1441777, 655360, 12, 1376241, 655360, 12, 1310705, 655360, 12, 1245169, 589824, 12, 1179633, 655360, 12, 1114097, 655360, 12, 1179634, 655360, 12, 1245170, 655360, 12, 1310706, 655360, 12, 1376242, 589824, 12, 1441778, 655360, 12, 1441779, 655360, 12, 1376243, 655360, 12, 1310707, 655360, 12, 1245171, 655360, 12, 1179635, 655360, 12, 1179636, 655360, 12, 1245172, 655360, 12, 1310708, 655360, 12, 1376244, 655360, 12, 1441780, 655360, 12, 1441781, 655360, 12, 1310709, 655360, 12, 1245173, 655360, 12, 1179637, 655360, 12, 1179638, 655360, 12, 1245174, 655360, 12, 1310710, 655360, 12, 1376246, 655360, 12, 1376247, 655360, 12, 1310711, 589824, 12, 1245175, 655360, 12, 1179639, 655360, 12, 1179640, 655360, 12, 1245176, 655360, 12, 1310712, 655360, 12, 1376248, 655360, 12, 1376249, 655360, 12, 1310713, 655360, 12, 1245177, 655360, 12, 1179641, 655360, 12, 1179642, 655360, 12, 1245178, 655360, 12, 1310714, 655360, 12, 1376250, 655360, 12, 1376251, 655360, 12, 1310715, 655360, 12, 1245179, 655360, 12, 1179643, 655360, 12, 1179644, 655360, 12, 1114108, 655360, 12, 1048572, 655360, 12, 1048573, 655360, 12, 1114109, 655360, 12, 1179645, 655360, 12, 1245181, 655360, 12, 1245180, 589824, 12, 1310716, 589824, 12, 1376252, 655360, 12, 1376253, 655360, 12, 1310717, 655360, 12, 1310718, 655360, 12, 1245182, 655360, 12, 1179646, 655360, 12, 1114110, 655360, 12, 1048574, 655360, 12, 1048575, 655360, 12, 983039, 655360, 12, 917504, 655360, 12, 851968, 655360, 12, 851969, 655360, 12, 786433, 655360, 12, 720897, 655360, 12, 720898, 655360, 12, 655362, 589824, 12, 655363, 655360, 12, 589827, 655360, 12, 589828, 655360, 12, 589829, 655360, 12, 524293, 655360, 12, 524294, 589824, 12, 589830, 655360, 12, 655366, 655360, 12, 655365, 655360, 12, 720899, 655360, 12, 786435, 655360, 12, 786434, 655360, 12, 851970, 655360, 12, 917505, 655360, 12, 983040, 655360, 12, 1114111, 655360, 12, 1376254, 655360, 12, 1376255, 458752, 12, 1310720, 655360, 12, 1310721, 655360, 12, 1310722, 655360, 12, 1310723, 655360, 12, -1638426, 655360, 12, -1572890, 655360, 12, -1507354, 655360, 12, -1441818, 655360, 12, -1376282, 655360, 12, -1310746, 655360, 12, -1245210, 458752, 12, -1179674, 655360, 12, -1114138, 655360, 12, -1048602, 655360, 12, -983066, 655360, 12, -917530, 655360, 12, -851994, 655360, 12, -786458, 655360, 12, -720922, 655360, 12, -655386, 655360, 12, -589850, 655360, 12, -524314, 655360, 12, -458778, 655360, 12, -393242, 655360, 12, -327706, 655360, 12, -458777, 655360, 12, -524313, 655360, 12, -589849, 655360, 12, -655385, 655360, 12, -720921, 655360, 12, -786457, 655360, 12, -851993, 655360, 12, -917529, 458752, 12, -983065, 655360, 12, -1048601, 655360, 12, -1114137, 655360, 12, -1179673, 655360, 12, -1114136, 655360, 12, -1048600, 655360, 12, -983064, 655360, 12, -917528, 655360, 12, -851992, 655360, 12, -786456, 655360, 12, -720920, 655360, 12, -655384, 655360, 12, -589848, 655360, 12, -524312, 655360, 12, -655383, 655360, 12, -720919, 655360, 12, -786455, 655360, 12, -851991, 655360, 12, -917527, 655360, 12, -983063, 655360, 12, -1048599, 655360, 12, -1114135, 655360, 12, -1114134, 655360, 12, -1048598, 655360, 12, -983062, 655360, 12, -917526, 655360, 12, -851990, 458752, 12, -786454, 655360, 12, -786453, 655360, 12, -851989, 655360, 12, -917525, 655360, 12, -983061, 655360, 12, -1048597, 655360, 12, -917524, 655360, 12, -1507353, 655360, 12, -1572889, 655360, 12, -1638425, 655360, 12, -1638424, 655360, 12, -1572888, 655360, 12, -1507352, 655360, 12, -1507351, 655360, 12, -1572887, 655360, 12, -1638423, 655360, 12, -1638422, 655360, 12, -1572886, 655360, 12, -1507350, 655360, 12, -1507349, 458752, 12, -1572885, 655360, 12, -1638421, 655360, 12, -1638420, 655360, 12, -1572884, 655360, 12, -1572883, 655360, 12, -1638419, 655360, 12, -1638418, 655360, 12, -1638417, 655360, 12, -1638416, 655360, 12, -1638415, 655360, 12, -1638414, 655360, 12, -1703950, 655360, 12, -1572878, 655360, 12, -1572877, 655360, 12, -1638413, 655360, 12, -1638412, 655360, 12, -1572876, 655360, 12, -1572875, 655360, 12, -1638411, 655360, 12, -1638410, 655360, 12, -1572874, 655360, 12, -1507338, 655360, 12, -1507339, 458752, 12, -1441803, 655360, 12, -1441802, 655360, 12, -1376266, 655360, 12, -1310730, 655360, 12, -1245194, 655360, 12, -1179658, 655360, 12, -1114122, 655360, 12, -1048586, 655360, 12, -1048587, 655360, 12, -983051, 655360, 12, -983052, 655360, 12, -983050, 655360, 12, -983049, 655360, 12, -1048585, 655360, 12, -1114121, 655360, 12, -1179657, 655360, 12, -1245193, 655360, 12, -1310729, 655360, 12, -1376265, 655360, 12, -1441801, 655360, 12, -1507337, 655360, 12, -1572873, 655360, 12, -1638409, 655360, 12, -1638408, 655360, 12, -1572872, 655360, 12, -1638407, 655360, 12, -524266, 589824, 12, -589802, 655360, 12, -655338, 655360, 12, -720874, 655360, 12, -786410, 655360, 12, -851946, 655360, 12, -917482, 655360, 12, -983018, 655360, 12, -1048554, 655360, 12, -1114090, 655360, 12, -1179626, 655360, 12, -1245162, 655360, 12, -1310698, 655360, 12, -1376234, 589824, 12, -1441770, 655360, 12, -1507306, 655360, 12, -1572842, 655360, 12, -1638378, 655360, 12, -1703914, 655360, 12, -1703915, 655360, 12, -1703916, 655360, 12, -1703917, 655360, 12, -1703918, 589824, 12, -1703919, 655360, 12, -1703920, 655360, 12, -1703921, 655360, 12, -1703922, 655360, 12, -1703923, 655360, 12, -1703924, 458752, 12, -1703925, 655360, 12, -1703926, 458752, 12, -1703927, 655360, 12, -1703928, 655360, 12, -1703929, 655360, 12, -1703930, 655360, 12, -1703931, 655360, 12, -1703932, 655360, 12, -1703933, 655360, 12, -1703934, 655360, 12, -1703935, 655360, 12, -1769471, 655360, 12, -1638396, 655360, 12, -1638395, 655360, 12, -1572859, 655360, 12, -1572858, 655360, 12, -1638394, 655360, 12, -1638393, 655360, 12, -1572857, 655360, 12, -1572856, 655360, 12, -1638392, 655360, 12, -1638391, 655360, 12, -1572855, 655360, 12, -1507319, 655360, 12, -1507320, 655360, 12, -1507318, 655360, 12, -1572854, 655360, 12, -1638390, 655360, 12, -1638389, 655360, 12, -1572853, 655360, 12, -1507317, 655360, 12, -1441781, 655360, 12, -1441782, 655360, 12, -1376246, 655360, 12, -1310710, 655360, 12, -1245174, 655360, 12, -1179638, 655360, 12, -1114102, 655360, 12, -1048566, 655360, 12, -1048565, 655360, 12, -1114101, 655360, 12, -1179637, 655360, 12, -1245173, 655360, 12, -1310709, 655360, 12, -1376245, 655360, 12, -1376244, 655360, 12, -1441780, 655360, 12, -1507316, 655360, 12, -1572852, 655360, 12, -1638388, 655360, 12, -1638387, 655360, 12, -1572851, 655360, 12, -1507315, 655360, 12, -1441779, 655360, 12, -1376243, 655360, 12, -1310707, 655360, 12, -1310708, 655360, 12, -1245172, 655360, 12, -1179636, 655360, 12, -1114100, 655360, 12, -1048564, 655360, 12, -1048563, 655360, 12, -1114099, 655360, 12, -1179635, 655360, 12, -1245171, 655360, 12, -1245170, 655360, 12, -1310706, 655360, 12, -1376242, 655360, 12, -1441778, 655360, 12, -1507314, 655360, 12, -1572850, 655360, 12, -1638386, 655360, 12, -1638385, 655360, 12, -1572849, 655360, 12, -1507313, 655360, 12, -1441777, 655360, 12, -1376241, 655360, 12, -1310705, 655360, 12, -1245169, 655360, 12, -1179633, 655360, 12, -1179634, 655360, 12, -1114098, 655360, 12, -1048562, 589824, 12, -1048561, 655360, 12, -1114097, 655360, 12, -1114096, 655360, 12, -1179632, 655360, 12, -1245168, 655360, 12, -1310704, 655360, 12, -1376240, 655360, 12, -1441776, 655360, 12, -1507312, 655360, 12, -1572848, 655360, 12, -1638384, 655360, 12, -1638383, 655360, 12, -1572847, 655360, 12, -1507311, 655360, 12, -1441775, 655360, 12, -1376239, 655360, 12, -1310703, 655360, 12, -1245167, 655360, 12, -1179631, 655360, 12, -1114095, 655360, 12, -1048559, 655360, 12, -1048560, 655360, 12, -983023, 655360, 12, -917487, 655360, 12, -851951, 655360, 12, -851952, 655360, 12, -786416, 655360, 12, -851950, 589824, 12, -917486, 655360, 12, -983022, 655360, 12, -1048558, 655360, 12, -1114094, 655360, 12, -1179630, 655360, 12, -1245166, 655360, 12, -1310702, 655360, 12, -1376238, 589824, 12, -1441774, 655360, 12, -1507310, 655360, 12, -1572846, 655360, 12, -1638382, 655360, 12, -1638381, 655360, 12, -1572845, 655360, 12, -1507309, 655360, 12, -1441773, 655360, 12, -1376237, 655360, 12, -1310701, 655360, 12, -1245165, 655360, 12, -1179629, 655360, 12, -1114093, 655360, 12, -1048557, 655360, 12, -983021, 655360, 12, -917485, 655360, 12, -851949, 655360, 12, -786413, 655360, 12, -786414, 655360, 12, -720878, 655360, 12, -720879, 655360, 12, -655342, 655360, 12, -655341, 655360, 12, -720877, 655360, 12, -720876, 655360, 12, -786412, 655360, 12, -851948, 655360, 12, -917484, 655360, 12, -983020, 655360, 12, -1048556, 655360, 12, -1114092, 655360, 12, -1179628, 655360, 12, -1245164, 655360, 12, -1310700, 655360, 12, -1376236, 655360, 12, -1441772, 655360, 12, -1507308, 655360, 12, -1572844, 655360, 12, -1638380, 655360, 12, -1638379, 655360, 12, -1572843, 655360, 12, -1507307, 655360, 12, -1441771, 655360, 12, -1376235, 655360, 12, -1310699, 655360, 12, -1245163, 655360, 12, -1179627, 655360, 12, -1114091, 655360, 12, -1048555, 655360, 12, -983019, 655360, 12, -917483, 655360, 12, -851947, 589824, 12, -786411, 655360, 12, -720875, 655360, 12, -655339, 589824, 12, -655340, 655360, 12, -589804, 655360, 12, -524268, 655360, 12, -458732, 655360, 12, -393196, 655360, 12, -327660, 655360, 12, -262124, 655360, 12, -196588, 655360, 12, -131052, 655360, 12, -65516, 458752, 12, 20, 655360, 12, 19, 589824, 12, 65555, 655360, 12, 131091, 655360, 12, 196627, 655360, 12, 196626, 655360, 12, 262162, 655360, 12, 262161, 655360, 12, 327697, 458752, 12, 327696, 655360, 12, 327695, 655360, 12, 393231, 655360, 12, 393230, 655360, 12, 458766, 655360, 12, 458765, 655360, 12, 524301, 655360, 12, 524300, 655360, 12, 589836, 655360, 12, 589835, 655360, 12, 589834, 655360, 12, 524298, 655360, 12, 524297, 655360, 12, 589833, 655360, 12, 655369, 655360, 12, 655370, 655360, 12, 655371, 655360, 12, 589837, 655360, 12, 524302, 655360, 12, 524303, 655360, 12, 458767, 655360, 12, 458768, 655360, 12, 393232, 655360, 12, 393233, 655360, 12, 327698, 655360, 12, 262163, 655360, 12, 262164, 655360, 12, 196628, 655360, 12, 131092, 458752, 12, 65556, 655360, 12, 131093, 655360, 12, 196629, 655360, 12, 262165, 655360, 12, 262166, 655360, 12, 196630, 655360, 12, 131094, 655360, 12, 65558, 655360, 12, 22, 589824, 12, -65514, 655360, 12, -131050, 655360, 12, -196586, 655360, 12, -262122, 655360, 12, -327658, 655360, 12, -393194, 655360, 12, -458730, 655360, 12, -458731, 655360, 12, -524267, 655360, 12, -589803, 655360, 12, -393195, 655360, 12, -327659, 655360, 12, -262123, 655360, 12, -196587, 655360, 12, -131051, 655360, 12, -65515, 655360, 12, 21, 655360, 12, -458729, 655360, 12, -524265, 655360, 12, -589801, 655360, 12, -655337, 655360, 12, -720873, 655360, 12, -786409, 655360, 12, -851945, 655360, 12, -917481, 655360, 12, -983017, 655360, 12, -1048553, 655360, 12, -1114089, 655360, 12, -1179625, 655360, 12, -1245161, 655360, 12, -1310697, 655360, 12, -1376233, 655360, 12, -1441769, 655360, 12, -1507305, 655360, 12, -1572841, 655360, 12, -1638377, 655360, 12, -1703913, 655360, 12, -1703912, 655360, 12, -1638376, 655360, 12, -1572840, 655360, 12, -1507304, 458752, 12, -1441768, 655360, 12, -1376232, 655360, 12, -1310696, 655360, 12, -1245160, 655360, 12, -1179624, 655360, 12, -1114088, 655360, 12, -1048552, 655360, 12, -983016, 655360, 12, -917480, 655360, 12, -851944, 655360, 12, -786408, 655360, 12, -720872, 655360, 12, -655336, 655360, 12, -589800, 655360, 12, -524264, 655360, 12, -458728, 655360, 12, -393192, 655360, 12, -393193, 655360, 12, -327657, 655360, 12, -262121, 589824, 12, -196585, 655360, 12, -131049, 655360, 12, -65513, 589824, 12, 23, 458752, 12, 65559, 655360, 12, 131095, 655360, 12, 196631, 655360, 12, 262167, 655360, 12, 327703, 655360, 12, 327702, 655360, 12, 393238, 655360, 12, 458774, 655360, 12, 524310, 655360, 12, 589846, 655360, 12, 655382, 655360, 12, 720918, 655360, 12, 720919, 655360, 12, 655383, 655360, 12, 655384, 655360, 12, 589848, 655360, 12, 524312, 655360, 12, 458776, 655360, 12, 393240, 655360, 12, 327704, 458752, 12, 262168, 655360, 12, 196632, 655360, 12, 131096, 655360, 12, 65560, 655360, 12, 24, 655360, 12, -65512, 655360, 12, -131048, 655360, 12, -196584, 655360, 12, -262120, 655360, 12, -327656, 655360, 12, -327655, 655360, 12, -393191, 655360, 12, -458727, 655360, 12, -524263, 655360, 12, -589799, 655360, 12, -655335, 655360, 12, -720871, 655360, 12, -786407, 655360, 12, -851943, 655360, 12, -917479, 655360, 12, -983015, 655360, 12, -1048551, 655360, 12, -1114087, 655360, 12, -1179623, 655360, 12, -1245159, 655360, 12, -1310695, 655360, 12, -1376231, 655360, 12, -1441767, 655360, 12, -1507303, 655360, 12, -1572839, 655360, 12, -1638375, 655360, 12, -1703911, 655360, 12, -262119, 458752, 12, -196583, 655360, 12, -131047, 655360, 12, -65511, 655360, 12, 25, 458752, 12, 65561, 655360, 12, 393239, 655360, 12, 458775, 655360, 12, 524311, 655360, 12, 720920, 458752, 12, 786456, 655360, 12, 786455, 655360, 12, 851991, 655360, 12, 917527, 458752, 12, 983063, 655360, 12, 1048599, 655360, 12, 1048598, 655360, 12, 1114134, 655360, 12, 1179670, 655360, 12, 1179671, 655360, 12, 1114135, 655360, 12, 1114136, 655360, 12, 1048600, 655360, 12, 983064, 655360, 12, 917528, 655360, 12, 851992, 655360, 12, 1179672, 655360, 12, 1245208, 655360, 12, 1245207, 655360, 12, 1310743, 655360, 12, 1310742, 655360, 12, 1310744, 655360, 12, 1507323, 655360, 12, 1310728, 655360, 12)
+
+[node name="Details" type="TileMap" parent="Map"]
+tile_set = SubResource("TileSet_orc4v")
+format = 2
+layer_0/tile_data = PackedInt32Array(786437, 720896, 0, 1245199, 65536, 0, 983050, 65536, 0, 720916, 65536, 0, 983059, 851968, 0, 1048596, 327680, 0, 917523, 393216, 0, 983043, 393216, 0, 1114115, 458752, 0, 1179653, 524288, 0, 1114120, 262144, 0, -1114117, 393216, 3, -1179655, 327680, 3, -1179648, 65536, 3, -1179643, 327680, 3, -1638399, 196608, 3, -1507324, 0, 3, -1507322, 458752, 3, -1310712, 65536, 3, -1310714, 0, 3, -1114129, 131072, 2, -1179660, 131072, 2, -458762, 131072, 2, -65557, 131072, 2, 262126, 131072, 2, 655348, 131072, 2, 458740, 131072, 2, 917496, 131072, 2, 851964, 131072, 2, 720894, 131072, 2, -327684, 131072, 2, -720881, 131072, 2, 458737, 196608, 2, -196621, 196608, 2, 262136, 196608, 2, 917494, 196608, 2, 327676, 196608, 2, 196612, 196608, 2, 196614, 196608, 2, -786420, 196608, 2, -65554, 327680, 2, -65551, 327680, 2, 983026, 327680, 2, -524293, 327680, 2, -458755, 327680, 2, 393222, 327680, 2, 13, 327680, 2, -458747, 327680, 2, -524279, 327680, 2, -589810, 327680, 2, -917499, 0, 0, -917519, 393216, 2, -589835, 393216, 2, -851975, 393216, 2, -131088, 393216, 2, -5, 262144, 2, 589812, 393216, 2, 917489, 131072, 0, 1048563, 131072, 0, 786419, 131072, 0, 655347, 131072, 0, 720886, 131072, 0, 655350, 131072, 0, 655353, 131072, 0, 786427, 131072, 0, 851962, 131072, 0, 1048568, 131072, 0, 983030, 131072, 0, 262141, 393216, 2, -589828, 393216, 2, -655345, 393216, 2, -589809, 393216, 2, -393210, 393216, 2, 393215, 393216, 2, 720888, 458752, 2, 851961, 262144, 2, 786423, 262144, 2, 458742, 458752, 2, -262166, 458752, 2, -851961, 458752, 2, -851955, 262144, 2, 851952, 393216, 2, -1114126, 0, 2, -458769, 65536, 2, -327699, 0, 2, 131052, 65536, 2, -327692, 0, 2, -65549, 65536, 2, 65534, 0, 2, -131080, 65536, 2, 65530, 131072, 0, 65536, 131072, 0, -458760, 131072, 0, -786435, 131072, 0, -720891, 131072, 0, -524280, 131072, 0, -393211, 131072, 0, -655355, 0, 2, -786422, 0, 2, -786419, 0, 2, -589808, 65536, 2, -65537, 393216, 2, -262145, 393216, 2, -262149, 65536, 2, 262139, 65536, 2, 393211, 0, 2, 262142, 0, 2)
+
+[node name="Bamboos" type="Node" parent="."]
+
+[node name="Bamboo" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(-538, -531)
+
+[node name="Bamboo2" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(-724, -311)
+
+[node name="Bamboo3" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(-566, 124)
+
+[node name="Bamboo4" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(-1211, 187)
+
+[node name="Bamboo5" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(-1233, -351)
+
+[node name="Bamboo6" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(-922, -786)
+
+[node name="Bamboo7" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(-741, 577)
+
+[node name="Bamboo8" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(-164, 554)
+
+[node name="Bamboo9" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(758, 192)
+
+[node name="Bamboo10" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(763, -713)
+
+[node name="Bamboo11" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(-158, -96)
+
+[node name="Bamboo12" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(967, -238)
+
+[node name="Bamboo13" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(294, -594)
+
+[node name="Bamboo14" parent="Bamboos" instance=ExtResource("4_8jerw")]
+position = Vector2(560, -141)
+
+[node name="Killzone" parent="." instance=ExtResource("5_3xrri")]
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Killzone"]
+position = Vector2(-3, 1217)
+shape = SubResource("WorldBoundaryShape2D_5dw0q")
+
+[node name="CollisionShape2D2" type="CollisionShape2D" parent="Killzone"]
+shape = SubResource("WorldBoundaryShape2D_7ioaa")
+
+[node name="CollisionShape2D3" type="CollisionShape2D" parent="Killzone"]
+shape = SubResource("WorldBoundaryShape2D_fq7i5")
+
+[node name="CollisionShape2D4" type="CollisionShape2D" parent="Killzone"]
+shape = SubResource("WorldBoundaryShape2D_kp00i")
+
+[node name="Players" type="Node" parent="."]
+
+[node name="Player" parent="Players" instance=ExtResource("1_ykwem")]
+position = Vector2(204, -105)
+collision_mask = 7
+
+[node name="Overworld" type="Camera2D" parent="."]
+unique_name_in_owner = true
+position = Vector2(955, -128)
+zoom = Vector2(0.21, 0.21)
+
+[node name="Sync" type="Node" parent="."]
+script = ExtResource("7_c27o5")
+speed_up = 20.0
+
+[node name="WorldTimer" type="Timer" parent="."]
+unique_name_in_owner = true
+wait_time = 1000.0
+autostart = true
+
+[connection signal="death" from="Players/Player" to="." method="_on_player_death"]
+[connection signal="timeout" from="WorldTimer" to="." method="_on_timer_timeout"]
diff --git a/scenes/notice.tscn b/scenes/notice.tscn
new file mode 100644
index 0000000..852e08a
--- /dev/null
+++ b/scenes/notice.tscn
@@ -0,0 +1,4 @@
+[gd_scene format=3 uid="uid://dxwjan054vgw0"]
+
+[node name="Notice" type="Area2D"]
+collision_mask = 2
diff --git a/scenes/player.tscn b/scenes/player.tscn
new file mode 100644
index 0000000..f75cb4b
--- /dev/null
+++ b/scenes/player.tscn
@@ -0,0 +1,252 @@
+[gd_scene load_steps=41 format=3 uid="uid://c7rps714eqdg5"]
+
+[ext_resource type="Script" path="res://code/player.gd" id="1_iepw4"]
+[ext_resource type="Texture2D" uid="uid://b30lhx6f0uy74" path="res://assets/graphics/player/down_attack/attack_down.png" id="2_nre2m"]
+[ext_resource type="Texture2D" uid="uid://dxtdtufshr3tw" path="res://assets/graphics/player/left_attack/attack_left.png" id="3_byxsk"]
+[ext_resource type="Texture2D" uid="uid://bsocx4vc2sb6s" path="res://assets/graphics/player/right_attack/attack_right.png" id="4_8jqr7"]
+[ext_resource type="Texture2D" uid="uid://spquud6cue2l" path="res://assets/graphics/player/up_attack/attack_up.png" id="5_jmjp6"]
+[ext_resource type="Texture2D" uid="uid://dij0wyugh24b" path="res://assets/graphics/player/down_idle/idle_down.png" id="6_1snvs"]
+[ext_resource type="Texture2D" uid="uid://s31ghurbke8i" path="res://assets/graphics/player/left_idle/idle_left.png" id="7_5uysv"]
+[ext_resource type="Texture2D" uid="uid://dh3tuae2rueb" path="res://assets/graphics/player/right_idle/idle_right.png" id="8_i2d7d"]
+[ext_resource type="Texture2D" uid="uid://clmyffqm3bmo7" path="res://assets/graphics/player/up_idle/idle_up.png" id="9_vygid"]
+[ext_resource type="Texture2D" uid="uid://cs8hfdfrcj3ym" path="res://assets/graphics/player/down/down_0.png" id="10_ix4yj"]
+[ext_resource type="Texture2D" uid="uid://5sv3w4si1nrt" path="res://assets/graphics/player/down/down_1.png" id="11_n0p7r"]
+[ext_resource type="Texture2D" uid="uid://bmijyqm6i1c1c" path="res://assets/graphics/player/down/down_2.png" id="12_ewi2q"]
+[ext_resource type="Texture2D" uid="uid://c81kxx6dryb36" path="res://assets/graphics/player/down/down_3.png" id="13_uvjce"]
+[ext_resource type="Texture2D" uid="uid://bdbd32x12d60" path="res://assets/graphics/player/left/left_0.png" id="14_1ggki"]
+[ext_resource type="Texture2D" uid="uid://8jvqhpphj6np" path="res://assets/graphics/player/left/left_1.png" id="15_0b7dq"]
+[ext_resource type="Texture2D" uid="uid://cam3122hb8vfa" path="res://assets/graphics/player/left/left_2.png" id="16_4yut5"]
+[ext_resource type="Texture2D" uid="uid://b801fr00dpw8u" path="res://assets/graphics/player/left/left_3.png" id="17_xafwe"]
+[ext_resource type="Texture2D" uid="uid://3bsrlfk4poo1" path="res://assets/graphics/player/right/right_0.png" id="18_g74n4"]
+[ext_resource type="Texture2D" uid="uid://bjjcymlv4lkps" path="res://assets/graphics/player/right/right_1.png" id="19_r3xtt"]
+[ext_resource type="Texture2D" uid="uid://cfo77c6bv322j" path="res://assets/graphics/player/right/right_2.png" id="20_5b8or"]
+[ext_resource type="Texture2D" uid="uid://debleuxlf6kdt" path="res://assets/graphics/player/right/right_3.png" id="21_qn80v"]
+[ext_resource type="Texture2D" uid="uid://cbou2pxybkt4d" path="res://assets/graphics/player/up/up_0.png" id="22_5nuot"]
+[ext_resource type="Texture2D" uid="uid://o78bod3x5qss" path="res://assets/graphics/player/up/up_1.png" id="23_vkm2w"]
+[ext_resource type="Texture2D" uid="uid://crspttjaijn4g" path="res://assets/graphics/player/up/up_2.png" id="24_j1lfm"]
+[ext_resource type="Texture2D" uid="uid://b20c4l52ey54t" path="res://assets/graphics/player/up/up_3.png" id="25_mui4y"]
+[ext_resource type="PackedScene" uid="uid://dh6xtqap2c2j4" path="res://scenes/weapon.tscn" id="26_5p1ew"]
+[ext_resource type="PackedScene" uid="uid://bj4ap7bw0imhy" path="res://scenes/camera.tscn" id="27_dsoxo"]
+[ext_resource type="Script" path="res://code/AIController2D.gd" id="28_cl3w8"]
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_n5xny"]
+atlas = ExtResource("6_1snvs")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_1pcxv"]
+atlas = ExtResource("10_ix4yj")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_hc3sy"]
+atlas = ExtResource("11_n0p7r")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_ae5o2"]
+atlas = ExtResource("12_ewi2q")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_dvqaa"]
+atlas = ExtResource("13_uvjce")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_i6fhi"]
+atlas = ExtResource("14_1ggki")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_b6l7h"]
+atlas = ExtResource("22_5nuot")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_43afb"]
+atlas = ExtResource("23_vkm2w")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_kib0g"]
+atlas = ExtResource("24_j1lfm")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="AtlasTexture" id="AtlasTexture_3nifw"]
+atlas = ExtResource("25_mui4y")
+region = Rect2(0, 0, 64, 64)
+
+[sub_resource type="SpriteFrames" id="SpriteFrames_bjuky"]
+animations = [{
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("2_nre2m")
+}],
+"loop": false,
+"name": &"attack_down",
+"speed": 2.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("3_byxsk")
+}],
+"loop": false,
+"name": &"attack_left",
+"speed": 2.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("4_8jqr7")
+}],
+"loop": false,
+"name": &"attack_right",
+"speed": 2.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("5_jmjp6")
+}],
+"loop": false,
+"name": &"attack_up",
+"speed": 2.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_n5xny")
+}],
+"loop": false,
+"name": &"idle_down",
+"speed": 10.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("7_5uysv")
+}],
+"loop": false,
+"name": &"idle_left",
+"speed": 10.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("8_i2d7d")
+}],
+"loop": false,
+"name": &"idle_right",
+"speed": 10.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("9_vygid")
+}],
+"loop": false,
+"name": &"idle_up",
+"speed": 10.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_1pcxv")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_hc3sy")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_ae5o2")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_dvqaa")
+}],
+"loop": true,
+"name": &"move_down",
+"speed": 10.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_i6fhi")
+}, {
+"duration": 1.0,
+"texture": ExtResource("15_0b7dq")
+}, {
+"duration": 1.0,
+"texture": ExtResource("16_4yut5")
+}, {
+"duration": 1.0,
+"texture": ExtResource("17_xafwe")
+}],
+"loop": true,
+"name": &"move_left",
+"speed": 10.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("18_g74n4")
+}, {
+"duration": 1.0,
+"texture": ExtResource("19_r3xtt")
+}, {
+"duration": 1.0,
+"texture": ExtResource("20_5b8or")
+}, {
+"duration": 1.0,
+"texture": ExtResource("21_qn80v")
+}],
+"loop": true,
+"name": &"move_right",
+"speed": 10.0
+}, {
+"frames": [{
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_b6l7h")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_43afb")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_kib0g")
+}, {
+"duration": 1.0,
+"texture": SubResource("AtlasTexture_3nifw")
+}],
+"loop": true,
+"name": &"move_up",
+"speed": 10.0
+}]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_ilpv0"]
+size = Vector2(47, 48)
+
+[node name="Player" type="CharacterBody2D"]
+z_index = 5
+position = Vector2(0, -31)
+collision_layer = 2
+collision_mask = 6
+script = ExtResource("1_iepw4")
+
+[node name="Button" type="Button" parent="."]
+modulate = Color(1, 1, 1, 0)
+self_modulate = Color(1, 1, 1, 0)
+offset_left = -85.0
+offset_top = -86.0
+offset_right = 85.0
+offset_bottom = 93.0
+icon_alignment = 1
+
+[node name="Weapon" parent="." instance=ExtResource("26_5p1ew")]
+position = Vector2(-10, 48)
+
+[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
+position = Vector2(0, -1)
+sprite_frames = SubResource("SpriteFrames_bjuky")
+animation = &"idle_down"
+autoplay = "idle_down"
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(-1.5, 2)
+shape = SubResource("RectangleShape2D_ilpv0")
+
+[node name="AttackTimer" type="Timer" parent="."]
+wait_time = 0.4
+one_shot = true
+
+[node name="Camera" parent="." instance=ExtResource("27_dsoxo")]
+visible = false
+position = Vector2(-2, 18)
+
+[node name="AIController2D" type="Node2D" parent="."]
+script = ExtResource("28_cl3w8")
+
+[connection signal="pressed" from="Button" to="." method="_on_button_pressed"]
+[connection signal="toggled" from="Button" to="." method="_on_button_toggled"]
+[connection signal="timeout" from="AttackTimer" to="." method="_on_attack_timer_timeout"]
diff --git a/scenes/weapon.tscn b/scenes/weapon.tscn
new file mode 100644
index 0000000..3d0463f
--- /dev/null
+++ b/scenes/weapon.tscn
@@ -0,0 +1,100 @@
+[gd_scene load_steps=8 format=3 uid="uid://dh6xtqap2c2j4"]
+
+[ext_resource type="Texture2D" uid="uid://bpobfwslfc3qy" path="res://assets/graphics/weapons/sword/down.png" id="1_1yw4v"]
+[ext_resource type="Script" path="res://code/weapon.gd" id="1_utwve"]
+
+[sub_resource type="SpriteFrames" id="SpriteFrames_4n6kd"]
+animations = [{
+"frames": [{
+"duration": 1.0,
+"texture": ExtResource("1_1yw4v")
+}],
+"loop": true,
+"name": &"down",
+"speed": 5.0
+}]
+
+[sub_resource type="RectangleShape2D" id="RectangleShape2D_iedax"]
+size = Vector2(51, 79)
+
+[sub_resource type="Animation" id="Animation_0n3f6"]
+length = 0.001
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("AnimatedSprite2D:visible")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("CollisionShape2D:disabled")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [true]
+}
+
+[sub_resource type="Animation" id="Animation_vwacy"]
+resource_name = "attack"
+tracks/0/type = "value"
+tracks/0/imported = false
+tracks/0/enabled = true
+tracks/0/path = NodePath("AnimatedSprite2D:visible")
+tracks/0/interp = 1
+tracks/0/loop_wrap = true
+tracks/0/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [true]
+}
+tracks/1/type = "value"
+tracks/1/imported = false
+tracks/1/enabled = true
+tracks/1/path = NodePath("CollisionShape2D:disabled")
+tracks/1/interp = 1
+tracks/1/loop_wrap = true
+tracks/1/keys = {
+"times": PackedFloat32Array(0),
+"transitions": PackedFloat32Array(1),
+"update": 1,
+"values": [false]
+}
+
+[sub_resource type="AnimationLibrary" id="AnimationLibrary_sb3pq"]
+_data = {
+"RESET": SubResource("Animation_0n3f6"),
+"attack": SubResource("Animation_vwacy")
+}
+
+[node name="Weapon" type="Area2D"]
+collision_mask = 4
+script = ExtResource("1_utwve")
+
+[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="."]
+visible = false
+sprite_frames = SubResource("SpriteFrames_4n6kd")
+animation = &"down"
+flip_h = true
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
+position = Vector2(10.5, -15.5)
+shape = SubResource("RectangleShape2D_iedax")
+disabled = true
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+libraries = {
+"": SubResource("AnimationLibrary_sb3pq")
+}
+
+[connection signal="body_entered" from="." to="." method="_on_body_entered"]
diff --git a/script_templates/AIController/controller_template.gd b/script_templates/AIController/controller_template.gd
new file mode 100644
index 0000000..ea1ddf1
--- /dev/null
+++ b/script_templates/AIController/controller_template.gd
@@ -0,0 +1,43 @@
+# meta-name: AI Controller Logic
+# meta-description: Methods that need implementing for AI controllers
+# meta-default: true
+extends _BASE_
+
+#-- Methods that need implementing using the "extend script" option in Godot --#
+
+func get_obs() -> Dictionary:
+ assert(false, "the get_obs method is not implemented when extending from ai_controller")
+ return {"obs":[]}
+
+func get_reward() -> float:
+ assert(false, "the get_reward method is not implemented when extending from ai_controller")
+ return 0.0
+
+func get_action_space() -> Dictionary:
+ assert(false, "the get get_action_space method is not implemented when extending from ai_controller")
+ return {
+ "example_actions_continous" : {
+ "size": 2,
+ "action_type": "continuous"
+ },
+ "example_actions_discrete" : {
+ "size": 2,
+ "action_type": "discrete"
+ },
+ }
+
+func set_action(action) -> void:
+ assert(false, "the get set_action method is not implemented when extending from ai_controller")
+# -----------------------------------------------------------------------------#
+
+#-- Methods that can be overridden if needed --#
+
+#func get_obs_space() -> Dictionary:
+# May need overriding if the obs space is complex
+# var obs = get_obs()
+# return {
+# "obs": {
+# "size": [len(obs["obs"])],
+# "space": "box"
+# },
+# }
diff --git a/shell.nix b/shell.nix
new file mode 100644
index 0000000..f655597
--- /dev/null
+++ b/shell.nix
@@ -0,0 +1,11 @@
+with import {};
+
+mkShell {
+ NIX_LD_LIBRARY_PATH = lib.makeLibraryPath [
+ stdenv.cc.cc
+ ];
+ NIX_LD = lib.fileContents "${stdenv.cc}/nix-support/dynamic-linker";
+ shellHook = ''
+ export LD_LIBRARY_PATH=$NIX_LD_LIBRARY_PATH
+ '';
+}
diff --git a/stable_baselines3_example.py b/stable_baselines3_example.py
new file mode 100644
index 0000000..4697ab9
--- /dev/null
+++ b/stable_baselines3_example.py
@@ -0,0 +1,225 @@
+import argparse
+import os
+import pathlib
+from typing import Callable
+
+from stable_baselines3 import PPO
+from stable_baselines3.common.callbacks import CheckpointCallback
+from stable_baselines3.common.vec_env.vec_monitor import VecMonitor
+
+from godot_rl.core.utils import can_import
+from godot_rl.wrappers.onnx.stable_baselines_export import export_ppo_model_as_onnx
+from godot_rl.wrappers.stable_baselines_wrapper import StableBaselinesGodotEnv
+
+# To download the env source and binary:
+# 1. gdrl.env_from_hub -r edbeeching/godot_rl_BallChase
+# 2. chmod +x examples/godot_rl_BallChase/bin/BallChase.x86_64
+if can_import("ray"):
+ print("WARNING, stable baselines and ray[rllib] are not compatible")
+
+parser = argparse.ArgumentParser(allow_abbrev=False)
+parser.add_argument(
+ "--env_path",
+ default=None,
+ type=str,
+ help="The Godot binary to use, do not include for in editor training",
+)
+parser.add_argument(
+ "--experiment_dir",
+ default="logs/sb3",
+ type=str,
+ help="The name of the experiment directory, in which the tensorboard logs and checkpoints (if enabled) are "
+ "getting stored.",
+)
+parser.add_argument(
+ "--experiment_name",
+ default="experiment",
+ type=str,
+ help="The name of the experiment, which will be displayed in tensorboard and "
+ "for checkpoint directory and name (if enabled).",
+)
+parser.add_argument("--seed", type=int, default=0, help="seed of the experiment")
+parser.add_argument(
+ "--resume_model_path",
+ default=None,
+ type=str,
+ help="The path to a model file previously saved using --save_model_path or a checkpoint saved using "
+ "--save_checkpoints_frequency. Use this to resume training or infer from a saved model.",
+)
+parser.add_argument(
+ "--save_model_path",
+ default=None,
+ type=str,
+ help="The path to use for saving the trained sb3 model after training is complete. Saved model can be used later "
+ "to resume training. Extension will be set to .zip",
+)
+parser.add_argument(
+ "--save_checkpoint_frequency",
+ default=None,
+ type=int,
+ help=(
+ "If set, will save checkpoints every 'frequency' environment steps. "
+ "Requires a unique --experiment_name or --experiment_dir for each run. "
+ "Does not need --save_model_path to be set. "
+ ),
+)
+parser.add_argument(
+ "--onnx_export_path",
+ default=None,
+ type=str,
+ help="If included, will export onnx file after training to the path specified.",
+)
+parser.add_argument(
+ "--timesteps",
+ default=1_000_000,
+ type=int,
+ help="The number of environment steps to train for, default is 1_000_000. If resuming from a saved model, "
+ "it will continue training for this amount of steps from the saved state without counting previously trained "
+ "steps",
+)
+parser.add_argument(
+ "--inference",
+ default=False,
+ action="store_true",
+ help="Instead of training, it will run inference on a loaded model for --timesteps steps. "
+ "Requires --resume_model_path to be set.",
+)
+parser.add_argument(
+ "--linear_lr_schedule",
+ default=False,
+ action="store_true",
+ help="Use a linear LR schedule for training. If set, learning rate will decrease until it reaches 0 at "
+ "--timesteps"
+ "value. Note: On resuming training, the schedule will reset. If disabled, constant LR will be used.",
+)
+parser.add_argument(
+ "--viz",
+ action="store_true",
+ help="If set, the simulation will be displayed in a window during training. Otherwise "
+ "training will run without rendering the simulation. This setting does not apply to in-editor training.",
+ default=False,
+)
+parser.add_argument("--speedup", default=1, type=int, help="Whether to speed up the physics in the env")
+parser.add_argument(
+ "--n_parallel",
+ default=1,
+ type=int,
+ help="How many instances of the environment executable to " "launch - requires --env_path to be set if > 1.",
+)
+args, extras = parser.parse_known_args()
+
+
+def handle_onnx_export():
+ # Enforce the extension of onnx and zip when saving model to avoid potential conflicts in case of same name
+ # and extension used for both
+ if args.onnx_export_path is not None:
+ path_onnx = pathlib.Path(args.onnx_export_path).with_suffix(".onnx")
+ print("Exporting onnx to: " + os.path.abspath(path_onnx))
+ export_ppo_model_as_onnx(model, str(path_onnx))
+
+
+def handle_model_save():
+ if args.save_model_path is not None:
+ zip_save_path = pathlib.Path(args.save_model_path).with_suffix(".zip")
+ print("Saving model to: " + os.path.abspath(zip_save_path))
+ model.save(zip_save_path)
+
+
+def close_env():
+ try:
+ print("closing env")
+ env.close()
+ except Exception as e:
+ print("Exception while closing env: ", e)
+
+
+path_checkpoint = os.path.join(args.experiment_dir, args.experiment_name + "_checkpoints")
+abs_path_checkpoint = os.path.abspath(path_checkpoint)
+
+# Prevent overwriting existing checkpoints when starting a new experiment if checkpoint saving is enabled
+if args.save_checkpoint_frequency is not None and os.path.isdir(path_checkpoint):
+ raise RuntimeError(
+ abs_path_checkpoint + " folder already exists. "
+ "Use a different --experiment_dir, or --experiment_name,"
+ "or if previous checkpoints are not needed anymore, "
+ "remove the folder containing the checkpoints. "
+ )
+
+if args.inference and args.resume_model_path is None:
+ raise parser.error("Using --inference requires --resume_model_path to be set.")
+
+if args.env_path is None and args.viz:
+ print("Info: Using --viz without --env_path set has no effect, in-editor training will always render.")
+
+env = StableBaselinesGodotEnv(
+ env_path=args.env_path, show_window=args.viz, seed=args.seed, n_parallel=args.n_parallel, speedup=args.speedup
+)
+env = VecMonitor(env)
+
+
+# LR schedule code snippet from:
+# https://stable-baselines3.readthedocs.io/en/master/guide/examples.html#learning-rate-schedule
+def linear_schedule(initial_value: float) -> Callable[[float], float]:
+ """
+ Linear learning rate schedule.
+
+ :param initial_value: Initial learning rate.
+ :return: schedule that computes
+ current learning rate depending on remaining progress
+ """
+
+ def func(progress_remaining: float) -> float:
+ """
+ Progress will decrease from 1 (beginning) to 0.
+
+ :param progress_remaining:
+ :return: current learning rate
+ """
+ return progress_remaining * initial_value
+
+ return func
+
+
+if args.resume_model_path is None:
+ learning_rate = 0.0003 if not args.linear_lr_schedule else linear_schedule(0.0003)
+ model: PPO = PPO(
+ "MultiInputPolicy",
+ env,
+ batch_size=128,
+ ent_coef=0.001,
+ verbose=2,
+ n_steps=32,
+ tensorboard_log=args.experiment_dir,
+ learning_rate=learning_rate,
+ )
+else:
+ path_zip = pathlib.Path(args.resume_model_path)
+ print("Loading model: " + os.path.abspath(path_zip))
+ model = PPO.load(path_zip, env=env, tensorboard_log=args.experiment_dir)
+
+if args.inference:
+ obs = env.reset()
+ for i in range(args.timesteps):
+ action, _state = model.predict(obs, deterministic=True)
+ obs, reward, done, info = env.step(action)
+else:
+ learn_arguments = dict(total_timesteps=args.timesteps, tb_log_name=args.experiment_name)
+ if args.save_checkpoint_frequency:
+ print("Checkpoint saving enabled. Checkpoints will be saved to: " + abs_path_checkpoint)
+ checkpoint_callback = CheckpointCallback(
+ save_freq=(args.save_checkpoint_frequency // env.num_envs),
+ save_path=path_checkpoint,
+ name_prefix=args.experiment_name,
+ )
+ learn_arguments["callback"] = checkpoint_callback
+ try:
+ model.learn(**learn_arguments)
+ except KeyboardInterrupt:
+ print(
+ """Training interrupted by user. Will save if --save_model_path was
+ used and/or export if --onnx_export_path was used."""
+ )
+
+close_env()
+handle_onnx_export()
+handle_model_save()