diff --git a/class_overview.gd b/addons/class_overview.gd similarity index 100% rename from class_overview.gd rename to addons/class_overview.gd diff --git a/class_overview.tscn b/addons/class_overview.tscn similarity index 100% rename from class_overview.tscn rename to addons/class_overview.tscn diff --git a/class_properties.gd b/addons/class_properties.gd similarity index 100% rename from class_properties.gd rename to addons/class_properties.gd diff --git a/class_properties.tscn b/addons/class_properties.tscn similarity index 100% rename from class_properties.tscn rename to addons/class_properties.tscn diff --git a/custom_properties.gd b/addons/custom_properties.gd similarity index 100% rename from custom_properties.gd rename to addons/custom_properties.gd diff --git a/custom_properties.tscn b/addons/custom_properties.tscn similarity index 100% rename from custom_properties.tscn rename to addons/custom_properties.tscn diff --git a/data.gd b/addons/data.gd similarity index 100% rename from data.gd rename to addons/data.gd diff --git a/data_editor.gd b/addons/data_editor.gd similarity index 100% rename from data_editor.gd rename to addons/data_editor.gd diff --git a/data_editor_gui.gd b/addons/data_editor_gui.gd similarity index 100% rename from data_editor_gui.gd rename to addons/data_editor_gui.gd diff --git a/data_editor_gui.tscn b/addons/data_editor_gui.tscn similarity index 100% rename from data_editor_gui.tscn rename to addons/data_editor_gui.tscn diff --git a/data_item.gd b/addons/data_item.gd similarity index 100% rename from data_item.gd rename to addons/data_item.gd diff --git a/fonts/DroidSans.ttf b/addons/fonts/DroidSans.ttf similarity index 100% rename from fonts/DroidSans.ttf rename to addons/fonts/DroidSans.ttf diff --git a/fonts/DroidSerif-Bold.ttf b/addons/fonts/DroidSerif-Bold.ttf similarity index 100% rename from fonts/DroidSerif-Bold.ttf rename to addons/fonts/DroidSerif-Bold.ttf diff --git a/fonts/DroidSerif-BoldItalic.ttf b/addons/fonts/DroidSerif-BoldItalic.ttf similarity index 100% rename from fonts/DroidSerif-BoldItalic.ttf rename to addons/fonts/DroidSerif-BoldItalic.ttf diff --git a/fonts/DroidSerif-Italic.ttf b/addons/fonts/DroidSerif-Italic.ttf similarity index 100% rename from fonts/DroidSerif-Italic.ttf rename to addons/fonts/DroidSerif-Italic.ttf diff --git a/fonts/droid_sans_title.tres b/addons/fonts/droid_sans_title.tres similarity index 100% rename from fonts/droid_sans_title.tres rename to addons/fonts/droid_sans_title.tres diff --git a/fonts/droid_serif_bold.tres b/addons/fonts/droid_serif_bold.tres similarity index 100% rename from fonts/droid_serif_bold.tres rename to addons/fonts/droid_serif_bold.tres diff --git a/fonts/droid_serif_bolditalic.tres b/addons/fonts/droid_serif_bolditalic.tres similarity index 100% rename from fonts/droid_serif_bolditalic.tres rename to addons/fonts/droid_serif_bolditalic.tres diff --git a/fonts/droid_serif_italic.tres b/addons/fonts/droid_serif_italic.tres similarity index 100% rename from fonts/droid_serif_italic.tres rename to addons/fonts/droid_serif_italic.tres diff --git a/icons/empty.png b/addons/icons/empty.png similarity index 100% rename from icons/empty.png rename to addons/icons/empty.png diff --git a/icons/gom.png b/addons/icons/gom.png similarity index 100% rename from icons/gom.png rename to addons/icons/gom.png diff --git a/icons/icon_add.png b/addons/icons/icon_add.png similarity index 100% rename from icons/icon_add.png rename to addons/icons/icon_add.png diff --git a/icons/icon_copy.png b/addons/icons/icon_copy.png similarity index 100% rename from icons/icon_copy.png rename to addons/icons/icon_copy.png diff --git a/icons/icon_display-name.png b/addons/icons/icon_display-name.png similarity index 100% rename from icons/icon_display-name.png rename to addons/icons/icon_display-name.png diff --git a/icons/icon_duplicate.png b/addons/icons/icon_duplicate.png similarity index 100% rename from icons/icon_duplicate.png rename to addons/icons/icon_duplicate.png diff --git a/icons/icon_edit.png b/addons/icons/icon_edit.png similarity index 100% rename from icons/icon_edit.png rename to addons/icons/icon_edit.png diff --git a/icons/icon_empty.png b/addons/icons/icon_empty.png similarity index 100% rename from icons/icon_empty.png rename to addons/icons/icon_empty.png diff --git a/icons/icon_load.png b/addons/icons/icon_load.png similarity index 100% rename from icons/icon_load.png rename to addons/icons/icon_load.png diff --git a/icons/icon_move_down.png b/addons/icons/icon_move_down.png similarity index 100% rename from icons/icon_move_down.png rename to addons/icons/icon_move_down.png diff --git a/icons/icon_move_up.png b/addons/icons/icon_move_up.png similarity index 100% rename from icons/icon_move_up.png rename to addons/icons/icon_move_up.png diff --git a/icons/icon_multi_line.png b/addons/icons/icon_multi_line.png similarity index 100% rename from icons/icon_multi_line.png rename to addons/icons/icon_multi_line.png diff --git a/icons/icon_options.png b/addons/icons/icon_options.png similarity index 100% rename from icons/icon_options.png rename to addons/icons/icon_options.png diff --git a/icons/icon_reload_small.png b/addons/icons/icon_reload_small.png similarity index 100% rename from icons/icon_reload_small.png rename to addons/icons/icon_reload_small.png diff --git a/icons/icon_remove.png b/addons/icons/icon_remove.png similarity index 100% rename from icons/icon_remove.png rename to addons/icons/icon_remove.png diff --git a/icons/icon_rename.png b/addons/icons/icon_rename.png similarity index 100% rename from icons/icon_rename.png rename to addons/icons/icon_rename.png diff --git a/icons/icon_save.png b/addons/icons/icon_save.png similarity index 100% rename from icons/icon_save.png rename to addons/icons/icon_save.png diff --git a/icons/icon_script.png b/addons/icons/icon_script.png similarity index 100% rename from icons/icon_script.png rename to addons/icons/icon_script.png diff --git a/input_dialog.gd b/addons/input_dialog.gd similarity index 100% rename from input_dialog.gd rename to addons/input_dialog.gd diff --git a/input_dialog.tscn b/addons/input_dialog.tscn similarity index 100% rename from input_dialog.tscn rename to addons/input_dialog.tscn diff --git a/item_manager.gd b/addons/item_manager.gd similarity index 100% rename from item_manager.gd rename to addons/item_manager.gd diff --git a/item_tree.gd b/addons/item_tree.gd similarity index 100% rename from item_tree.gd rename to addons/item_tree.gd diff --git a/item_tree.tscn b/addons/item_tree.tscn similarity index 100% rename from item_tree.tscn rename to addons/item_tree.tscn diff --git a/no_classes.tscn b/addons/no_classes.tscn similarity index 100% rename from no_classes.tscn rename to addons/no_classes.tscn diff --git a/options.gd b/addons/options.gd similarity index 100% rename from options.gd rename to addons/options.gd diff --git a/options.tscn b/addons/options.tscn similarity index 100% rename from options.tscn rename to addons/options.tscn diff --git a/plugin.cfg b/addons/plugin.cfg similarity index 100% rename from plugin.cfg rename to addons/plugin.cfg diff --git a/property_item.gd b/addons/property_item.gd similarity index 100% rename from property_item.gd rename to addons/property_item.gd diff --git a/property_item.tscn b/addons/property_item.tscn similarity index 100% rename from property_item.tscn rename to addons/property_item.tscn diff --git a/screenshots/class.png b/addons/screenshots/class.png similarity index 100% rename from screenshots/class.png rename to addons/screenshots/class.png diff --git a/screenshots/editor.png b/addons/screenshots/editor.png similarity index 100% rename from screenshots/editor.png rename to addons/screenshots/editor.png diff --git a/style/light_gray_panel.tres b/addons/style/light_gray_panel.tres similarity index 100% rename from style/light_gray_panel.tres rename to addons/style/light_gray_panel.tres diff --git a/warn.gd b/addons/warn.gd similarity index 100% rename from warn.gd rename to addons/warn.gd diff --git a/demo/Shop.tscn b/demo/Shop.tscn new file mode 100644 index 0000000..f8e3cad --- /dev/null +++ b/demo/Shop.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=3 format=1] + +[ext_resource path="res://World.gd" type="Script" id=1] +[ext_resource path="res://ShopDialog.tscn" type="PackedScene" id=2] + +[node name="World" type="Node2D"] + +script/script = ExtResource( 1 ) + +[node name="ShopButtons" type="VButtonArray" parent="."] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 465.0 +margin/top = 43.0 +margin/right = 600.0 +margin/bottom = 191.0 +flat = false +button/count = 0 +button/min_button_size = -1.0 +button/align = 437 + +[node name="ShopDialog" parent="." instance=ExtResource( 2 )] + +visibility/visible = false + +[node name="Label" type="Label" parent="."] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 189.0 +margin/bottom = 14.0 +text = "Open this scene to test items and shops." +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[connection signal="button_selected" from="ShopButtons" to="." method="_on_ShopButtons_button_selected"] + + diff --git a/demo/ShopDialog.gd b/demo/ShopDialog.gd new file mode 100644 index 0000000..420e589 --- /dev/null +++ b/demo/ShopDialog.gd @@ -0,0 +1,23 @@ +extends WindowDialog + +onready var item_list = get_node("VBoxContainer/ItemList") + + +func create_shop(merchant): + var items_of_this_merchant = [] + var all_shop_items = data.get_items("shop_item") + for shop_item in all_shop_items.values(): + if shop_item.seller == merchant.name: + items_of_this_merchant.append(shop_item) + + var i = 0 + item_list.clear() + for shop_item in items_of_this_merchant: + item_list.add_item(shop_item.name) + item_list.set_item_metadata(i, shop_item) + i = i + 1 + + get_node("VBoxContainer/MerchantLabel").set_bbcode(merchant.name) + get_node("VBoxContainer/GreetingLabel").set_text(merchant.greeting) + + \ No newline at end of file diff --git a/demo/ShopDialog.tscn b/demo/ShopDialog.tscn new file mode 100644 index 0000000..52c84e4 --- /dev/null +++ b/demo/ShopDialog.tscn @@ -0,0 +1,75 @@ +[gd_scene load_steps=2 format=1] + +[ext_resource path="res://ShopDialog.gd" type="Script" id=1] + +[node name="WindowDialog" type="WindowDialog"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 316.0 +margin/bottom = 288.0 +popup/exclusive = false +window/title = "" +script/script = ExtResource( 1 ) + +[node name="VBoxContainer" type="VBoxContainer" parent="."] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +alignment = 0 + +[node name="MerchantLabel" type="RichTextLabel" parent="VBoxContainer"] + +rect/min_size = Vector2( 0, 30 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 316.0 +margin/bottom = 30.0 +custom_colors/default_color = Color( 1, 0, 0, 1 ) +bbcode/enabled = false +bbcode/bbcode = "<>" +visible_characters = -1 + +[node name="GreetingLabel" type="Label" parent="VBoxContainer"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 34.0 +margin/right = 316.0 +margin/bottom = 48.0 +text = "<>" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="ItemList" type="ItemList" parent="VBoxContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 52.0 +margin/right = 316.0 +margin/bottom = 288.0 + + diff --git a/demo/ShopTest.gd b/demo/ShopTest.gd new file mode 100644 index 0000000..f5177a6 --- /dev/null +++ b/demo/ShopTest.gd @@ -0,0 +1,19 @@ +extends Node2D + +onready var buttons_array = get_node("ShopButtons") +onready var shop_dialog = get_node("ShopDialog") + + +func _ready(): + var shop_types = ["Armor Shop", "Weapon Shop", "Inn", "Travelling Salesman"] + for shop_type in shop_types: + buttons_array.add_button(shop_type) + + +func _on_ShopButtons_button_selected( button_idx ): + var text = buttons_array.get_button_text(button_idx) + var all_merchants = data.get_items("merchant") + for merchant in all_merchants.values(): + if merchant.name == text: + shop_dialog.create_shop(merchant) + shop_dialog.popup_centered() \ No newline at end of file diff --git a/demo/ShopTest.tscn b/demo/ShopTest.tscn new file mode 100644 index 0000000..e529043 --- /dev/null +++ b/demo/ShopTest.tscn @@ -0,0 +1,46 @@ +[gd_scene load_steps=3 format=1] + +[ext_resource path="res://ShopTest.gd" type="Script" id=1] +[ext_resource path="res://ShopDialog.tscn" type="PackedScene" id=2] + +[node name="World" type="Node2D"] + +script/script = ExtResource( 1 ) + +[node name="ShopButtons" type="VButtonArray" parent="."] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 465.0 +margin/top = 43.0 +margin/right = 600.0 +margin/bottom = 191.0 +flat = false +button/count = 0 +button/min_button_size = -1.0 +button/align = 437 + +[node name="ShopDialog" parent="." instance=ExtResource( 2 )] + +visibility/visible = false + +[node name="Label" type="Label" parent="."] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 189.0 +margin/bottom = 14.0 +text = "Open this scene to test items and shops." +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[connection signal="button_selected" from="ShopButtons" to="." method="_on_ShopButtons_button_selected"] + + diff --git a/demo/Spellbook.gd b/demo/Spellbook.gd new file mode 100644 index 0000000..2b785bc --- /dev/null +++ b/demo/Spellbook.gd @@ -0,0 +1,30 @@ +extends Panel + +onready var spell_list = get_node("LeftVBox/ScrollContainer/SpellList") + +var icon_spell_unknown = preload("res://graphics/icon_spell_unknown.png") + +func _ready(): + var all_spells = data.get_items("spell") + var i = 0 + for spell in all_spells.values(): + var icon = null + if spell.icon: + icon = load(spell.icon) + else: + icon = icon_spell_unknown + spell_list.add_item(spell.name, icon) + spell_list.set_item_tooltip(i, spell.name) + spell_list.set_item_metadata(i, spell) + i = i + 1 + + spell_list.select(0) + _on_SpellList_item_selected(0) + +func _on_SpellList_item_selected( index ): + var spell = spell_list.get_item_metadata(index) + get_node("RightVBox/SkillName").set_text(spell.name) + get_node("RightVBox/Description").set_text(spell.description) + var element = data.get_item("element", spell.element) + get_node("RightVBox/Type").set_bbcode("[color=#" + element.color.to_html() + "]" + element.name + "[/color]") + get_node("RightVBox/BaseDamage").set_text("Base Damage: " + str(spell.base_damage)) diff --git a/demo/Spellbook.tscn b/demo/Spellbook.tscn new file mode 100644 index 0000000..6229108 --- /dev/null +++ b/demo/Spellbook.tscn @@ -0,0 +1,162 @@ +[gd_scene load_steps=3 format=1] + +[ext_resource path="res://Spellbook.gd" type="Script" id=1] +[ext_resource path="res://title_font.fnt" type="BitmapFont" id=2] + +[node name="Panel" type="Panel"] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +script/script = ExtResource( 1 ) + +[node name="LeftVBox" type="VBoxContainer" parent="."] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 200.0 +margin/bottom = 600.0 +alignment = 0 + +[node name="Label" type="Label" parent="LeftVBox"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 200.0 +margin/bottom = 21.0 +custom_fonts/font = ExtResource( 2 ) +text = "Spellbook" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="ScrollContainer" type="ScrollContainer" parent="LeftVBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 25.0 +margin/right = 200.0 +margin/bottom = 600.0 +scroll/horizontal = true +scroll/vertical = true + +[node name="SpellList" type="ItemList" parent="LeftVBox/ScrollContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 200.0 +margin/bottom = 575.0 + +[node name="RightVBox" type="VBoxContainer" parent="."] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 270.0 +margin/top = 20.0 +margin/right = 0.0 +margin/bottom = 0.0 +alignment = 0 + +[node name="SkillName" type="Label" parent="RightVBox"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 754.0 +margin/bottom = 21.0 +custom_fonts/font = ExtResource( 2 ) +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Description" type="Label" parent="RightVBox"] + +rect/min_size = Vector2( 0, 100 ) +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 25.0 +margin/right = 754.0 +margin/bottom = 125.0 +autowrap = true +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Type" type="RichTextLabel" parent="RightVBox"] + +rect/min_size = Vector2( 0, 20 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 129.0 +margin/right = 754.0 +margin/bottom = 149.0 +bbcode/enabled = true +bbcode/bbcode = "" +visible_characters = -1 + +[node name="BaseDamage" type="Label" parent="RightVBox"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 153.0 +margin/right = 754.0 +margin/bottom = 167.0 +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="Label" type="Label" parent="."] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 247.0 +margin/bottom = 14.0 +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[connection signal="item_selected" from="LeftVBox/ScrollContainer/SpellList" to="." method="_on_SpellList_item_selected"] + + diff --git a/demo/addons/godot_data_editor/.gitattributes b/demo/addons/godot_data_editor/.gitattributes new file mode 100644 index 0000000..bdb0cab --- /dev/null +++ b/demo/addons/godot_data_editor/.gitattributes @@ -0,0 +1,17 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Custom for Visual Studio +*.cs diff=csharp + +# Standard to msysgit +*.doc diff=astextplain +*.DOC diff=astextplain +*.docx diff=astextplain +*.DOCX diff=astextplain +*.dot diff=astextplain +*.DOT diff=astextplain +*.pdf diff=astextplain +*.PDF diff=astextplain +*.rtf diff=astextplain +*.RTF diff=astextplain diff --git a/demo/addons/godot_data_editor/README.md b/demo/addons/godot_data_editor/README.md new file mode 100644 index 0000000..c0d1563 --- /dev/null +++ b/demo/addons/godot_data_editor/README.md @@ -0,0 +1,114 @@ +# Godot Data Editor +This repository hosts a plugin for the [Godot Engine]. It allows users to enter data items based on Godot classes which are then serialized in either as json or binaries. Serialized items may be encrypted if desired. + +# Features +* Support for binary or json serialization +* Create data classes with the click of a button +* Use gdscript to add properties and logic to your data classes, all instances will be Nodes +* Make use of the built-in [export property hints] +* Add instance-specific custom properties +* Access data with a simple API using the _data_ singleton +* ALPHA: Use the notification/observer system to react to changes in data items +* ALPHA: Encrypt your data files + +# Screenshots +![editor_screenshot] +![class_screenshot] + +# Installation +* Open your project folder, e.g. "../MyGame/" +* Create a folder named "addons" (if not already present) +* In addons, create a folder named "godot_data_editor" +* Copy the content of this repository into it. You may remove the "sceenshots" ;) +* Open your project in the editor and navigate to the plugin (Scene -> Project Settings -> Plugins) +* The plugin "godot_data_editor" should now appear, change the status from "Inactive" to "Active" +* Restart the editor to make sure that the _data_ singleton is loaded properly + +I intend to upload the plugin to the AssetLib, once I feel it is stable enough. + +# System Requirements +The plugin was written for version *2.1.3* of the Godot Engine. Upcoming minor versions should be supported as well. +It is very likely that a number of changes will be necessary, once Godot 3 is released. + +# API / Tutorial +I created a little video which shows how to use the plugin to create a simple shop system: [[Link to video which does not exist yet :) ]] + +Working with data is rather simple, use the provided _data_ class to access the items. The following code snippets demonstrates item retrieval as well as the observation feature: +```gdscript +extends Node + +func _ready(): + # Get a single item + var herb = data.get_item("shop_item", "herb") + var price = herb.price + + # Get all items as dictionary (key: id, value: item) + var shop_items = data.get_items("shop_item") + for shop_item in shop_items.values(): + print(shop_item.price) + pass + + ####################################### + # Observe Properties: + # Please note that you currently have to update properties using the "update_property" to make use of this feature + ####################################### + + # Be notified when something about this herb changes + data.observe_item(self, herb, "herb_changed") + herb.update_property("name", "better_herb") + + # Be notified when the price of this herb changes, + data.observe_item_property(self, herb, "price", "herb_price_changed") + herb.update_property("price", 500) + + # Be notified when any item changes + var doge_axe = data.get_item("shop_item", "doge_axe") + data.observe_class(self, "shop_item", "shop_item_changed") + doge_axe.update_property("price", 500) + + # Overkill: be notified about everything + data.observe_all_changes(self, "something_changed") + + ####################################### + # Stop Observing: + # When you are no longer interested in updates, simply unsubscribe/stop observing + ####################################### + data.stop_observing_item_property(self, herb, "price") + data.stop_observing_item(self, herb) + data.stop_observing_class(self, "shop_item") + data.stop_observing_changes(self) + + +func herb_changed(item, property, value): + print("Something about this herb changed!") + +func herb_price_changed(item, property, value): + print("Herb price changed!") + +func shop_item_changed(item, property, value): + print(item.name + " changed! " + property + " : " + str(value)) + +func something_changed(item, property, value): + print("I guess something changed.") +``` + +# Please Contribute! +Please feel free to contribute. Unfortunately, the code base still is not documented that well and there are a number of bugs which will need to be ironed out. I am sure that there are many things I have been doing wrong, especially in regard to memory management. + +# Known Issues +* The "Rename Class" feature may not properly rename the class file if it still in use +* In some cases, the controls are not correctly resized - pressing "Reload" should usually do the trick though +* There is no support for undo/redo +* Pressing Ctrl+S will not save the data items but the current scene +* The _data_ singleton is only visible in the editor when the project is being restarted. This seems to be a limitation of the engine which does not allow reload the engine.cfg file +* The "class overview" screen is lacking any kind of useful content + +# HALP! Something went wrong! +Stay calm, most issues can be resolved by either pressing the "Reload" button or activating and deactivating the plugin. If the problem persists, there is likely an issue with your data. Check if the name of the class (which are stored in the "classes" folder by default) is the same as the folder name of your instances (by default called "data"). If this is the case, there might be a conflict with duplicate IDs or the like. Please post an issue here if this happened without any external influence (e.g. you edited the files manually in another editor). + + + +[Godot Engine]: +[export property hints]: +[editor_screenshot]: https://github.com/Stoeoeoe/godot_data_editor/blob/master/screenshots/editor.png "The Godot Data Editor" +[class_screenshot]: https://github.com/Stoeoeoe/godot_data_editor/blob/master/screenshots/class.png "Example Class" \ No newline at end of file diff --git a/demo/addons/godot_data_editor/class_overview.gd b/demo/addons/godot_data_editor/class_overview.gd new file mode 100644 index 0000000..fa254a2 --- /dev/null +++ b/demo/addons/godot_data_editor/class_overview.gd @@ -0,0 +1,10 @@ +tool +extends PanelContainer + + + +func _ready(): + pass + +func set_label(text): + get_node("Panel/Body/Label").set_text(text) diff --git a/demo/addons/godot_data_editor/class_overview.tscn b/demo/addons/godot_data_editor/class_overview.tscn new file mode 100644 index 0000000..19b4ddb --- /dev/null +++ b/demo/addons/godot_data_editor/class_overview.tscn @@ -0,0 +1,163 @@ +[gd_scene load_steps=4 format=1] + +[ext_resource path="res://addons/godot_data_editor/class_overview.gd" type="Script" id=1] +[ext_resource path="res://addons/godot_data_editor/style/light_gray_panel.tres" type="StyleBox" id=2] +[ext_resource path="res://addons/godot_data_editor/fonts/droid_serif_bold.tres" type="DynamicFont" id=3] + +[node name="ClassOverview" type="PanelContainer"] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +script/script = ExtResource( 1 ) + +[node name="Panel" type="Panel" parent="."] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 7.0 +margin/top = 7.0 +margin/right = 1273.0 +margin/bottom = 593.0 +custom_styles/panel = ExtResource( 2 ) + +[node name="Body" type="VBoxContainer" parent="Panel"] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 10.0 +margin/top = 10.0 +margin/right = 10.0 +margin/bottom = 10.0 +alignment = 0 + +[node name="ClassPropertiesLabel" type="Label" parent="Panel/Body"] + +visibility/visible = false +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1246.0 +margin/bottom = 19.0 +custom_fonts/font = ExtResource( 3 ) +text = "Static Class Properties" +uppercase = true +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="HSeparator" type="HSeparator" parent="Panel/Body"] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1246.0 +margin/bottom = 3.0 + +[node name="Control" type="Control" parent="Panel/Body"] + +rect/min_size = Vector2( 0, 15 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1246.0 +margin/bottom = 15.0 + +[node name="Scroll" type="ScrollContainer" parent="Panel/Body"] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 19.0 +margin/right = 1246.0 +margin/bottom = 566.0 +scroll/horizontal = true +scroll/vertical = true + +[node name="Statics" type="VBoxContainer" parent="Panel/Body/Scroll"] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1246.0 +margin/bottom = 0.0 +alignment = 0 + +[node name="NoStaticsPropertiesLabel" type="Label" parent="Panel/Body/Scroll/Statics"] + +visibility/visible = false +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1246.0 +margin/bottom = 14.0 +text = "There are no static properties for this class. Click below to add one." +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="AddStaticPropertyButton" type="Button" parent="Panel/Body/Scroll/Statics"] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 18.0 +margin/right = 1246.0 +margin/bottom = 38.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Add static property" +flat = false + +[node name="Label" type="Label" parent="Panel/Body"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 19.0 +margin/right = 1246.0 +margin/bottom = 33.0 +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + + diff --git a/demo/addons/godot_data_editor/class_properties.gd b/demo/addons/godot_data_editor/class_properties.gd new file mode 100644 index 0000000..828ef47 --- /dev/null +++ b/demo/addons/godot_data_editor/class_properties.gd @@ -0,0 +1,50 @@ +tool +extends Panel + +var property_item_class = preload("property_item.tscn") + +onready var class_properties_box = get_node("Body/Scroll/ClassProperties") +onready var no_class_properties_label = get_node("Body/Scroll/ClassProperties/NoClassPropertiesLabel") + +var item = null + +signal on_item_changed(item) + + +func build_properties(item): + self.item = item + for node in class_properties_box.get_children(): + if node.has_meta("property"): + class_properties_box.remove_child(node) + + + var number_of_properties = 0 + for property in item.get_property_list(): + if property["usage"] == (PROPERTY_USAGE_SCRIPT_VARIABLE + PROPERTY_USAGE_STORAGE + PROPERTY_USAGE_EDITOR + PROPERTY_USAGE_NETWORK): + no_class_properties_label.hide() + number_of_properties += 1 + var property_item = property_item_class.instance() + var property_name = property["name"] + var value = item.get(property_name) + property_item.initialize(property_name, property["type"], value, property["hint"], property["hint_string"]) + property_item.connect("property_item_load_button_down", self, "_property_item_requests_file_dialog", []) + var changed_values = [] + property_item.connect("on_property_value_changed", self, "item_changed", changed_values) + property_item.set_meta("property", true) + class_properties_box.add_child(property_item) + pass + if number_of_properties == 0: + no_class_properties_label.show() + + +func item_changed(property, value): + if item: + item.set(property, value) + emit_signal("on_item_changed", item) + + + + + + + diff --git a/demo/addons/godot_data_editor/class_properties.tscn b/demo/addons/godot_data_editor/class_properties.tscn new file mode 100644 index 0000000..286a149 --- /dev/null +++ b/demo/addons/godot_data_editor/class_properties.tscn @@ -0,0 +1,116 @@ +[gd_scene load_steps=4 format=1] + +[ext_resource path="res://addons/godot_data_editor/style/light_gray_panel.tres" type="StyleBox" id=1] +[ext_resource path="res://addons/godot_data_editor/class_properties.gd" type="Script" id=2] +[ext_resource path="res://addons/godot_data_editor/fonts/droid_serif_bold.tres" type="DynamicFont" id=3] + +[node name="ClassProperties" type="Panel"] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +custom_styles/panel = ExtResource( 1 ) +script/script = ExtResource( 2 ) + +[node name="Body" type="VBoxContainer" parent="."] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 10.0 +margin/top = 10.0 +margin/right = 10.0 +margin/bottom = 10.0 +alignment = 0 + +[node name="TitleLabel" type="Label" parent="Body"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1260.0 +margin/bottom = 2.0 +custom_fonts/font = ExtResource( 3 ) +text = "Class Properties" +uppercase = true +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="HSeparator" type="HSeparator" parent="Body"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 6.0 +margin/right = 1260.0 +margin/bottom = 9.0 + +[node name="Spacer" type="Control" parent="Body"] + +rect/min_size = Vector2( 0, 15 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 13.0 +margin/right = 1260.0 +margin/bottom = 28.0 + +[node name="Scroll" type="ScrollContainer" parent="Body"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 32.0 +margin/right = 1260.0 +margin/bottom = 580.0 +scroll/horizontal = true +scroll/vertical = true + +[node name="ClassProperties" type="VBoxContainer" parent="Body/Scroll"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 454.0 +margin/bottom = 14.0 +alignment = 0 + +[node name="NoClassPropertiesLabel" type="Label" parent="Body/Scroll/ClassProperties"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 454.0 +margin/bottom = 14.0 +text = "There are currently no class properties. Edit the Class to add new ones." +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + + diff --git a/demo/addons/godot_data_editor/custom_properties.gd b/demo/addons/godot_data_editor/custom_properties.gd new file mode 100644 index 0000000..420ee61 --- /dev/null +++ b/demo/addons/godot_data_editor/custom_properties.gd @@ -0,0 +1,77 @@ +tool +extends Panel + +var item = null +var property_item_class = preload("property_item.tscn") +var remove_icon = preload("icons/icon_remove.png") + + +onready var custom_properties_box = get_node("Body/Scroll/CustomProperties") +onready var no_custom_properties_label = get_node("Body/Scroll/CustomProperties/NoCustomPropertiesLabel") + +onready var item_manager = null # Item Manager, used to load, modify and save items + +signal on_item_changed(item) +signal new_custom_property_created +signal custom_property_add_requested +signal custom_property_delete_requested(custom_property_id) + +#TODO: Somehow the properties are initialized twice + +func _ready(): + pass + self.item_manager = Globals.get("item_manager") + +func build_properties(item): + self.item = item + var properties = item._custom_properties + for node in custom_properties_box.get_children(): + if node.has_meta("property"): + custom_properties_box.remove_child(node) + + var number_of_properties = 0 + var property_names = properties.keys() + property_names.sort() + for property_name in property_names: + no_custom_properties_label.hide() + number_of_properties += 1 + + var container = MarginContainer.new() + var property_item = property_item_class.instance() + var type = properties[property_name][0] + + # If there already is a value, read it, otherwise set it to null + var value = null + if properties[property_name].size() == 2: + value = properties[property_name][1] + + property_item.initialize(property_name, type, value, 0, "", true) + property_item.connect("custom_property_delete_requested", self, "emit_signal", ["custom_property_delete_requested", property_name, ]) + property_item.connect("property_item_load_button_down", self, "_property_item_requests_file_dialog", []) + var changed_values = [] + property_item.connect("on_property_value_changed", self, "item_changed", changed_values) + + container.set_meta("property", true) + container.add_child(property_item) + custom_properties_box.add_child(container) + + pass + if number_of_properties == 0: + no_custom_properties_label.show() + + +# Fires signal when the item's custom properties is to be updated, delegates to data_editor_gui. +func item_changed(property, value): + if item: + item._custom_properties[property][1] = value + emit_signal("on_item_changed", item) + + +# Delegates the deletion +func delete_custom_property(property_name): + emit_signal("custom_property_delete_requested", property_name) + + +# Fires signal when the item's custom properties is to be updated, delegates to data_editor_gui.func _on_NewCustomPropertyButton_button_down(): +func _on_NewCustomPropertyButton_button_down(): + emit_signal("custom_property_add_requested") \ No newline at end of file diff --git a/demo/addons/godot_data_editor/custom_properties.tscn b/demo/addons/godot_data_editor/custom_properties.tscn new file mode 100644 index 0000000..71471d2 --- /dev/null +++ b/demo/addons/godot_data_editor/custom_properties.tscn @@ -0,0 +1,134 @@ +[gd_scene load_steps=4 format=1] + +[ext_resource path="res://addons/godot_data_editor/style/light_gray_panel.tres" type="StyleBox" id=1] +[ext_resource path="res://addons/godot_data_editor/custom_properties.gd" type="Script" id=2] +[ext_resource path="res://addons/godot_data_editor/fonts/droid_serif_bold.tres" type="DynamicFont" id=3] + +[node name="Panel" type="Panel"] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +custom_styles/panel = ExtResource( 1 ) +script/script = ExtResource( 2 ) + +[node name="Body" type="VBoxContainer" parent="."] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 10.0 +margin/top = 10.0 +margin/right = 10.0 +margin/bottom = 10.0 +alignment = 0 + +[node name="TitleLabel" type="Label" parent="Body"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1260.0 +margin/bottom = 2.0 +custom_fonts/font = ExtResource( 3 ) +text = "Custom Properties" +uppercase = true +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="HSeparator" type="HSeparator" parent="Body"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 6.0 +margin/right = 1260.0 +margin/bottom = 9.0 + +[node name="Spacer" type="Control" parent="Body"] + +rect/min_size = Vector2( 0, 15 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 13.0 +margin/right = 1260.0 +margin/bottom = 28.0 + +[node name="Scroll" type="ScrollContainer" parent="Body"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 32.0 +margin/right = 1260.0 +margin/bottom = 556.0 +scroll/horizontal = true +scroll/vertical = true + +[node name="CustomProperties" type="VBoxContainer" parent="Body/Scroll"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 441.0 +margin/bottom = 524.0 +alignment = 0 + +[node name="NoCustomPropertiesLabel" type="Label" parent="Body/Scroll/CustomProperties"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 441.0 +margin/bottom = 14.0 +text = "There are no custom properties for this item. Click below to add one." +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="NewCustomPropertyButton" type="Button" parent="Body"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 560.0 +margin/right = 1260.0 +margin/bottom = 580.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Add new custom property" +flat = false + +[connection signal="button_down" from="Body/NewCustomPropertyButton" to="." method="_on_NewCustomPropertyButton_button_down"] + + diff --git a/demo/addons/godot_data_editor/data.gd b/demo/addons/godot_data_editor/data.gd new file mode 100644 index 0000000..656b16e --- /dev/null +++ b/demo/addons/godot_data_editor/data.gd @@ -0,0 +1,138 @@ +extends Node + +var item_manager = null +var items = {} +var values = {} + + +func _init(): + # Caution: This item manager may not be in sync with the one used by the editor + self.item_manager = preload("item_manager.gd").new() + self.items = item_manager.items + + +func get_item(item_class, id): + return item_manager.get_item(item_class, id) + + +func get_items(item_class): + return item_manager.get_items(item_class) + + +func _load_item(item_class, id): + items[item_class][id] = item_manager.load_item(item_class, id) + + +func load_item_value(item, property): + return get_progress(item._class, item._id, property) + + +func get_progress(item_class, id, property): + if items[item_class].has(id) and items[item_class][id].has(property): + return items[item_class][id][property] + + +func set_progress(item_class, id, property, value): + var item = item_manager.get_item(item_class, id) + var has_value = item.get(property) + if item and has_value: + item.set(property, value) + if has_user_signal("@any_value_changed"): + emit_signal("@any_value_changed", item, property, value) + + var signal_name = "" + signal_name = "@" + item_class + # Class signal + if has_user_signal(signal_name): + emit_signal(signal_name, item, property, value) + + # Item signal + signal_name = "@" + item_class + "|" + id + if has_user_signal(signal_name): + emit_signal(signal_name, item, property, value) + + # Property signal + signal_name = "@" + item_class + "|" + id + "|" + property + if has_user_signal(signal_name): + emit_signal(signal_name, item, property, value) + + return true + else: + return false + +func observe_all_changes(observer, method, binds=[], flags = 0): + var signal_name = "@any_value_changed" + self.add_user_signal(signal_name) # TODO: Args + self.connect(signal_name, observer, method, binds, flags) + +func observe_class(observer, item_class, method, binds=[], flags = 0): + var signal_name = "@" + item_class + self.add_user_signal(signal_name) # TODO: Args + self.connect(signal_name, observer, method, binds, flags) + +func observe_item(observer, item, method, binds=[], flags = 0): + var signal_name = "@" + item._class + "|" + item._id + if not has_user_signal(signal_name): + self.add_user_signal(signal_name) # TODO: Args + self.connect(signal_name, observer, method, binds, flags) + + +func observe_item_property(observer, item, property, method, binds=[], flags = 0): + var signal_name = "@" + item._class + "|" + item._id + "|" + property + if not has_user_signal(signal_name): + self.add_user_signal(signal_name) # TODO: Args + self.connect(signal_name, observer, method, binds, flags) + +func _get_relevant_connections(): + var relevant_connections = [] + var signals = get_signal_list() + for s in signals: + var name = s["name"] + if name.begins_with("@"): + for c in get_signal_connection_list(name): + relevant_connections.append(c) + return relevant_connections + + +func stop_observing_class(observer, item_class): + var connection_list = _get_relevant_connections() + for connection in connection_list: + var target = connection["target"] + var signal_info = connection["signal"].replace("@", "").split("|") + if signal_info.size() == 1 and signal_info[0] == item_class and target == observer: + self.disconnect(connection["signal"], target, connection["method"]) + +func stop_observing_item(observer, item): + var connection_list = _get_relevant_connections() + for connection in connection_list: + var target = connection["target"] + var signal_info = connection["signal"].replace("@", "").split("|") + if signal_info.size() == 2 and signal_info[0] == item._class and signal_info[1] == item._id and target == observer: + self.disconnect(connection["signal"], target, connection["method"]) + +func stop_observing_item_property(observer, item, property): + var connection_list = _get_relevant_connections() + for connection in connection_list: + var target = connection["target"] + var signal_info = connection["signal"].replace("@", "").split("|") + if signal_info.size() == 3 and signal_info[0] == item._class and signal_info[1] == item._id and signal_info[2] == property and target == observer: + self.disconnect(connection["signal"], target, connection["method"]) + +func stop_observing_changes(observer): + var connection_list = _get_relevant_connections() + for connection in connection_list: + var target = connection["target"] + if target == observer: + self.disconnect(connection["signal"], target, connection["method"]) + + +# observer.disconnect( + + +func set_item_progress(item, property, value): + set_progress(item._class, item._id, property, value) + +func get_progress_by_item(item): + + + \ No newline at end of file diff --git a/demo/addons/godot_data_editor/data_editor.gd b/demo/addons/godot_data_editor/data_editor.gd new file mode 100644 index 0000000..6cf0a39 --- /dev/null +++ b/demo/addons/godot_data_editor/data_editor.gd @@ -0,0 +1,97 @@ +tool +extends EditorPlugin + +var data_editor_class = preload("data_editor_gui.tscn") +var data_class = preload("data.gd") +var gui = null + +var all_items = {} + +signal data_item_class_opened(item_class) + +func _enter_tree(): + OS.set_low_processor_usage_mode(true) + check_for_data_singleton() + check_plugin_settings() + gui = data_editor_class.instance() + get_editor_viewport().add_child(gui) + gui.set_area_as_parent_rect() + gui.hide() + + +# Remove control and data singleton +func _exit_tree(): + OS.set_low_processor_usage_mode(false) + get_editor_viewport().remove_child(gui) + gui.free() + var config = ConfigFile.new() + var status = config.load("res://engine.cfg") + if status == OK: + if config.has_section_key("autoload", "data"): + config.set_value("autoload", "data", null) + config.save("res://engine.cfg") + # Check if the Classes and Data folders exist + Globals.clear("item_manager") + +func _ready(): + gui.connect("class_edit_requested", self, "edit_class", []) + Globals.set("debug_is_editor", true) + +# Opens the selected class in the Script Editor +func edit_class(item_class): + edit_resource(item_class) + + +func check_for_data_singleton(): + var config = ConfigFile.new() + var status = config.load("res://engine.cfg") + + + if status == OK: + if not config.has_section_key("autoload", "data"): + config.set_value("autoload", "data", "*res://addons/godot_data_editor/data.gd") + config.save("res://engine.cfg") + #var directory = Directory.new() + #directory.copy("res://engine.cfg", "res://engine.cfg_BACKUP") + +# Load the plugin settings and adds default if they do not exist. +# TODO: Obtain defaults from dialog +func check_plugin_settings(): + var config = ConfigFile.new() + var status = config.load("res://addons/godot_data_editor/plugin.cfg") + if status == OK: + if not config.has_section_key("custom", "class_directory"): + config.set_value("custom", "class_directory", "res://classes") + # TODO: Create folders + if not config.has_section_key("custom", "extension"): + config.set_value("custom", "extension", "json") + if not config.has_section_key("custom", "output_directory"): + config.set_value("custom", "output_directory", "res://data") + # TODO: Create folders + if not config.has_section_key("custom", "password"): + config.set_value("custom", "password", "") + if not config.has_section_key("custom", "sanitize_ids"): + config.set_value("custom", "sanitize_ids", true) + if not config.has_section_key("custom", "serializer"): + config.set_value("custom", "serializer", "json") + config.save("res://addons/godot_data_editor/plugin.cfg") + + +# Virtual: Name of the tool button on top +func get_name(): + return "Data" + +# Virtual: Makes sure that the control owns the main screen +func has_main_screen(): + return true + +# Virtual: +func make_visible(visible): + if(visible): + gui.reload() + gui.show() + + else: + gui.hide() + + diff --git a/demo/addons/godot_data_editor/data_editor_gui.gd b/demo/addons/godot_data_editor/data_editor_gui.gd new file mode 100644 index 0000000..99b2ede --- /dev/null +++ b/demo/addons/godot_data_editor/data_editor_gui.gd @@ -0,0 +1,405 @@ +tool +extends Control + +var selected_item = null +var selected_id = null +var selected_class = null + + +onready var item_tree = get_node("VBox/Body/ItemTree") +onready var id_label = get_node("VBox/Body/Content/VBox/Container/ItemIdLabel") + +onready var instance_details = get_node("VBox/Body/Content/VBox/InstanceDetails/") +onready var class_properties = get_node("VBox/Body/Content/VBox/InstanceDetails/HBox/ClassProperties") +onready var custom_properties = get_node("VBox/Body/Content/VBox/InstanceDetails/HBox/CustomProperties") +onready var class_overview = get_node("VBox/Body/Content/VBox/ClassOverview") +onready var no_classes = get_node("VBox/Body/Content/VBox/NoClasses") + +#onready var last_modified_date = get_node("VBox/Body/Content/VBox/Container/GridContainer/LastModifiedDate") +#onready var created_date = get_node("VBox/Body/Content/VBox/Container/GridContainer/CreatedDate") + + +onready var new_custom_property_dialog = get_node("NewCustomPropertyDialog") +onready var new_custom_property_name = get_node("NewCustomPropertyDialog/LineEdit") +onready var new_custom_property_type_options = get_node("NewCustomPropertyDialog/TypeOptions") + +onready var add_button = get_node("VBox/Head/Add") +onready var delete_button = get_node("VBox/Head/Delete") +onready var duplicate_button = get_node("VBox/Head/Duplicate") +onready var change_display_name_button = get_node("VBox/Body/Content/VBox/Container/HBox/DisplayName") +onready var rename_button = get_node("VBox/Head/Rename") +onready var save_button = get_node("VBox/Head/Save") +onready var save_all_button = get_node("VBox/Head/SaveAll") + +onready var copy_id_button = get_node("VBox/Body/Content/VBox/Container/HBox/CopyId") +onready var edit_class_button = get_node("VBox/Body/Content/VBox/Container/HBox/EditClass") + +# Dialogs +onready var input_dialog = get_node("InputDialog") + +onready var new_item_class_dialog = get_node("NewClassDialog") +onready var new_item_class_name = get_node("NewClassDialog/ClassName") +onready var new_item_class_icon = get_node("NewClassDialog/ClassIconPath") +onready var new_item_class_icon_dialog = get_node("NewClassDialog/ClassIconFileDialog") + + +onready var warn_dialog = get_node("WarnDialog") +onready var options_screen = get_node("OptionsDialog") + +var item_tree_class = preload("item_tree.tscn") +#var active_element = null +var item_manager = null + +signal class_edit_requested(script) +signal input_dialog_confirmed(text1, text2) + +# First initialize the item manager which is used for loading, saving and configs +func _init(): + item_manager = preload("item_manager.gd").new() # This item_manager will add itself to the globals + +func _ready(): + Globals.set("debug_is_editor", false) + # Tree signals + item_tree.connect("on_new_item_pressed", self, "handle_actions", ["add"]) + item_tree.connect("on_rename_pressed", self, "handle_actions", ["rename"]) + item_tree.connect("on_delete_pressed", self, "handle_actions", ["delete"]) + item_tree.connect("on_duplicate_pressed", self, "handle_actions", ["duplicate"]) + item_tree.connect("on_item_selected", self, "change_item_context", []) + item_tree.connect("on_open", self, "open_item", []) + + custom_properties.connect("custom_property_add_requested", self, "handle_actions", ["add_custom_property"]) + custom_properties.connect("new_custom_property_created", self, "handle_actions", ["add_custom_property"]) + custom_properties.connect("custom_property_delete_requested", self, "delete_custom_property", []) + class_properties.connect("on_item_changed", self, "toggle_item_dirty_state", []) + + options_screen.connect("extension_changed", item_manager, "rename_extension_of_all_items", []) + options_screen.connect("encryption_changed", item_manager, "delete_and_resave", []) + + item_manager.connect("class_insertion_failed", self, "show_warning", []) + item_manager.connect("item_insertion_failed", self, "show_warning", []) + item_manager.connect("custom_property_insertion_failed", self, "show_warning", []) + item_manager.connect("item_duplication_failed", self, "show_warning", []) +# item_manager.connect("class_is_invalid", self, "show_warning", []) + + # Add types to the custom property type dropdown + var type_names = item_manager.type_names.keys() + type_names.sort() + new_custom_property_type_options.clear() + var index = 0 + for type in type_names: + new_custom_property_type_options.add_item(type) + new_custom_property_type_options.set_item_metadata(index, item_manager.type_names[type]) + index += 1 + + # No classes available + var has_no_classes = item_manager.classes.size() == 0 + if has_no_classes: + change_display_name_button.set_disabled(has_no_classes) + duplicate_button.set_disabled(true) + save_button.set_disabled(true) + save_all_button.set_disabled(true) + save_all_button.set_disabled(true) + rename_button.set_disabled(true) + add_button.set_disabled(true) + delete_button.set_disabled(true) + copy_id_button.set_disabled(true) + edit_class_button.set_disabled(true) + no_classes.show() + id_label.set_text("No Classes") + instance_details.hide() + class_overview.hide() + else: + # Select the first item in the tree when loading the GUI + var all_classes = item_manager.classes.keys() + all_classes.sort() + selected_class = all_classes[0] + change_item_context(selected_item, selected_class) + +# TODO: Implement +func open_item(): + var item_path = item_manager.get_full_path(selected_item) + var program = "" + var os_name = OS.get_name() + if os_name == "Windows": + program = "explorer" + item_path = item_path.replace("/", "\\") # ~_~... + # TODO: Not sure if these work... Probably add the possibility to add a custom editor + elif os_name == "OSX": + program = "open" + else: + program = "nautilus" + OS.execute(program, [item_path], false) + +func change_item_context(selected_item, selected_class): + + if selected_class: + self.selected_class = selected_class + + + + # TODO: Move to method, clean up + var has_no_classes = item_manager.classes.size() == 0 + if has_no_classes: + change_display_name_button.set_disabled(has_no_classes) + duplicate_button.set_disabled(true) + save_button.set_disabled(true) + save_all_button.set_disabled(true) + save_all_button.set_disabled(true) + rename_button.set_disabled(true) + add_button.set_disabled(true) + delete_button.set_disabled(true) + copy_id_button.set_disabled(true) + edit_class_button.set_disabled(true) + no_classes.show() + instance_details.hide() + class_overview.hide() + id_label.set_text("No Classes") + + + # An item was selected + if selected_item: + # Context was lost, e.g. because of changes to the classes. Reload. + if selected_item and not selected_item.get("_id"): + self.item_manager.load_manager() + self.item_tree.load_tree(true) + selected_item = item_tree.select_first_element() + + change_display_name_button.set_disabled(false) + duplicate_button.set_disabled(false) + save_button.set_disabled(false) + save_all_button.set_disabled(false) + rename_button.set_disabled(false) + add_button.set_disabled(false) + delete_button.set_disabled(false) + copy_id_button.set_disabled(false) + edit_class_button.set_disabled(false) + + self.selected_item = selected_item + self.selected_id = selected_item._id + class_overview.hide() + no_classes.hide() + instance_details.show() + if selected_item._display_name == selected_id: + id_label.set_text(selected_id) + else: + id_label.set_text(selected_item._display_name + " (" + selected_id + ")") + + class_properties.build_properties(selected_item) + custom_properties.build_properties(selected_item) + # A class was selected + elif selected_class: + change_display_name_button.set_disabled(true) + duplicate_button.set_disabled(true) + save_button.set_disabled(true) + save_all_button.set_disabled(false) + rename_button.set_disabled(false) + add_button.set_disabled(false) + delete_button.set_disabled(false) + copy_id_button.set_disabled(false) + edit_class_button.set_disabled(false) + self.selected_item = null + self.selected_id = null + id_label.set_text(selected_class.capitalize()) + if item_manager.invalid_classes.has(selected_class): + class_overview.set_label("There is a problem with this class, please check if there are any issues. Press 'Reload' once you are ready.") + else: + class_overview.set_label("") + class_overview.show() + instance_details.hide() + no_classes.hide() + + + +func _on_ItemTree_on_new_item_created(new_item): + selected_item = new_item + + +func create_shortcut(keys): + var short_cut = ShortCut.new() + var input_event = InputEvent() + input_event.type = InputEvent.KEY + input_event.ID = keys + short_cut.set_shortcut(input_event) + +# TODO: Implement +func warn_about_reload(): + if item_manager.has_unsaved_items(): + input_dialog.popup(self, "reload_confirmed", tr("Confirm reload"), tr("Some changes have not been saved. \nThey will be discarded if you proceed. Are you sure you want to perform this action?")) + + +func reload(): + item_manager.load_manager() + item_tree.load_tree(true) + if item_manager.get_item(selected_class, selected_id): + item_tree.select_item(item_manager.get_item(selected_class, selected_id)) + + +func toggle_item_dirty_state(item): + item._dirty = true + item_tree.set_tree_item_label_text(item) + + +# Validation takes place in the item manager +func _on_NewCustomPropertyDialog_confirmed(): + var custom_property_id = new_custom_property_name.get_text().strip_edges() + var custom_property_type = new_custom_property_type_options.get_selected_metadata() + var success = item_manager.add_custom_property(selected_item, custom_property_id, custom_property_type) + if success: + item_tree.set_tree_item_label_text(selected_item) + toggle_item_dirty_state(selected_item) + custom_properties.build_properties(selected_item) + + +# TODO: Show confirmation dialog +func delete_custom_property(property_name): + item_manager.delete_custom_property(selected_item, property_name) + toggle_item_dirty_state(selected_item) + custom_properties.build_properties(selected_item) + + +# TODO: New Class Dialog is still a mess +func _on_AddClassButton_button_down(): + new_item_class_name.set_text("") + new_item_class_icon.set_text("") + new_item_class_icon_dialog.set_current_path("") + new_item_class_dialog.popup_centered() + new_item_class_name.grab_focus() + + +func _on_NewClassDialog_confirmed(): + var name = new_item_class_name.get_text().to_lower() + var icon_path = new_item_class_icon.get_text() + item_manager.create_class(name, icon_path) + item_tree.load_tree() + item_tree.select_class(name) + reload() + edit_class() + + +# New Class Dialog +func _on_NewClassIconSearchButton_button_down(): + new_item_class_icon_dialog.popup_centered() + +# Icon for new class was selected +func _on_NewClassIconFileDialog_file_selected(path): + new_item_class_icon.set_text(path) + +# General handler for a lot of actions to centralize the GUI logic a bit +func handle_actions(action, argument = ""): + if action == "add": + input_dialog.popup(self, "_on_add_item_confirmed", tr("New Item"), tr("Please enter an ID for and optionally a display name the new item"), tr("ID"), "", tr("Display Name (optional)"), "") + elif action == "rename": + if selected_item: + input_dialog.popup(self, "_on_rename_item_confirmed", tr("Rename Item"), tr("Please enter a new ID for this item."), "ID", selected_id) + else: + input_dialog.popup(self, "_on_rename_class_confirmed", tr("Rename Class"), tr("Please enter a new name for this class. All pending changes will be discarded!"), "ID", selected_class) + elif action == "duplicate": + var new_display_name = "" + if selected_item._dirty: + input_dialog.popup(self, "item_duplication_failed", tr("Item duplication failed"), tr("Before duplicating this item, please first save it.")) + return + selected_item._display_name = "" + input_dialog.popup(self, "_on_duplicate_confirmed", tr("Duplicate Item"), tr("Please enter a new ID for this item"), "ID", selected_id, tr("Display Name (optional)"), new_display_name) + elif action == "save": + item_manager.save_item(selected_item) + item_tree.load_tree() + #reload() + elif action == "save_all": + item_manager.save_all_items() + item_tree.load_tree() + #reload() + elif action == "reload": + item_manager.load_manager() + reload() + elif action == "new_class": + _on_AddClassButton_button_down() # TODO: Incorporate into dialog handling + elif action == "delete": + if selected_item: + input_dialog.popup(self, "_on_delete_item_confirmed", tr("Delete Item"), tr("Are you sure you want to delete this item?")) + else: + input_dialog.popup(self, "_on_delete_class_confirmed", tr("Delete Class"), tr("Are you sure you want to delete class along with all items?")) + elif action == "options": + options_screen.popup_centered() + elif action == "edit_class": + edit_class() + elif action == "copy_id": + copy_id() + elif action == "change_display_name": + input_dialog.popup(self, "change_display_name", tr("Change Display Name"), tr("Please enter a display name for this item."), "Display Name", selected_item._display_name) + elif action == "add_custom_property": + new_custom_property_name.set_text("") + new_custom_property_dialog.popup_centered() + new_custom_property_name.grab_focus() + +######################################################################### +# Handlers # +######################################################################### + +func _on_add_item_confirmed(id, display_name): + var new_item = item_manager.create_and_add_new_item(selected_class, id, display_name) + if new_item: + item_tree.add_leaf(new_item, true) + + +func _on_rename_item_confirmed(id): + item_manager.rename_item(selected_item, id) + reload() + + +func _on_rename_class_confirmed(name): + item_manager.rename_class(selected_class, name) + reload() + + +func _on_duplicate_confirmed(id, display_name): + var duplicated_item = item_manager.duplicate_item(selected_item, id, display_name, false) + item_tree.add_leaf(duplicated_item, true) + reload() + +func _on_delete_item_confirmed(): + item_manager.delete_item(selected_item) + reload() + + +func _on_delete_class_confirmed(): + item_manager.delete_class(selected_class) + if item_manager.classes.size() > 0: + item_tree.select_class(item_manager.class_names[0]) + else: + change_item_context(null, null) + reload() + +######################################################################### +# Buttons on the right # +######################################################################### +func change_display_name(new_name): + selected_item._display_name = new_name + toggle_item_dirty_state(selected_item) + change_item_context(selected_item, selected_class) + +func copy_id(): + if selected_item: + OS.set_clipboard(selected_id) + else: + OS.set_clipboard(selected_class) + +func edit_class(): + var script = item_manager.classes[selected_class] + emit_signal("class_edit_requested", script) + +##################################################### +# OTHERS +##################################################### + +func show_warning(title, text): + warn_dialog.set_title(title) + warn_dialog.set_text(text) + warn_dialog.popup_centered() + + +func log_text(text): + var file = File.new() + file.open("res://test.log", File.READ_WRITE) + var old_text = file.get_as_text() + var date = str(OS.get_datetime()["hour"]) + ":" + str(OS.get_datetime()["minute"]) + ":" + str(OS.get_datetime()["second"]) + "\t" + file.store_line(old_text + date + text) diff --git a/demo/addons/godot_data_editor/data_editor_gui.tscn b/demo/addons/godot_data_editor/data_editor_gui.tscn new file mode 100644 index 0000000..907cdf2 --- /dev/null +++ b/demo/addons/godot_data_editor/data_editor_gui.tscn @@ -0,0 +1,834 @@ +[gd_scene load_steps=22 format=1] + +[ext_resource path="res://addons/godot_data_editor/data_editor_gui.gd" type="Script" id=1] +[ext_resource path="res://addons/godot_data_editor/icons/icon_add.png" type="Texture" id=2] +[ext_resource path="res://addons/godot_data_editor/icons/icon_save.png" type="Texture" id=3] +[ext_resource path="res://addons/godot_data_editor/icons/icon_rename.png" type="Texture" id=4] +[ext_resource path="res://addons/godot_data_editor/icons/icon_duplicate.png" type="Texture" id=5] +[ext_resource path="res://addons/godot_data_editor/icons/icon_remove.png" type="Texture" id=6] +[ext_resource path="res://addons/godot_data_editor/icons/icon_reload_small.png" type="Texture" id=7] +[ext_resource path="res://addons/godot_data_editor/icons/icon_script.png" type="Texture" id=8] +[ext_resource path="res://addons/godot_data_editor/icons/icon_options.png" type="Texture" id=9] +[ext_resource path="res://addons/godot_data_editor/item_tree.tscn" type="PackedScene" id=10] +[ext_resource path="res://addons/godot_data_editor/icons/icon_display-name.png" type="Texture" id=11] +[ext_resource path="res://addons/godot_data_editor/icons/icon_copy.png" type="Texture" id=12] +[ext_resource path="res://addons/godot_data_editor/icons/icon_edit.png" type="Texture" id=13] +[ext_resource path="res://addons/godot_data_editor/fonts/droid_sans_title.tres" type="DynamicFont" id=14] +[ext_resource path="res://addons/godot_data_editor/class_properties.tscn" type="PackedScene" id=15] +[ext_resource path="res://addons/godot_data_editor/custom_properties.tscn" type="PackedScene" id=16] +[ext_resource path="res://addons/godot_data_editor/class_overview.tscn" type="PackedScene" id=17] +[ext_resource path="res://addons/godot_data_editor/no_classes.tscn" type="PackedScene" id=18] +[ext_resource path="res://addons/godot_data_editor/warn.gd" type="Script" id=19] +[ext_resource path="res://addons/godot_data_editor/options.tscn" type="PackedScene" id=20] +[ext_resource path="res://addons/godot_data_editor/input_dialog.tscn" type="PackedScene" id=21] + +[node name="godot_data_editor" type="Control"] + +anchor/right = 1 +anchor/bottom = 1 +rect/min_size = Vector2( 800, 0 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +script/script = ExtResource( 1 ) + +[node name="VBox" type="VBoxContainer" parent="."] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +alignment = 0 + +[node name="Head" type="HBoxContainer" parent="VBox"] + +rect/min_size = Vector2( 0, 22 ) +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1280.0 +margin/bottom = 28.0 +alignment = 0 + +[node name="Add" type="ToolButton" parent="VBox/Head"] + +rect/min_size = Vector2( 28, 28 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 56.0 +margin/bottom = 28.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Add" +icon = ExtResource( 2 ) +flat = true +align = 0 + +[node name="VSeparator5" type="VSeparator" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 60.0 +margin/top = 0.0 +margin/right = 63.0 +margin/bottom = 28.0 + +[node name="Save" type="ToolButton" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 67.0 +margin/top = 0.0 +margin/right = 127.0 +margin/bottom = 28.0 +disabled = true +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Save" +icon = ExtResource( 3 ) +flat = false + +[node name="SaveAll" type="ToolButton" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 131.0 +margin/top = 0.0 +margin/right = 212.0 +margin/bottom = 28.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Save All" +icon = ExtResource( 3 ) +flat = false + +[node name="VSeparator" type="VSeparator" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 216.0 +margin/top = 0.0 +margin/right = 219.0 +margin/bottom = 28.0 + +[node name="Rename" type="ToolButton" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 223.0 +margin/top = 0.0 +margin/right = 306.0 +margin/bottom = 28.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Rename" +icon = ExtResource( 4 ) +flat = false + +[node name="Duplicate" type="ToolButton" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 310.0 +margin/top = 0.0 +margin/right = 402.0 +margin/bottom = 28.0 +disabled = true +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Duplicate" +icon = ExtResource( 5 ) +flat = false + +[node name="Delete" type="ToolButton" parent="VBox/Head"] + +rect/min_size = Vector2( 28, 28 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 406.0 +margin/top = 0.0 +margin/right = 480.0 +margin/bottom = 28.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Delete" +icon = ExtResource( 6 ) +flat = true + +[node name="VSeparator3" type="VSeparator" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 484.0 +margin/top = 0.0 +margin/right = 487.0 +margin/bottom = 28.0 + +[node name="Refresh2" type="ToolButton" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 491.0 +margin/top = 0.0 +margin/right = 563.0 +margin/bottom = 28.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Reload" +icon = ExtResource( 7 ) +flat = false + +[node name="VSeparator2" type="VSeparator" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 567.0 +margin/top = 0.0 +margin/right = 570.0 +margin/bottom = 28.0 + +[node name="NewClass" type="ToolButton" parent="VBox/Head"] + +rect/min_size = Vector2( 28, 28 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 574.0 +margin/top = 0.0 +margin/right = 670.0 +margin/bottom = 28.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "New Class" +icon = ExtResource( 8 ) +flat = true +align = 0 + +[node name="VSeparator4" type="VSeparator" parent="VBox/Head"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 674.0 +margin/top = 0.0 +margin/right = 677.0 +margin/bottom = 28.0 + +[node name="Options" type="ToolButton" parent="VBox/Head"] + +rect/min_size = Vector2( 28, 28 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 681.0 +margin/top = 0.0 +margin/right = 763.0 +margin/bottom = 28.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Options" +icon = ExtResource( 9 ) +flat = true +align = 0 + +[node name="Search" type="LineEdit" parent="VBox/Head"] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 377.0 +margin/top = 0.0 +margin/right = 435.0 +margin/bottom = 28.0 +placeholder/text = "Search" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="HSeparator" type="HSeparator" parent="VBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 32.0 +margin/right = 1280.0 +margin/bottom = 35.0 + +[node name="Body" type="HSplitContainer" parent="VBox"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 39.0 +margin/right = 1280.0 +margin/bottom = 600.0 +split/offset = 0 +split/collapsed = false +split/dragger_visibility = 0 + +[node name="ItemTree" parent="VBox/Body" instance=ExtResource( 10 )] + +anchor/right = 0 +anchor/bottom = 0 +rect/min_size = Vector2( 165, 0 ) +size_flags/horizontal = 2 +size_flags/stretch_ratio = 0.0 +margin/right = 165.0 +margin/bottom = 561.0 + +[node name="Content" type="Panel" parent="VBox/Body"] + +visibility/self_opacity = 0.0 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 177.0 +margin/top = 0.0 +margin/right = 1280.0 +margin/bottom = 561.0 + +[node name="VBox" type="VBoxContainer" parent="VBox/Body/Content"] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 3 +size_flags/stretch_ratio = 0.0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +alignment = 0 + +[node name="Container" type="MarginContainer" parent="VBox/Body/Content/VBox"] + +rect/min_size = Vector2( 0, 25 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1103.0 +margin/bottom = 25.0 + +[node name="HBox" type="HBoxContainer" parent="VBox/Body/Content/VBox/Container"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 8.0 +margin/top = 0.0 +margin/right = 1103.0 +margin/bottom = 25.0 +custom_constants/separation = 15 +alignment = 2 + +[node name="DisplayName" type="ToolButton" parent="VBox/Body/Content/VBox/Container/HBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 0 +size_flags/vertical = 2 +margin/left = 722.0 +margin/top = 0.0 +margin/right = 892.0 +margin/bottom = 25.0 +disabled = true +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Change Display Name" +icon = ExtResource( 11 ) +flat = true +align = 0 + +[node name="CopyId" type="ToolButton" parent="VBox/Body/Content/VBox/Container/HBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 0 +size_flags/vertical = 2 +margin/left = 907.0 +margin/top = 0.0 +margin/right = 988.0 +margin/bottom = 25.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Copy ID" +icon = ExtResource( 12 ) +flat = true +align = 0 + +[node name="EditClass" type="ToolButton" parent="VBox/Body/Content/VBox/Container/HBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 0 +size_flags/vertical = 2 +margin/left = 1003.0 +margin/top = 0.0 +margin/right = 1095.0 +margin/bottom = 25.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Edit Class" +icon = ExtResource( 13 ) +flat = true +align = 0 + +[node name="ItemIdLabel" type="Label" parent="VBox/Body/Content/VBox/Container"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 8.0 +margin/top = 0.0 +margin/right = 1103.0 +margin/bottom = 25.0 +custom_fonts/font = ExtResource( 14 ) +custom_colors/font_color_shadow = Color( 0.300781, 0.300781, 0.300781, 1 ) +custom_constants/shadow_offset_x = 1 +custom_constants/shadow_offset_y = 1 +text = "Actor" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="GridContainer" type="GridContainer" parent="VBox/Body/Content/VBox/Container"] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 0 +size_flags/vertical = 2 +margin/left = 555.0 +margin/top = 0.0 +margin/right = 555.0 +margin/bottom = 25.0 +custom_constants/hseparation = 10 +columns = 2 + +[node name="Created" type="Label" parent="VBox/Body/Content/VBox/Container/GridContainer"] + +visibility/opacity = 0.25 +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 91.0 +margin/bottom = 14.0 +text = "Created:" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="CreatedDate" type="Label" parent="VBox/Body/Content/VBox/Container/GridContainer"] + +visibility/opacity = 0.25 +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 101.0 +margin/top = 0.0 +margin/right = 217.0 +margin/bottom = 14.0 +text = "01.01.01 01:01:01" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="LastModifiedLabel" type="Label" parent="VBox/Body/Content/VBox/Container/GridContainer"] + +visibility/opacity = 0.25 +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 18.0 +margin/right = 91.0 +margin/bottom = 32.0 +text = "Last modified:" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="LastModifiedDate" type="Label" parent="VBox/Body/Content/VBox/Container/GridContainer"] + +visibility/opacity = 0.25 +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 101.0 +margin/top = 18.0 +margin/right = 217.0 +margin/bottom = 32.0 +text = "01.01.01 01:01:01" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="VBoxContainer" type="VBoxContainer" parent="VBox/Body/Content/VBox/Container"] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 8.0 +margin/top = 0.0 +margin/right = 1103.0 +margin/bottom = 25.0 +alignment = 0 + +[node name="HSeparator" type="HSeparator" parent="VBox/Body/Content/VBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 29.0 +margin/right = 1103.0 +margin/bottom = 32.0 + +[node name="Spacer" type="Control" parent="VBox/Body/Content/VBox"] + +rect/min_size = Vector2( 0, 10 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 36.0 +margin/right = 1103.0 +margin/bottom = 46.0 + +[node name="InstanceDetails" type="PanelContainer" parent="VBox/Body/Content/VBox"] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 50.0 +margin/right = 1103.0 +margin/bottom = 561.0 + +[node name="HBox" type="HBoxContainer" parent="VBox/Body/Content/VBox/InstanceDetails"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 7.0 +margin/top = 7.0 +margin/right = 1096.0 +margin/bottom = 504.0 +alignment = 0 + +[node name="ClassProperties" parent="VBox/Body/Content/VBox/InstanceDetails/HBox" instance=ExtResource( 15 )] + +anchor/right = 0 +anchor/bottom = 0 +margin/right = 542.0 +margin/bottom = 497.0 + +[node name="CustomProperties" parent="VBox/Body/Content/VBox/InstanceDetails/HBox" instance=ExtResource( 16 )] + +anchor/right = 0 +anchor/bottom = 0 +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 546.0 +margin/right = 1089.0 +margin/bottom = 497.0 + +[node name="ClassOverview" parent="VBox/Body/Content/VBox" instance=ExtResource( 17 )] + +anchor/right = 0 +anchor/bottom = 0 +margin/top = 50.0 +margin/right = 1103.0 +margin/bottom = 561.0 + +[node name="NoClasses" parent="VBox/Body/Content/VBox" instance=ExtResource( 18 )] + +visibility/visible = false +anchor/right = 0 +anchor/bottom = 0 +margin/left = 0.0 +margin/top = 307.0 +margin/right = 1103.0 +margin/bottom = 561.0 + +[node name="WarnDialog" type="AcceptDialog" parent="."] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 350.0 +margin/bottom = 110.0 +popup/exclusive = true +window/title = "" +dialog/hide_on_ok = true +script/script = ExtResource( 19 ) + +[node name="NewClassDialog" type="ConfirmationDialog" parent="."] + +editor/display_folded = true +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 519.0 +margin/top = 193.0 +margin/right = 990.0 +margin/bottom = 316.0 +popup/exclusive = true +window/title = "New Class" +dialog/text = "Enter the name and the path to an optional icon" +dialog/hide_on_ok = true + +[node name="ClassName" type="LineEdit" parent="NewClassDialog"] + +focus_neighbour/bottom = NodePath("../ClassIconPath") +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 8.0 +margin/top = 27.0 +margin/right = 466.0 +margin/bottom = 51.0 +placeholder/text = "Name" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="ClassIconPath" type="LineEdit" parent="NewClassDialog"] + +focus_neighbour/top = NodePath("../ClassName") +focus_neighbour/right = NodePath("../NewClassIconSearchButton") +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 8.0 +margin/top = 60.0 +margin/right = 393.0 +margin/bottom = 84.0 +placeholder/text = "Icon Path (optional)" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="ClassIconFileDialog" type="FileDialog" parent="NewClassDialog"] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 393.0 +margin/bottom = 404.0 +popup/exclusive = true +window/title = "Open a File" +dialog/hide_on_ok = true +mode = 0 +access = 2 +filters = StringArray( "*.png" ) +show_hidden_files = false + +[node name="NewClassIconSearchButton" type="Button" parent="NewClassDialog"] + +focus_neighbour/left = NodePath("../ClassIconPath") +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 399.0 +margin/top = 61.0 +margin/right = 466.0 +margin/bottom = 83.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "Search" +flat = false + +[node name="OptionsDialog" parent="." instance=ExtResource( 20 )] + +visibility/visible = false +margin/right = 550.0 +margin/bottom = 310.0 + +[node name="InputDialog" parent="." instance=ExtResource( 21 )] + +visibility/visible = false + +[node name="NewCustomPropertyDialog" type="ConfirmationDialog" parent="."] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 117.0 +margin/top = 117.0 +margin/right = 489.0 +margin/bottom = 243.0 +popup/exclusive = false +window/title = "New custom property" +dialog/text = "Enter the name and type of the property" +dialog/hide_on_ok = true + +[node name="LineEdit" type="LineEdit" parent="NewCustomPropertyDialog"] + +focus_neighbour/bottom = NodePath("../TypeOptions") +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 7.0 +margin/top = 29.0 +margin/right = 363.0 +margin/bottom = 53.0 +placeholder/text = "Name" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="TypeOptions" type="OptionButton" parent="NewCustomPropertyDialog"] + +focus_neighbour/top = NodePath("../LineEdit") +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 7.0 +margin/top = 64.0 +margin/right = 363.0 +margin/bottom = 84.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "BOOL" +flat = false +align = 0 +selected = 0 +items = [ "BOOL", null, false, -1, 1, "COLOR", null, false, -1, 14, "IMAGE", null, false, -1, 15, "INT", null, false, -1, 2, "NODE_PATH", null, false, -1, 16, "OBJECT", null, false, -1, 18, "PLANE", null, false, -1, 9, "QUAT", null, false, -1, 10, "REAL", null, false, -1, 3, "RECT2", null, false, -1, 6, "STRING", null, false, -1, 4, "TRANSFORM", null, false, -1, 13, "VECTOR2", null, false, -1, 5, "VECTOR3", null, false, -1, 7 ] + +[connection signal="button_down" from="VBox/Head/Add" to="." method="handle_actions" binds= [ "add" ]] + +[connection signal="button_down" from="VBox/Head/Save" to="." method="handle_actions" binds= [ "save" ]] + +[connection signal="button_down" from="VBox/Head/SaveAll" to="." method="handle_actions" binds= [ "save_all" ]] + +[connection signal="button_down" from="VBox/Head/Rename" to="." method="handle_actions" binds= [ "rename" ]] + +[connection signal="button_down" from="VBox/Head/Duplicate" to="." method="handle_actions" binds= [ "duplicate" ]] + +[connection signal="button_down" from="VBox/Head/Delete" to="." method="handle_actions" binds= [ "delete" ]] + +[connection signal="button_down" from="VBox/Head/Refresh2" to="." method="handle_actions" binds= [ "reload" ]] + +[connection signal="button_down" from="VBox/Head/NewClass" to="." method="handle_actions" binds= [ "new_class" ]] + +[connection signal="button_down" from="VBox/Head/Options" to="." method="handle_actions" binds= [ "options" ]] + +[connection signal="button_down" from="VBox/Body/Content/VBox/Container/HBox/DisplayName" to="." method="handle_actions" binds= [ "change_display_name" ]] + +[connection signal="button_down" from="VBox/Body/Content/VBox/Container/HBox/CopyId" to="." method="handle_actions" binds= [ "copy_id" ]] + +[connection signal="button_down" from="VBox/Body/Content/VBox/Container/HBox/EditClass" to="." method="handle_actions" binds= [ "edit_class" ]] + +[connection signal="confirmed" from="NewClassDialog" to="." method="_on_NewClassDialog_confirmed"] + +[connection signal="file_selected" from="NewClassDialog/ClassIconFileDialog" to="." method="_on_NewClassIconFileDialog_file_selected"] + +[connection signal="button_down" from="NewClassDialog/NewClassIconSearchButton" to="." method="_on_NewClassIconSearchButton_button_down"] + +[connection signal="confirmed" from="NewCustomPropertyDialog" to="." method="_on_NewCustomPropertyDialog_confirmed"] + + diff --git a/demo/addons/godot_data_editor/data_item.gd b/demo/addons/godot_data_editor/data_item.gd new file mode 100644 index 0000000..5b0966e --- /dev/null +++ b/demo/addons/godot_data_editor/data_item.gd @@ -0,0 +1,55 @@ +extends Node + +# Class information +# No setter, that's why there is a comma +var _class setget ,get_class +var _class_name setget ,get_class_name + +var _dirty = false # TODO: Exclude +var _persistent = false # TODO: Exclude + +var _id = "" +var _display_name setget set_display_name,get_display_name +var _created = 0 +var _last_modified = 0 + + +# Instance-level custom properties, consists of arrays containing name, type, (hint and hint_text), default value +var _custom_properties = {} + +func _ready(): + pass + + + +func get_class(): + if _class: + return _class + else: + _class = self.get_script().get_path().get_file().basename() + return _class + + +func get_class_name(): + return self.get_class().capitalize() + + +func get_display_name(): + if _display_name == null or _display_name == "": + return self._id + else: + return _display_name + + +func set_display_name(name): + _display_name = name + + +func update_property(property, value): + var data_singleton = Globals.get_singleton("data") + if data_singleton: + data_singleton.set_progress(_class, _id, property, value) + + +func _init(id): + self._id = id diff --git a/demo/addons/godot_data_editor/fonts/DroidSans.ttf b/demo/addons/godot_data_editor/fonts/DroidSans.ttf new file mode 100644 index 0000000..efd1f8b Binary files /dev/null and b/demo/addons/godot_data_editor/fonts/DroidSans.ttf differ diff --git a/demo/addons/godot_data_editor/fonts/DroidSerif-Bold.ttf b/demo/addons/godot_data_editor/fonts/DroidSerif-Bold.ttf new file mode 100644 index 0000000..108ed39 Binary files /dev/null and b/demo/addons/godot_data_editor/fonts/DroidSerif-Bold.ttf differ diff --git a/demo/addons/godot_data_editor/fonts/DroidSerif-BoldItalic.ttf b/demo/addons/godot_data_editor/fonts/DroidSerif-BoldItalic.ttf new file mode 100644 index 0000000..045e8a6 Binary files /dev/null and b/demo/addons/godot_data_editor/fonts/DroidSerif-BoldItalic.ttf differ diff --git a/demo/addons/godot_data_editor/fonts/DroidSerif-Italic.ttf b/demo/addons/godot_data_editor/fonts/DroidSerif-Italic.ttf new file mode 100644 index 0000000..689a1ba Binary files /dev/null and b/demo/addons/godot_data_editor/fonts/DroidSerif-Italic.ttf differ diff --git a/demo/addons/godot_data_editor/fonts/droid_sans_title.tres b/demo/addons/godot_data_editor/fonts/droid_sans_title.tres new file mode 100644 index 0000000..4859ebc --- /dev/null +++ b/demo/addons/godot_data_editor/fonts/droid_sans_title.tres @@ -0,0 +1,11 @@ +[gd_resource type="DynamicFont" load_steps=2 format=1] + +[ext_resource path="res://addons/godot_data_editor/fonts/DroidSans.ttf" type="DynamicFontData" id=1] + +[resource] + +font/size = 22 +font/use_mipmaps = false +font/use_filter = false +font/font = ExtResource( 1 ) + diff --git a/demo/addons/godot_data_editor/fonts/droid_serif_bold.tres b/demo/addons/godot_data_editor/fonts/droid_serif_bold.tres new file mode 100644 index 0000000..d8bfb40 --- /dev/null +++ b/demo/addons/godot_data_editor/fonts/droid_serif_bold.tres @@ -0,0 +1,11 @@ +[gd_resource type="DynamicFont" load_steps=2 format=1] + +[ext_resource path="res://addons/godot_data_editor/fonts/DroidSerif-Bold.ttf" type="DynamicFontData" id=1] + +[resource] + +font/size = 16 +font/use_mipmaps = false +font/use_filter = false +font/font = ExtResource( 1 ) + diff --git a/demo/addons/godot_data_editor/fonts/droid_serif_bolditalic.tres b/demo/addons/godot_data_editor/fonts/droid_serif_bolditalic.tres new file mode 100644 index 0000000..07edaa0 --- /dev/null +++ b/demo/addons/godot_data_editor/fonts/droid_serif_bolditalic.tres @@ -0,0 +1,11 @@ +[gd_resource type="DynamicFont" load_steps=2 format=1] + +[ext_resource path="res://addons/godot_data_editor/fonts/DroidSerif-Italic.ttf" type="DynamicFontData" id=1] + +[resource] + +font/size = 16 +font/use_mipmaps = false +font/use_filter = false +font/font = ExtResource( 1 ) + diff --git a/demo/addons/godot_data_editor/fonts/droid_serif_italic.tres b/demo/addons/godot_data_editor/fonts/droid_serif_italic.tres new file mode 100644 index 0000000..07edaa0 --- /dev/null +++ b/demo/addons/godot_data_editor/fonts/droid_serif_italic.tres @@ -0,0 +1,11 @@ +[gd_resource type="DynamicFont" load_steps=2 format=1] + +[ext_resource path="res://addons/godot_data_editor/fonts/DroidSerif-Italic.ttf" type="DynamicFontData" id=1] + +[resource] + +font/size = 16 +font/use_mipmaps = false +font/use_filter = false +font/font = ExtResource( 1 ) + diff --git a/demo/addons/godot_data_editor/icons/empty.png b/demo/addons/godot_data_editor/icons/empty.png new file mode 100644 index 0000000..2504386 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/empty.png differ diff --git a/demo/addons/godot_data_editor/icons/gom.png b/demo/addons/godot_data_editor/icons/gom.png new file mode 100644 index 0000000..ca3781a Binary files /dev/null and b/demo/addons/godot_data_editor/icons/gom.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_add.png b/demo/addons/godot_data_editor/icons/icon_add.png new file mode 100644 index 0000000..297be14 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_add.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_copy.png b/demo/addons/godot_data_editor/icons/icon_copy.png new file mode 100644 index 0000000..d777f13 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_copy.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_display-name.png b/demo/addons/godot_data_editor/icons/icon_display-name.png new file mode 100644 index 0000000..7c44933 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_display-name.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_duplicate.png b/demo/addons/godot_data_editor/icons/icon_duplicate.png new file mode 100644 index 0000000..320b365 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_duplicate.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_edit.png b/demo/addons/godot_data_editor/icons/icon_edit.png new file mode 100644 index 0000000..c114d2f Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_edit.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_empty.png b/demo/addons/godot_data_editor/icons/icon_empty.png new file mode 100644 index 0000000..da163ba Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_empty.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_load.png b/demo/addons/godot_data_editor/icons/icon_load.png new file mode 100644 index 0000000..cc05e98 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_load.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_move_down.png b/demo/addons/godot_data_editor/icons/icon_move_down.png new file mode 100644 index 0000000..3934310 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_move_down.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_move_up.png b/demo/addons/godot_data_editor/icons/icon_move_up.png new file mode 100644 index 0000000..684013d Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_move_up.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_multi_line.png b/demo/addons/godot_data_editor/icons/icon_multi_line.png new file mode 100644 index 0000000..95a029c Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_multi_line.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_options.png b/demo/addons/godot_data_editor/icons/icon_options.png new file mode 100644 index 0000000..4db4c53 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_options.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_reload_small.png b/demo/addons/godot_data_editor/icons/icon_reload_small.png new file mode 100644 index 0000000..1397ac6 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_reload_small.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_remove.png b/demo/addons/godot_data_editor/icons/icon_remove.png new file mode 100644 index 0000000..289db46 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_remove.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_rename.png b/demo/addons/godot_data_editor/icons/icon_rename.png new file mode 100644 index 0000000..2df503f Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_rename.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_save.png b/demo/addons/godot_data_editor/icons/icon_save.png new file mode 100644 index 0000000..8695b78 Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_save.png differ diff --git a/demo/addons/godot_data_editor/icons/icon_script.png b/demo/addons/godot_data_editor/icons/icon_script.png new file mode 100644 index 0000000..5aa673f Binary files /dev/null and b/demo/addons/godot_data_editor/icons/icon_script.png differ diff --git a/demo/addons/godot_data_editor/input_dialog.gd b/demo/addons/godot_data_editor/input_dialog.gd new file mode 100644 index 0000000..67afc14 --- /dev/null +++ b/demo/addons/godot_data_editor/input_dialog.gd @@ -0,0 +1,58 @@ +tool +extends ConfirmationDialog + +#var text = "" +#var title = "" +var placeholder_1 = "" +var placeholder_2 = "" +var caller = null +var callback_method = "" + +onready var line_edit_1 = get_node("VBox/LineEdit1") +onready var line_edit_2 = get_node("VBox/LineEdit2") + + +#func _init(text, placerholder_1 = "", placeholder_2 = ""): + +func popup(caller, callback_method, title, text, placeholder_1 = "", default_text_1 = "", placeholder_2 = "", default_text_2 = ""): + self.caller = caller + self.callback_method = callback_method + self.placeholder_1 = placeholder_1 + self.placeholder_2 = placeholder_2 + + if not caller.is_connected("input_dialog_confirmed", caller, callback_method): + caller.connect("input_dialog_confirmed", caller, callback_method, []) + set_text(text) + set_title(title) + if placeholder_1 == "": + line_edit_1.hide() + else: + line_edit_1.show() + line_edit_1.set_placeholder(placeholder_1) + + + if placeholder_2 == "": + line_edit_2.hide() + else: + line_edit_2.show() + line_edit_2.set_placeholder(placeholder_2) + + line_edit_1.set_text(default_text_1) + line_edit_2.set_text(default_text_2) + self.popup_centered() + + if not line_edit_1.is_hidden(): + line_edit_1.grab_focus() + +func _on_ConfirmationDialog_confirmed(): + var text1 = line_edit_1.get_text().strip_edges() + var text2 = line_edit_2.get_text().strip_edges() + if placeholder_2: + caller.emit_signal("input_dialog_confirmed", text1, text2) + elif placeholder_1: + caller.emit_signal("input_dialog_confirmed", text1) + else: + caller.emit_signal("input_dialog_confirmed") + + + caller.disconnect("input_dialog_confirmed", caller, callback_method) \ No newline at end of file diff --git a/demo/addons/godot_data_editor/input_dialog.tscn b/demo/addons/godot_data_editor/input_dialog.tscn new file mode 100644 index 0000000..9501729 --- /dev/null +++ b/demo/addons/godot_data_editor/input_dialog.tscn @@ -0,0 +1,71 @@ +[gd_scene load_steps=2 format=1] + +[ext_resource path="res://addons/godot_data_editor/input_dialog.gd" type="Script" id=1] + +[node name="ConfirmationDialog" type="ConfirmationDialog"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 440.0 +margin/bottom = 150.0 +popup/exclusive = true +window/title = "Please Confirm..." +dialog/text = "Text" +dialog/hide_on_ok = true +script/script = ExtResource( 1 ) + +[node name="VBox" type="VBoxContainer" parent="."] + +anchor/top = 1 +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 8.0 +margin/top = 103.0 +margin/right = 8.0 +margin/bottom = 45.0 +custom_constants/separation = 10 +alignment = 0 + +[node name="LineEdit1" type="LineEdit" parent="VBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 424.0 +margin/bottom = 24.0 +placeholder/text = "Hint 1" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="LineEdit2" type="LineEdit" parent="VBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 34.0 +margin/right = 424.0 +margin/bottom = 58.0 +placeholder/text = "Hint 2" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[connection signal="confirmed" from="." to="." method="_on_ConfirmationDialog_confirmed"] + + diff --git a/demo/addons/godot_data_editor/item_manager.gd b/demo/addons/godot_data_editor/item_manager.gd new file mode 100644 index 0000000..416b681 --- /dev/null +++ b/demo/addons/godot_data_editor/item_manager.gd @@ -0,0 +1,607 @@ +extends Node + +# Holds a dictionary of dictionaries with all items (class and then items) +var items = {} + +var class_names = [] +var classes = {} +var invalid_classes = [] + +var config_class_directory = "" +var config_output_directory = "" +var config_sanitize_ids = "" +var config_encrypt = "" +var config_password = "" +var config_extension = "" +var config_serializer = "" + +signal class_is_invalid(item_class) +signal item_duplication_failed(title, reason) +signal item_insertion_failed(title, reason) +signal class_insertion_failed(title, reason) +signal custom_property_insertion_failed(title, reason) + +var property_blacklist = ["_dirty"] + +var default_type_values = { + str(TYPE_STRING): "", # OK for simple + str(TYPE_BOOL): false, # OK + str(TYPE_COLOR): Color(0,0,0), + str(TYPE_OBJECT): "res://", + str(TYPE_IMAGE): "res://", + str(TYPE_INT): 0, + str(TYPE_NODE_PATH): @"", + str(TYPE_REAL): 0.0, + str(TYPE_RECT2): Rect2(0,0,32,32), + str(TYPE_VECTOR2): Vector2(0,0), + str(TYPE_VECTOR3): Vector3(0,0,0), + str(TYPE_PLANE): Plane(0,0,0,0), + str(TYPE_QUAT): Quat(0,0,0,0), + str(TYPE_TRANSFORM): Transform(Vector3(0,0,0),Vector3(0,0,0),Vector3(0,0,0),Vector3(0,0,0)) + } + +var type_names = {"STRING":TYPE_STRING, "BOOL":TYPE_BOOL, "COLOR":TYPE_COLOR, "OBJECT":TYPE_OBJECT, "IMAGE":TYPE_IMAGE, "INT":TYPE_INT, "NODE_PATH":TYPE_NODE_PATH, "REAL":TYPE_REAL, "RECT2":TYPE_RECT2, "VECTOR2":TYPE_VECTOR2, "VECTOR3":TYPE_VECTOR3, "PLANE":TYPE_PLANE, "QUAT":TYPE_QUAT, "TRANSFORM":TYPE_TRANSFORM } + + +func _init(): + load_manager() + + +func load_manager(): + store_unsaved_changes() + initialize_variables() + load_config() + load_class_names() + load_classes() + set_up_item_folders() + load_items() + reload_unsaved_items() + Globals.set("item_manager", self) + +# Try to keep unsaved changes when (re)loading the item_manager +var unsaved_items = [] +func store_unsaved_changes(): + for item_class in items: + for item in items[item_class].values(): + # Check for id to prevent invalid entries from showing up + if item and item.get("_id") and (item._dirty or not item._persistent): + unsaved_items.append(item) + +# Create a duplicate of the unsaved item because this will not mess up changed properties +func reload_unsaved_items(): + for unsaved_item in unsaved_items: + print(unsaved_item._id) + duplicate_item(unsaved_item, unsaved_item._id, unsaved_item._display_name, true) +# new_item._dirty = true + + pass + unsaved_items = [] + + +func initialize_variables(): + items = {} + class_names = [] + invalid_classes = [] + classes = {} + + config_class_directory = "" + config_output_directory = "" + config_sanitize_ids = "" + config_encrypt = "" + config_password = "" + config_extension = "" + config_serializer = "" + +func load_config(): + var config = ConfigFile.new() + config.load("res://addons/godot_data_editor/plugin.cfg") + self.config_class_directory = config.get_value("custom", "class_directory") + self.config_output_directory = config.get_value("custom", "output_directory") + self.config_sanitize_ids = config.get_value("custom", "sanitize_ids") + self.config_encrypt = config.get_value("custom", "encrypt") + self.config_password = config.get_value("custom", "password") + self.config_serializer = config.get_value("custom", "serializer") + self.config_extension = config.get_value("custom", "extension") + + +func load_class_names(): + class_names.clear() + var directory = Directory.new() + if directory.open(config_class_directory) == OK: + directory.list_dir_begin() + var file_name = directory.get_next() + while (file_name != ""): + if file_name.extension() == "gd" and not directory.current_is_dir() and file_name != "data_item.gd" : + class_names.append(file_name.replace(".gd", "")) + file_name = directory.get_next() + class_names.sort() + + +# Loads the classes from disk +# TODO: Check if there is an issue with the class and display a warning instead of crashing the whole plugin... +func load_classes(): + classes = {} + for item_class in class_names: + classes[item_class] = load(config_class_directory + "/" + item_class + ".gd") + var error = classes[item_class].reload(true) + if not error == OK or not classes[item_class]: + emit_signal("class_is_invalid", item_class) + invalid_classes.append(item_class) + pass + + +# Creates the directories for the items if they do not yet exist +func set_up_item_folders(): + var directory = Directory.new() + for item_class in classes: + var path = config_output_directory + "/" + item_class + if not directory.dir_exists(path): + directory.make_dir_recursive(path) + +func get_item_path(item): + return config_output_directory + "/" + item._class + "/" + item._id + "." + config_extension + +func get_full_path(item): + return Globals.globalize_path(config_output_directory + "/" + item._class + "/" + item._id + "." + config_extension) +# return config_output_directory.replace("res://", "") + "/" + item._class + "/" + item._id + "." + config_extension + +func load_items(): + items.clear() + var directory = Directory.new() + for item_class in class_names: + items[item_class] = {} + + if invalid_classes.has(item_class): + continue + + directory.open(config_output_directory + "/" + item_class ) + directory.list_dir_begin() + var file_name = directory.get_next() + while (file_name != ""): + if file_name.extension() == config_extension and not directory.current_is_dir() : + var id = file_name.basename() + if config_serializer == "json": + items[item_class][id] = load_json_item(item_class, file_name) + elif config_serializer == "binary": + items[item_class][id] = load_binary_item(item_class, file_name) + else: + pass + items[item_class][id].set_name(items[item_class][id]._class + ":" + id) + file_name = directory.get_next() + pass + pass + +# Loads a single item stored in the binary format +func load_binary_item(item_class, file_name): + var file = File.new() + var id = file_name.basename() + var status = 0 + if not config_encrypt: + file.open(config_output_directory + "/" + item_class + "/" + file_name, File.READ) + else: + file.open_encrypted_with_pass(config_output_directory + "/" + item_class + "/" + file_name, File.READ, config_password) + + var item = classes[item_class].new(id) + if status == OK: + # Load all the variables + while file.get_pos() < file.get_len(): + var property_name = str(file.get_var()) + + var value = file.get_var() + item.set(property_name, value) + pass + + item._dirty = false + item._persistent = true + else: + pass # TODO: Handle + file.close() + return item + +# Loads a single item stored in the json format +func load_json_item(item_class, file_name): + var file = File.new() + var id = file_name.basename() + var status = file.open(config_output_directory + "/" + item_class + "/" + file_name, File.READ) + var item = classes[item_class].new(id) + if status == OK: + var text = file.get_as_text() + var dict = {} + dict.parse_json(text) + + for property_name in dict: + + + if property_name == "_custom_properties": + var value = dict["_custom_properties"] + item._custom_properties = {} + for custom_property in value: + item._custom_properties[custom_property] = [] + var cp_value = value[custom_property][0] + var cp_type = value[custom_property][1] + cp_value = parse_value(cp_type, cp_value) + item._custom_properties[custom_property].append(cp_type) + item._custom_properties[custom_property].append(cp_value) + else: + var value = dict[property_name][0] + var type = dict[property_name][1] + value = parse_value(type, value) + item.set(property_name, value) + pass + item._dirty = false + item._persistent = true + else: + pass # TODO: Handle + file.close() + return item + +# Handles some special cases of JSON deserialization, e.g. Color +func parse_value(type, value): + if type == TYPE_COLOR: + value = Color(value) + elif type == TYPE_PLANE: + var split = value.replace("(", "").replace(")", "").split(",") + value = Plane(split[0], split[1], split[2], split[3]) + elif type == TYPE_QUAT: + var split = value.replace("(", "").replace(")", "").split(",") + value = Quat(split[0], split[1], split[2], split[3]) + elif type == TYPE_RECT2: + var split = value.replace("(", "").replace(")", "").split(",") + value = Rect2(split[0], split[1], split[2], split[3]) + elif type == TYPE_TRANSFORM: + var split = value.replace("(", "").replace(")", "").split(",") + value = Transform(Vector3(split[0], split[1], split[2]), Vector3(split[3], split[4], split[5]), Vector3(split[6], split[7], split[8]), Vector3(split[9], split[10], split[11])) + return value + + +# Saves all items +func save_all_items(): + for item_class in items: + for id in items[item_class]: + save_item(items[item_class][id]) + pass + pass + +# Stores an item on the disk and updates the "last modified" property +func save_item(item): + if item: + item._last_modified= OS.get_unix_time() + if config_serializer == "json": + save_json_item(item) + elif config_serializer == "binary": + save_binary_item(item) + else: + pass + +# Saves a single binary item +func save_binary_item(item): + var file = File.new() + var status = 0 + if not config_encrypt: + status = file.open(get_item_path(item), File.WRITE) + else: + status = file.open_encrypted_with_pass(get_item_path(item), File.WRITE, config_password) + if status == OK: + for property in item.get_property_list(): + # Serialize each property, even those starting with an underscore because they might be informative to external editors + var property_name = property["name"] + var property_usage = property["usage"] + if property_usage >= PROPERTY_USAGE_SCRIPT_VARIABLE: + file.store_var(property_name) + file.store_var(item.get(property_name)) + pass + item._persistent = true + item._dirty = false + else: + pass #TODO: Handle + file.close() + +# Saves a single json item +func save_json_item(item): + var file = File.new() + var status = 0 + status = file.open(get_item_path(item), File.WRITE) + var dict = {} + if status == OK: + for property in item.get_property_list(): + # Serialize each property + var property_name = property["name"].json_escape() + var property_usage = property["usage"] + if property_usage >= PROPERTY_USAGE_SCRIPT_VARIABLE and not property_name in property_blacklist: + var type = typeof(item.get(property_name)) + var value = item.get(property_name) + + # Custom properties are handled separately since they are stored as arrays + if property_name == "_custom_properties": + dict["_custom_properties"] = {} + for custom_property in value: + var type = value[custom_property][0] + var sanitized_value = sanitize_variant(value[custom_property][1], type) + dict["_custom_properties"][custom_property] = [sanitized_value, type] + pass + # Normal properties are simply stored as type-value pairs in an array + else: + value = sanitize_variant(value, type) + dict[property_name] = [value, type] + pass + item._persistent = true + item._dirty = false + else: + #TODO: Handle + pass + file.store_string(dict.to_json()) + file.close() + + +func sanitize_variant(value, type): + if type == TYPE_COLOR: + value = value.to_html() + elif type == TYPE_STRING: + value = value.json_escape() + return value + + +# Deletes a single item +func delete_item(item): + var path = get_item_path(item) + var directory = Directory.new() + # TODO: Check why items[item._class].erase(item) doesn't work + var items_of_class = items[item._class] + var status = directory.remove(path) + load_manager() + + +# Gets all items of a specific class +func get_items(item_class): + if items.has(item_class): + return items[item_class] + else: + return null + + +# Gets a single item +func get_item(item_class, id): + if items.has(item_class) and items[item_class].has(id): + return items[item_class][id] + else: + return null + + +# Creates a new item of a given class, adds it to the items dictionary and returns the newly created item +func create_and_add_new_item(item_class, id, display_name): + id = sanitize_string(id) + id = rename_id_if_exists(item_class, id) + if id == "" or id == null: + emit_signal("item_insertion_failed", "Item insertion failed", "The item must haven an ID.") + return null + if items[item_class].has(id): + emit_signal("item_insertion_failed", "Item insertion failed", "The item could not be created.") + return null + var new_item = classes[item_class].new(id) + if display_name: + new_item._display_name = display_name + items[item_class][id] = new_item + new_item._created = OS.get_unix_time() + return new_item + +func duplicate_item(item, id, display_name, overwrite = true): + id = sanitize_string(id) + if not overwrite: + id = rename_id_if_exists(item._class, id) + if id == "" or id == null: + emit_signal("item_duplication_failed", "Item duplication failed", "The item must haven an ID.") + return null + if items[item._class].has(id) and not overwrite: + emit_signal("item_duplication_failed", "Item duplication failed", "The item could not be duplicated because it already exists.") + return null + + var new_item = classes[item._class].new(id) + # Copy all properties + for property in new_item.get_property_list(): + if property["usage"] >= PROPERTY_USAGE_SCRIPT_VARIABLE: + new_item.set(property["name"], item.get(property["name"])) + new_item._id = id + if display_name: + new_item._display_name = display_name + else: + new_item._display_name = new_item._id + + new_item._dirty = true + new_item._persistent = false + items[new_item._class][new_item._id] = new_item + items[new_item._class][id].set_name(new_item._class + ":" + id) + return new_item + +# Rename the item, delete the old entry, overwrite the id and save anew +# TODO: Could it still be referenced/locked somewhere? +# TODO: Check for duplicate ids? +func rename_item(item, new_id): + new_id = sanitize_string(new_id) + var directory = Directory.new() + directory.remove(get_item_path(item)) + if item._id == item._display_name: + item._display_name = new_id + item._id = new_id + save_item(item) + load_manager() + +# Adds a custom property to an item. +# Returns true if it succeeded, false if it failed +func add_custom_property(item, name, type): + name = sanitize_string(name.strip_edges()) + + if item.get(name): + emit_signal("custom_property_insertion_failed", "Custom Property Insertion Failed", "There already is a property with that name.") + return false + if item._custom_properties.has(name): + emit_signal("custom_property_insertion_failed", "Custom Property Insertion Failed", "There already is a custom property with that name.") + return false + elif name == '': + emit_signal("custom_property_insertion_failed", "Custom Property Insertion Failed", "The custom property name cannot be empty.") + return false + else: + item._custom_properties[str(name)] = [type, default_type_values[str(type)]] + item._dirty = true + return true + +func delete_custom_property(item, property_name): + item._custom_properties.erase(property_name) + +func delete_class(item_class): + # Delete items + var directory = Directory.new() + var path = config_output_directory + "/" + item_class + var status = directory.open(path) + if status == OK: + directory.list_dir_begin() + var file_name = directory.get_next() + while (file_name != ""): + if not directory.current_is_dir(): + directory.remove(path + "/" + file_name) + file_name = directory.get_next() + pass + directory.remove(path) + classes.erase(item_class) + class_names.erase(item_class) + items.erase(item_class) + + directory.remove(config_class_directory + "/" + item_class + ".gd") + directory.remove(config_class_directory + "/" + item_class + ".png") + +func create_class(name, icon_path): + # Check if the classes folder already exists. If not, create it- + var directory = Directory.new() + if not directory.dir_exists(config_class_directory): + directory.make_dir(config_class_directory) + + name = sanitize_string(name) + if name == "": + emit_signal("class_insertion_failed", tr("Invalid name"), tr("The class name cannot be empty.")) + return + elif class_names.has(name): + emit_signal("class_insertion_failed", tr("Invalid name"), tr("The class name already exists.")) + return + + # Handle icons + var icon_file = File.new() + if icon_path == "" or not icon_file.file_exists(icon_path): + icon_path = "res://addons/godot_data_editor/icons/icon_empty.png" + + var icon_resource = load(icon_path) + var icon_data = icon_resource.get_data() + if icon_data.get_width() <= 22 and icon_data.get_height() <= 22: + var directory = Directory.new() + var error = directory.copy(icon_path, config_class_directory + "/" + name + ".png") + if error != OK: + emit_signal("class_insertion_failed", tr("Could not copy icon"), tr("There was a problem while copying the icon. Was it already opened by another program?") + "\nError code: " + str(error)) + return + else: + emit_signal("class_insertion_failed", tr("Invalid icon size"), tr("Icon must be smaller than 22x22 pixels.")) + return + + # Create class + var class_source = "" + class_source += "extends \"res://addons/godot_data_editor/data_item.gd\"\n\n" + class_source += "export(String) var your_string_property = \"\"\n" + class_source += "export(bool) var your_boolean_property = true\n" + class_source += "export(Color) var your_color_property = Color(1,0,1)\n" + class_source += "\n\n\n" + class_source += "func _init(id).(id):\n" + class_source += "\tpass\n" + + var script_file = File.new() + var directory = Directory.new() + if not directory.dir_exists(config_class_directory): + directory.make_dir(config_class_directory) + + script_file.open(config_class_directory + "/" + name + ".gd", File.WRITE) + script_file.store_string(class_source) + script_file.close() + load_manager() + + +func sanitize_string(string): + if config_sanitize_ids: + return string.replace(" ", "_").replace("\\", "_").replace("/", "_").replace(":", "_").replace("*", "_").replace("?", "_").replace("\"", "_").replace("<", "_").replace(">", "_").replace("|", "_").to_lower() + else: + return string + +func rename_id_if_exists(item_class, id): + if not items[item_class].has(id): + return id + else: + var regex = RegEx.new() + regex.compile("(\\D*)(\\d*)") + var has_valid_name = false + var number = 0 + var current_name = id + while(true): + regex.find(current_name) + var id_without_number = regex.get_capture(1) + var number_at_end_string = regex.get_capture(2) + var number_at_end = int(number_at_end_string) + number = number + number_at_end + 1 + var new_id = id_without_number + str(number) + if not items[item_class].has(new_id): + return new_id + + +func rename_class(item_class, new_item_class): + new_item_class = sanitize_string(new_item_class) + var directory = Directory.new() + if new_item_class == "": + emit_signal("class_insertion_failed", tr("Invalid name"), tr("The class name cannot be empty.")) + return + elif class_names.has(new_item_class): + emit_signal("class_insertion_failed", tr("Invalid name"), tr("The class name already exists.")) + return + + directory.rename(config_class_directory + item_class + ".gd", config_class_directory + new_item_class + ".gd") + directory.rename(config_class_directory + item_class + ".png", config_class_directory + new_item_class + ".png") + directory.rename(config_output_directory + "/" + item_class, config_output_directory + "/" + new_item_class) + load_manager() + + +func rename_extension_of_all_items(new_extension, serializer): + var directory = Directory.new() + for item_class in class_names: + for id in items[item_class]: + var item = items[item_class][id] + var original_item_path = get_item_path(item) + var new_item_path = original_item_path.replace("." + config_extension, "." + new_extension) + if serializer == config_serializer: + directory.rename(original_item_path, new_item_path) + directory.remove(original_item_path) + load_config() + save_all_items() + else: + directory.remove(original_item_path) + load_config() + save_all_items() + pass + + +func delete_and_resave(is_encrypted, password): + var directory = Directory.new() + for item_class in class_names: + for id in items[item_class]: + var item = items[item_class][id] + var item_path = get_item_path(item) + directory.remove(item_path) + pass + pass + load_config() + save_all_items() + +func has_unsaved_items(): + for item_class in items: + for id in items[item_class]: + var item = items[item_class][id] + if item._dirty: + return true + pass + pass + return false + +# TODO: Lazy loading +# TODO: Arrays \ No newline at end of file diff --git a/demo/addons/godot_data_editor/item_tree.gd b/demo/addons/godot_data_editor/item_tree.gd new file mode 100644 index 0000000..70f3674 --- /dev/null +++ b/demo/addons/godot_data_editor/item_tree.gd @@ -0,0 +1,284 @@ +# Item Tree +tool +extends Control + +var dummy_root = null + + +onready var tree = get_node("Panel/VBox/Tree") # The item tree +onready var class_context_menu = get_node("ClassContextMenu") # Context menu when right clicking on a class +onready var instance_context_menu = get_node("InstanceContextMenu") # Context menu when right clicking on an instance +onready var filter_control = get_node("Panel/VBox/Margin/HBoxContainer/Filter") + +var item_manager = null # Item Manager, used to load, modify and save items + +var tree_roots = {} # Holds a copy of all tree roots, i.e. classes, accessible by class name +var tree_elements = {} # Reference to all tree elements, accessible by ["_roots"][item_class] (for the roots) and [item_class][id] for the items + +signal on_delete_pressed # Emitted when item is deleted +signal on_rename_pressed # Emitted when item is renamed +signal on_duplicate_pressed # Emitted when item is duplicated +signal on_new_item_pressed # Emitted when new item is created +signal on_open # Emitted when item is opened in OS +signal on_item_selected(item, is_leaf) # Emitted when a tree item is selected, carries the item and wheter or not it is a leaf element + +var last_selected = null # Reference to last selected item +var last_selected_id = "" # Name/id of last selected item +var last_selected_class = "" # Name/id of last selected class + +var plugin_config + +var filter = "" + +# Load the tree when ready +func _ready(): +# test = EditorPlugin.new() + tree.set_hide_root(true) + tree.set_select_mode(Tree.SELECT_SINGLE) + tree.set_allow_rmb_select(true) + load_tree() + + +func load_tree(is_reload = false): + plugin_config = ConfigFile.new() + plugin_config.load("res://addons/godot_data_editor/plugin.cfg") + + self.item_manager = Globals.get("item_manager") + tree_elements = {} + tree_roots = {} + #filter_control.set_text("") + #filter = "" + last_selected_id = "" + last_selected_class = "" + last_selected = null + var tree_element_to_be_selected = null + + # Store the class and name of the last selected item, in case the tree is reloaded + last_selected = tree.get_selected() + if last_selected: + if last_selected.has_meta("item"): + if last_selected.get_meta("item").get("_id"): + self.last_selected_id = last_selected.get_meta("item")._id + else: + self.last_selected_id = null + self.last_selected_class = last_selected.get_meta("class") + + + tree.clear() + + + # Create the roots for each item class, e.g. actors, monsters, crystals... + dummy_root = tree.create_item() + tree_elements["_roots"] = {} + var classes = item_manager.class_names + for item_class in classes: + var root = create_item_root(item_class) + tree_elements["_roots"][item_class] = root + pass + + # Populate the list with items + classes.sort() + for item_class in classes: + tree_elements[item_class] = {} + if item_manager.invalid_classes.has(item_class): + continue + + var ids = item_manager.items[item_class].keys() + ids.sort() + for id in ids: + var item = item_manager.get_item(item_class, id) + if filter == "" or id.find(filter) != -1: + var tree_item = add_leaf(item, false) + pass + pass + + if last_selected_id: + tree_element_to_be_selected = get_tree_item(last_selected_class, last_selected_id) + elif last_selected_class: + tree_element_to_be_selected = get_tree_item(last_selected_class) + elif tree.get_root().get_children(): + tree_element_to_be_selected = tree.get_root().get_children() + else: + tree_element_to_be_selected = null # No elements to be selected + + last_selected + + # Handle filter + if tree_element_to_be_selected and not filter_control.has_focus(): + tree.grab_focus() + tree_element_to_be_selected.select(0) + +func create_item_root(item_class): + var tree_item = tree.create_item(dummy_root) + tree_item.set_selectable(0, true) + tree_item.set_icon(0, load(plugin_config.get_value("custom", "class_directory") + "/" + item_class + ".png")) + tree_item.set_text(0, item_class.capitalize()) + tree_item.set_meta("class", item_class) + tree_roots[item_class] = tree_item + return tree_item + +func select_first_element(): + var first_element = tree.get_root().get_children() + if first_element: + first_element.select(0) + first_element = first_element.get_children() + last_selected = first_element.get_meta("item") + last_selected_id = last_selected._id + last_selected_class = last_selected._class + return last_selected + + + +# Creates a new tree item, optionally with an existing item +func add_leaf(item, update_order): + var id = item._id + var item_class = item._class + var tree_item = tree.create_item(tree_roots[item_class]) + set_tree_item_label_text(item, tree_item) + tree_item.set_selectable(0, true) + tree_item.set_meta("class", item_class) + tree_item.set_meta("item", item) + + tree_elements[item_class][id] = tree_item + + # Don't order the tree in the beginning as the ids will already be sorted + if update_order: + # Move the items which come before in the alphabet to the top + var elements_name_array = tree_elements[item_class].keys() + elements_name_array.sort() + tree_item.move_to_top() + var to_be_reordered = [] + for element_name in elements_name_array: + if str(id) > str(element_name) or str(id) == str(element_name): + to_be_reordered.append(element_name) + else: + break + pass + to_be_reordered.invert() + for element_name in to_be_reordered: + tree_elements[item_class][element_name].move_to_top() + pass + tree_item.select(0) + return tree_item + + +func set_tree_item_label_text(item, tree_item = null): + if tree_item == null: + tree_item = get_tree_item(item._class, item._id) + + if item._dirty or not item._persistent: + tree_item.set_text(0, " " + item._display_name + " (*)") + tree_item.set_custom_color(0, Color(1, 0.5, 0.5)) + else: + tree_item.set_text(0, " " + item._display_name) + tree_item.set_custom_color(0, Color(0.7, 0.7, 0.7)) + +func get_selected_item_root(): + var selected = tree.get_selected() + if selected.has_meta("item"): + return selected.get_parent() + else: + return selected + + +# A tree element in the tree was selected (either class or item) +func _on_Tree_cell_selected(): + emit_signal("on_item_selected", get_selected_item(), get_selected_class()) + +func get_selected_item(): + var selected = tree.get_selected() + if selected.has_meta("item"): + return selected.get_meta("item") + else: + return null + + +func get_selected_class(): + return tree.get_selected().get_meta("class") + + +func get_tree_item(item_class, id = ""): + if id != "": + if tree_elements.has(item_class) and tree_elements[item_class].has(id): + return tree_elements[item_class][id] + else: + return null + else: + if tree_elements["_roots"].has(item_class): + return tree_elements["_roots"][item_class] + else: + return null + +# Sets the selection to a specific tree item +func select_item(item): + if tree_elements.has(item._class) and tree_elements[item._class].has(item._id): + tree_elements[item._class][item._id].select(0) + +# Sets the selection to a specific class +func select_class(item_class): + if tree_elements["_roots"].has(item_class): + tree_elements["_roots"][item_class].select(0) + + +func _on_Filter_text_changed( text ): + self.filter = text + load_tree() + + + +# Right click context menu on leafs +# 0 = Add | 1 = Rename | 2 = Delete | 3 = Duplicate | 4 = Open +func _on_InstanceContextMenu_item_pressed(index): + if index == 0: + emit_signal("on_new_item_pressed") + elif index == 1: + emit_signal("on_rename_pressed") + elif index == 2: + emit_signal("on_delete_pressed") + elif index == 3: + emit_signal("on_duplicate_pressed") + elif index == 4: + emit_signal("on_open") + +########################################################### +# CLASS CONTEXT MENU # +########################################################### +func _on_ClassContextMenu_about_to_show(): + class_context_menu.set_item_text(0, tr("Add") + " " + get_selected_class().capitalize()) + +func _on_InstanceContextMenu_about_to_show(): + pass + +# Right click context menu on class branch +# 0 = Add | 1 = Delete Class +func _on_ClassContextMenu_item_pressed(index): + if index == 0: + emit_signal("on_new_item_pressed") + elif index == 1: + emit_signal("on_delete_pressed") + elif index == 2: + emit_signal("on_rename_pressed") + + + +func _on_Tree_item_rmb_selected(pos): + var is_leaf = get_selected_item() != null + if is_leaf: + instance_context_menu.set_pos(get_global_mouse_pos()) + instance_context_menu.popup() + else: + class_context_menu.set_pos(get_global_mouse_pos()) + class_context_menu.popup() + + +func _on_DeleteItemDialog_confirmed(): + var selected_item = get_selected_item() + if selected_item != null: + item_manager.delete_item(selected_item) + load_tree() + + + + + +#TODO: Proper memory management? diff --git a/demo/addons/godot_data_editor/item_tree.tscn b/demo/addons/godot_data_editor/item_tree.tscn new file mode 100644 index 0000000..e7ed451 --- /dev/null +++ b/demo/addons/godot_data_editor/item_tree.tscn @@ -0,0 +1,196 @@ +[gd_scene load_steps=8 format=1] + +[ext_resource path="res://addons/godot_data_editor/item_tree.gd" type="Script" id=1] +[ext_resource path="res://addons/godot_data_editor/icons/icon_add.png" type="Texture" id=2] +[ext_resource path="res://addons/godot_data_editor/icons/icon_remove.png" type="Texture" id=3] +[ext_resource path="res://addons/godot_data_editor/icons/icon_rename.png" type="Texture" id=4] +[ext_resource path="res://addons/godot_data_editor/icons/icon_duplicate.png" type="Texture" id=5] +[ext_resource path="res://addons/godot_data_editor/icons/icon_load.png" type="Texture" id=6] + +[sub_resource type="StyleBoxFlat" id=1] + +content_margin/left = -1.0 +content_margin/right = -1.0 +content_margin/top = -1.0 +content_margin/bottom = -1.0 +bg_color = Color( 0.172549, 0.164706, 0.196078, 1 ) +light_color = Color( 0.113725, 0.113725, 0.12549, 1 ) +dark_color = Color( 0.113725, 0.113725, 0.12549, 1 ) +border_size = 2 +border_blend = true +draw_bg = true + +[node name="Tree" type="Control"] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 0.0 +margin/bottom = 0.0 +script/script = ExtResource( 1 ) + +[node name="Panel" type="PanelContainer" parent="."] + +anchor/right = 1 +anchor/bottom = 1 +rect/min_size = Vector2( 150, 0 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 50.0 +margin/right = 0.0 +margin/bottom = 0.0 + +[node name="VBox" type="VBoxContainer" parent="Panel"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 7.0 +margin/top = 7.0 +margin/right = 1273.0 +margin/bottom = 543.0 +alignment = 0 + +[node name="Margin" type="MarginContainer" parent="Panel/VBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1266.0 +margin/bottom = 24.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="Panel/VBox/Margin"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 8.0 +margin/top = 0.0 +margin/right = 1266.0 +margin/bottom = 24.0 +alignment = 0 + +[node name="AddButton" type="ToolButton" parent="Panel/VBox/Margin/HBoxContainer"] + +visibility/visible = false +rect/min_size = Vector2( 28, 28 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 28.0 +margin/bottom = 28.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +icon = ExtResource( 2 ) +flat = true + +[node name="AddButton2" type="ToolButton" parent="Panel/VBox/Margin/HBoxContainer"] + +visibility/visible = false +rect/min_size = Vector2( 28, 28 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 32.0 +margin/top = 0.0 +margin/right = 60.0 +margin/bottom = 28.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +icon = ExtResource( 3 ) +flat = true + +[node name="Filter" type="LineEdit" parent="Panel/VBox/Margin/HBoxContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1258.0 +margin/bottom = 24.0 +placeholder/text = "Search" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="Tree" type="Tree" parent="Panel/VBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 28.0 +margin/right = 1266.0 +margin/bottom = 536.0 +custom_styles/bg = SubResource( 1 ) +custom_colors/guide_color = Color( 0.398438, 0.398438, 0.398438, 1 ) +custom_constants/hseparation = 4 + +[node name="ClassContextMenu" type="PopupMenu" parent="."] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 20.0 +margin/bottom = 20.0 +popup/exclusive = false +items = [ "Add Item", ExtResource( 2 ), false, false, false, 0, 0, null, "", false, "Delete Class", ExtResource( 3 ), false, false, false, 1, 0, null, "", false, "Rename Class", ExtResource( 4 ), false, false, false, -1, 0, null, "", false ] + +[node name="InstanceContextMenu" type="PopupMenu" parent="."] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 20.0 +margin/bottom = 20.0 +popup/exclusive = false +items = [ "Add", ExtResource( 2 ), false, false, false, 0, 0, null, "", false, "Rename", ExtResource( 4 ), false, false, false, 1, 0, null, "", false, "Delete", ExtResource( 3 ), false, false, false, 2, 0, null, "", false, "Duplicate", ExtResource( 5 ), false, false, false, 3, 0, null, "", false, "Open File", ExtResource( 6 ), false, false, false, 4, 0, null, "", false ] + +[connection signal="button_down" from="Panel/VBox/Margin/HBoxContainer/AddButton" to="." method="_on_AddButton_button_down"] + +[connection signal="text_changed" from="Panel/VBox/Margin/HBoxContainer/Filter" to="." method="_on_Filter_text_changed"] + +[connection signal="cell_selected" from="Panel/VBox/Tree" to="." method="_on_Tree_cell_selected"] + +[connection signal="item_rmb_selected" from="Panel/VBox/Tree" to="." method="_on_Tree_item_rmb_selected"] + +[connection signal="about_to_show" from="ClassContextMenu" to="." method="_on_ClassContextMenu_about_to_show"] + +[connection signal="item_pressed" from="ClassContextMenu" to="." method="_on_ClassContextMenu_item_pressed"] + +[connection signal="about_to_show" from="InstanceContextMenu" to="." method="_on_InstanceContextMenu_about_to_show"] + +[connection signal="item_pressed" from="InstanceContextMenu" to="." method="_on_InstanceContextMenu_item_pressed"] + + diff --git a/demo/addons/godot_data_editor/no_classes.tscn b/demo/addons/godot_data_editor/no_classes.tscn new file mode 100644 index 0000000..c2ddfc0 --- /dev/null +++ b/demo/addons/godot_data_editor/no_classes.tscn @@ -0,0 +1,115 @@ +[gd_scene load_steps=3 format=1] + +[ext_resource path="res://addons/godot_data_editor/style/light_gray_panel.tres" type="StyleBox" id=1] +[ext_resource path="res://addons/godot_data_editor/fonts/droid_serif_bold.tres" type="DynamicFont" id=2] + +[node name="Control" type="Panel"] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 2.0 +margin/top = -1.0 +margin/right = -2.0 +margin/bottom = 1.0 +custom_styles/panel = ExtResource( 1 ) + +[node name="Body" type="VBoxContainer" parent="."] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 10.0 +margin/top = 10.0 +margin/right = 10.0 +margin/bottom = 10.0 +alignment = 0 + +[node name="TitleLabel" type="Label" parent="Body"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 1260.0 +margin/bottom = 19.0 +custom_fonts/font = ExtResource( 2 ) +text = "No Classes" +uppercase = true +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="HSeparator" type="HSeparator" parent="Body"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 23.0 +margin/right = 1260.0 +margin/bottom = 26.0 + +[node name="Spacer" type="Control" parent="Body"] + +rect/min_size = Vector2( 0, 15 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 30.0 +margin/right = 1260.0 +margin/bottom = 45.0 + +[node name="Scroll" type="ScrollContainer" parent="Body"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 3 +margin/left = 0.0 +margin/top = 49.0 +margin/right = 1260.0 +margin/bottom = 580.0 +scroll/horizontal = true +scroll/vertical = true + +[node name="ClassProperties" type="VBoxContainer" parent="Body/Scroll"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 699.0 +margin/bottom = 31.0 +alignment = 0 + +[node name="NoClassPropertiesLabel" type="Label" parent="Body/Scroll/ClassProperties"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 699.0 +margin/bottom = 31.0 +text = "Currently, there are no classes. Click on \"Add Class\" to add a new class and make the necessary adjustments. +Once you feel ready, press \"Refresh\" and start adding instances/items." +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + + diff --git a/demo/addons/godot_data_editor/notes.txt b/demo/addons/godot_data_editor/notes.txt new file mode 100644 index 0000000..e60a1f9 --- /dev/null +++ b/demo/addons/godot_data_editor/notes.txt @@ -0,0 +1,21 @@ +Add "Notes" to each element +Add Display Name for each +Add Refresh +Check how to deal with reloading the tree +Add Sub categories +Translate +Add "state" handling +Add UndoRedo + +Move short callbacks from self to the object and call directly (e.g. popup) + +Use EditorFileSystem class to check for changes (external ones) + +print_progress + + +Handle when switching from encrypted to non-encrypted and vice versa + +# Progress? +get_status(story_item) +set_status(story_item, value) \ No newline at end of file diff --git a/demo/addons/godot_data_editor/options.gd b/demo/addons/godot_data_editor/options.gd new file mode 100644 index 0000000..b30a022 --- /dev/null +++ b/demo/addons/godot_data_editor/options.gd @@ -0,0 +1,190 @@ +tool +extends AcceptDialog + +var config = null + +onready var serializer_label = get_node("Panel/GridContainer/SerializerLabel") +onready var serializer_option = get_node("Panel/GridContainer/SerializerOption") +onready var extension_label = get_node("Panel/GridContainer/ExtensionLabel") +onready var extension_line_edit = get_node("Panel/GridContainer/ExtensionLineEdit") +onready var encrypt_label = get_node("Panel/GridContainer/EncryptLabel") +onready var encrypt_check_box = get_node("Panel/GridContainer/EncryptCheckBox") +onready var password_label = get_node("Panel/GridContainer/PasswordLabel") +onready var password_line_edit = get_node("Panel/GridContainer/PasswordLineEdit") +onready var output_directory_label = get_node("Panel/GridContainer/OutputDirectoryLabel") +onready var output_directory_line_edit = get_node("Panel/GridContainer/OutputDirectoryHBox/OutputDirectoryLineEdit") +onready var class_directory_label = get_node("Panel/GridContainer/OutputDirectoryLabel") +onready var class_directory_line_edit = get_node("Panel/GridContainer/ClassDirectoryHBox/ClassDirectoryLineEdit") +onready var sanitize_ids_label = get_node("Panel/GridContainer/SanitizeIdsLabel") +onready var sanitize_ids_check_box = get_node("Panel/GridContainer/SanitizeIdsCheckBox") + +onready var warn_dialog = get_node("WarnDialog") + +var extension = "" +var serializer = "" +var encrypt = false +var password = "" +var class_directory = "" +var output_directory = "" +var sanitize_ids = true + +signal extension_changed(new_extension, serializer) +signal encryption_changed(is_encrypted, password) + +func _ready(): + self.set_title(tr("Options")) + self.add_cancel(tr("Cancel")) # TODO: Does this keep on adding cancels? + serializer_label.set_text(tr("Serializer")) + extension_label.set_text(tr("File Extension")) + encrypt_label.set_text(tr("Encrypt Files")) + class_directory_label.set_text(tr("Class Directory")) + output_directory_label.set_text(tr("Output Directory")) + sanitize_ids_label.set_text(tr("Sanitize IDs")) + + config = ConfigFile.new() + config.load("res://addons/godot_data_editor/plugin.cfg") + serializer = config.get_value("custom", "serializer") + extension = config.get_value("custom", "extension") + + class_directory = config.get_value("custom", "class_directory") + sanitize_ids = config.get_value("custom", "sanitize_ids") + encrypt = config.get_value("custom", "encrypt") + password = config.get_value("custom", "password") + output_directory = config.get_value("custom", "output_directory") + sanitize_ids = config.get_value("custom", "sanitize_ids") + + serializer_option.clear() + serializer_option.add_item("json", 0) + serializer_option.add_item("binary", 1) + if serializer == "json": + serializer_option.select(0) + elif serializer == "binary": + serializer_option.select(1) + else: + serializer_option.select(0) + serializer = "json" + + extension_line_edit.set_text(extension) + + if serializer == "binary": + encrypt_check_box.set_disabled(false) + password_line_edit.set_editable(true) + else: + encrypt = false + password = "" + encrypt_check_box.set_disabled(true) + password_line_edit.set_editable(false) + + encrypt_check_box.set_pressed(encrypt) + encrypt_check_box.set_text(str(encrypt)) + + password_line_edit.set_text(str(password)) + + class_directory_line_edit.set_text(str(class_directory)) + output_directory_line_edit.set_text(str(output_directory)) + + sanitize_ids_check_box.set_pressed(sanitize_ids) + sanitize_ids_check_box.set_text(str(sanitize_ids)) + +func _on_SerializerOption_item_selected(index): + if index == 0: + extension_line_edit.set_text("json") + encrypt = false + password = "" + encrypt_check_box.set_disabled(true) + password_line_edit.set_editable(false) + if index == 1: + extension_line_edit.set_text("gob") + encrypt_check_box.set_disabled(false) + password_line_edit.set_editable(true) + + + +func _on_Options_confirmed(): + extract_values() + extension = extension.strip_edges() + if extension.begins_with("."): + extension = extension.replace(".", "") + + # TODO: Validate + var error_message = "" +# if self.serializer != "binary" or self.serializer != "json": +# error_message = tr("Please choose either 'json' or 'binary' as serializer.\n") + if self.extension == "": + error_message = tr("Please choose a valid file extension, e.g. 'gob' or 'json'.") + if self.class_directory == "" or not self.class_directory.begins_with("res://"): + error_message = tr("The class directory must be a resource path, e.g. 'res://classes'.") + if self.output_directory == "" or not self.output_directory.begins_with("res://"): + error_message = tr("The output directory must be a resource path, e.g. 'res://data'.") + + var extension_changed = false + var encryption_changed = false + if extension != config.get_value("custom", "extension") or serializer != config.get_value("custom", "serializer"): + extension_changed = true + + if encrypt != config.get_value("custom", "encrypt") or password != config.get_value("custom", "password"): + encryption_changed = true + + if error_message == "": + config.set_value("custom", "extension", extension) + config.set_value("custom", "serializer", serializer) + config.set_value("custom", "encrypt", encrypt) + config.set_value("custom", "password", password) + config.set_value("custom", "class_directory", output_directory) + config.set_value("custom", "output_directory", output_directory) + config.set_value("custom", "sanitize_ids", sanitize_ids) + config.save("res://addons/godot_data_editor/plugin.cfg") + hide() + else: + warn_dialog.set_text(error_message) + warn_dialog.popup_centered() + + if extension_changed: + emit_signal("extension_changed", extension, serializer) + + if encryption_changed: + emit_signal("encryption_changed", encrypt, password) +# TODO: Add a tip to NOT FORGET THE PASSWORD + +func extract_values(): + serializer = serializer_option.get_item_text(serializer_option.get_selected()) + extension = extension_line_edit.get_text() + encrypt = encrypt_check_box.is_pressed() + password = password_line_edit.get_text() + output_directory = output_directory_line_edit.get_text() + sanitize_ids = sanitize_ids_check_box.is_pressed() + +func _on_ClassDirectoryButton_button_down(): + var dialog = EditorFileDialog.new() + dialog.set_mode(EditorFileDialog.MODE_OPEN_DIR) + dialog.connect("dir_selected", self, "set_class_directory", []) + if not self.find_node("EditorFileDialog"): + add_child(dialog) + else: + get_node("EditorFileDialog").popup_centered() + dialog.popup_centered_ratio() + + +func _on_OutputDirectoryButton_button_down(): + var dialog = EditorFileDialog.new() + dialog.set_mode(EditorFileDialog.MODE_OPEN_DIR) + dialog.connect("dir_selected", self, "set_output_directory", []) + if not self.find_node("EditorFileDialog"): + add_child(dialog) + else: + get_node("EditorFileDialog").popup_centered() + dialog.popup_centered_ratio() + +func set_class_directory(selected_directory): + class_directory = selected_directory + class_directory_line_edit.set_text(selected_directory) + +func set_output_directory(selected_directory): + output_directory = selected_directory + output_directory_line_edit.set_text(selected_directory) + +func _on_EncryptCheckBox_button_down(): + encrypt_check_box.set_text(str(!encrypt_check_box.is_pressed())) + +func _on_SanitizeIdsCheckBox_button_down(): + sanitize_ids_check_box.set_text(str(!sanitize_ids_check_box.is_pressed())) diff --git a/demo/addons/godot_data_editor/options.tscn b/demo/addons/godot_data_editor/options.tscn new file mode 100644 index 0000000..bd29ac0 --- /dev/null +++ b/demo/addons/godot_data_editor/options.tscn @@ -0,0 +1,359 @@ +[gd_scene load_steps=4 format=1] + +[ext_resource path="res://addons/godot_data_editor/options.gd" type="Script" id=1] +[ext_resource path="res://addons/godot_data_editor/style/light_gray_panel.tres" type="StyleBox" id=2] +[ext_resource path="res://addons/godot_data_editor/icons/icon_load.png" type="Texture" id=3] + +[node name="Options" type="AcceptDialog"] + +rect/min_size = Vector2( 400, 300 ) +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 400.0 +margin/bottom = 300.0 +popup/exclusive = true +window/title = "Options" +dialog/hide_on_ok = false +script/script = ExtResource( 1 ) + +[node name="Panel" type="Panel" parent="."] + +anchor/right = 1 +anchor/bottom = 1 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 8.0 +margin/top = 8.0 +margin/right = 8.0 +margin/bottom = 40.0 +custom_styles/panel = ExtResource( 2 ) + +[node name="GridContainer" type="GridContainer" parent="Panel"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 7.0 +margin/top = 7.0 +margin/right = 377.0 +margin/bottom = 255.0 +custom_constants/vseparation = 10 +custom_constants/hseparation = 5 +columns = 2 + +[node name="SerializerLabel" type="Label" parent="Panel/GridContainer"] + +rect/min_size = Vector2( 150, 0 ) +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 3.0 +margin/right = 150.0 +margin/bottom = 17.0 +text = "Serializer" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="SerializerOption" type="OptionButton" parent="Panel/GridContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 155.0 +margin/top = 0.0 +margin/right = 370.0 +margin/bottom = 20.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +text = "json" +flat = false +align = 0 +selected = 0 +items = [ "json", null, false, 0, null, "binary", null, false, 1, null ] + +[node name="ExtensionLabel" type="Label" parent="Panel/GridContainer"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 35.0 +margin/right = 150.0 +margin/bottom = 49.0 +text = "File Extension" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="ExtensionLineEdit" type="LineEdit" parent="Panel/GridContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 155.0 +margin/top = 30.0 +margin/right = 370.0 +margin/bottom = 54.0 +text = "json" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="EncryptLabel" type="Label" parent="Panel/GridContainer"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 68.0 +margin/right = 150.0 +margin/bottom = 82.0 +text = "Encrypt Files" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="EncryptCheckBox" type="CheckBox" parent="Panel/GridContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 155.0 +margin/top = 64.0 +margin/right = 370.0 +margin/bottom = 87.0 +disabled = true +toggle_mode = true +enabled_focus_mode = 2 +shortcut = null +text = "False" +flat = false +align = 0 + +[node name="PasswordLabel" type="Label" parent="Panel/GridContainer"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 102.0 +margin/right = 150.0 +margin/bottom = 116.0 +text = "Password" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="PasswordLineEdit" type="LineEdit" parent="Panel/GridContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 155.0 +margin/top = 97.0 +margin/right = 370.0 +margin/bottom = 121.0 +placeholder/alpha = 0.6 +editable = false +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="ClassDirectoryLabel" type="Label" parent="Panel/GridContainer"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 136.0 +margin/right = 150.0 +margin/bottom = 150.0 +text = "Class Directory" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="ClassDirectoryHBox" type="HBoxContainer" parent="Panel/GridContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 155.0 +margin/top = 131.0 +margin/right = 370.0 +margin/bottom = 155.0 +alignment = 0 + +[node name="ClassDirectoryLineEdit" type="LineEdit" parent="Panel/GridContainer/ClassDirectoryHBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 183.0 +margin/bottom = 24.0 +text = "res://classes" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="ClassDirectoryButton" type="Button" parent="Panel/GridContainer/ClassDirectoryHBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 187.0 +margin/top = 0.0 +margin/right = 215.0 +margin/bottom = 24.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +icon = ExtResource( 3 ) +flat = false + +[node name="OutputDirectoryLabel" type="Label" parent="Panel/GridContainer"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 170.0 +margin/right = 150.0 +margin/bottom = 184.0 +text = "Output Directory" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="OutputDirectoryHBox" type="HBoxContainer" parent="Panel/GridContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 155.0 +margin/top = 165.0 +margin/right = 370.0 +margin/bottom = 189.0 +alignment = 0 + +[node name="OutputDirectoryLineEdit" type="LineEdit" parent="Panel/GridContainer/OutputDirectoryHBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 183.0 +margin/bottom = 24.0 +text = "res://data" +placeholder/alpha = 0.6 +focus_mode = 2 +caret/caret_blink = false +caret/caret_blink_speed = 0.65 + +[node name="OutputDirectoryButton" type="Button" parent="Panel/GridContainer/OutputDirectoryHBox"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 187.0 +margin/top = 0.0 +margin/right = 215.0 +margin/bottom = 24.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +icon = ExtResource( 3 ) +flat = false + +[node name="SanitizeIdsLabel" type="Label" parent="Panel/GridContainer"] + +focus/ignore_mouse = true +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 0 +margin/left = 0.0 +margin/top = 203.0 +margin/right = 150.0 +margin/bottom = 217.0 +text = "Sanitize IDs" +percent_visible = 1.0 +lines_skipped = 0 +max_lines_visible = -1 + +[node name="SanitizeIdsCheckBox" type="CheckBox" parent="Panel/GridContainer"] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 155.0 +margin/top = 199.0 +margin/right = 370.0 +margin/bottom = 222.0 +toggle_mode = true +is_pressed = true +enabled_focus_mode = 2 +shortcut = null +text = "True" +flat = false +align = 0 + +[node name="WarnDialog" type="AcceptDialog" parent="."] + +visibility/visible = false +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 260.0 +margin/bottom = 110.0 +popup/exclusive = false +window/title = "Alert!" +dialog/hide_on_ok = true + +[connection signal="confirmed" from="." to="." method="_on_Options_confirmed"] + +[connection signal="item_selected" from="Panel/GridContainer/SerializerOption" to="." method="_on_SerializerOption_item_selected"] + +[connection signal="button_down" from="Panel/GridContainer/EncryptCheckBox" to="." method="_on_EncryptCheckBox_button_down"] + +[connection signal="button_down" from="Panel/GridContainer/ClassDirectoryHBox/ClassDirectoryButton" to="." method="_on_ClassDirectoryButton_button_down"] + +[connection signal="button_down" from="Panel/GridContainer/OutputDirectoryHBox/OutputDirectoryButton" to="." method="_on_OutputDirectoryButton_button_down"] + +[connection signal="button_down" from="Panel/GridContainer/SanitizeIdsCheckBox" to="." method="_on_SanitizeIdsCheckBox_button_down"] + + diff --git a/demo/addons/godot_data_editor/plugin.cfg b/demo/addons/godot_data_editor/plugin.cfg new file mode 100644 index 0000000..4e34535 --- /dev/null +++ b/demo/addons/godot_data_editor/plugin.cfg @@ -0,0 +1,17 @@ +[custom] + +class_directory="res://classes" +encrypt=false +extension="json" +output_directory="res://data" +password="" +sanitize_ids=true +serializer="json" + +[plugin] + +author="Matthias Stoeckli" +description="An editor to write and use a data from Godot" +name="godot_data_editor" +script="data_editor.gd" +version="0.1" diff --git a/demo/addons/godot_data_editor/property_item.gd b/demo/addons/godot_data_editor/property_item.gd new file mode 100644 index 0000000..0b945d3 --- /dev/null +++ b/demo/addons/godot_data_editor/property_item.gd @@ -0,0 +1,480 @@ +tool +extends Panel +# This class represents an item control used to change the data values, e.g. the text boxes. + + +var load_icon = preload("icons/icon_load.png") +var multi_line_icon = preload("icons/icon_multi_line.png") + +var property_name = "" +var type = TYPE_NIL +var hint = 0 +var hint_array = [] +var hint_text = "" +var number_of_hints = 0 +var value = null # The value of the property + +var has_delete_button = false + + +var control = null +var popup = null +var menu = null +var value_editor = [] + + +var dialog = null +var object_type_line_edit = null + + +signal on_property_value_changed(property, value) +signal property_item_load_button_down(property_item) +signal custom_property_delete_requested(property_name) + +# has_delete is used for custom properties +func initialize(property_name, type, value = null, hint = 0, hint_text = "", has_delete = false): + self.property_name = property_name + self.type = type + self.value = value + self.hint = hint + self.hint_text = hint_text + self.has_delete_button = has_delete + + + +func _ready(): + # Label describing property + var property_label = Label.new() + property_label.set_text(property_name.capitalize()) + + # Split property hints + self.hint_array = hint_text.split(",") + self.number_of_hints = hint_array.size() + + ################################################## + # For each type, one control is defined + ################################################## + if type == TYPE_BOOL: + create_bool() + elif type == TYPE_INT or type == TYPE_REAL: + create_number() + elif type == TYPE_STRING: + create_string() + elif type == TYPE_COLOR: + create_color() + elif type == TYPE_NODE_PATH: + create_node_path() + elif type == TYPE_VECTOR2: + control = create_custom_editor_button(value); + create_custom_editor(2, 2, 10, ["x", "y"]) + elif type == TYPE_VECTOR3: + control = create_custom_editor_button(value); + create_custom_editor(3, 3, 10, ["x", "y", "z"]) + elif type == TYPE_RECT2: + control = create_custom_editor_button(value); + create_custom_editor(4, 4, 10, ["x", "y", "w", "h"]) + elif type == TYPE_PLANE: + control = create_custom_editor_button(value); + create_custom_editor(4, 4, 10, ["x", "y", "z", "d"]) + elif type == TYPE_QUAT: + control = create_custom_editor_button(value); + create_custom_editor(4, 4, 10, ["x", "y", "z", "w"]) + elif type == TYPE_TRANSFORM: + control = create_custom_editor_button(value); + create_custom_editor(12, 4, 16, ["xx", "xy", "xz", "xo", "yx", "yy", "yz", "yo", "zx", "zy", "zz", "zo"]) + elif type == TYPE_OBJECT or type == TYPE_IMAGE: + create_object_or_image() + else: + control = get_not_yet_supported() + + control.set_h_size_flags(Control.SIZE_EXPAND_FILL) + control.set_margin(MARGIN_LEFT, 200) + control.set_custom_minimum_size(Vector2(get_parent().get_parent().get_parent().get_size().x - 270, 0)) + add_child(property_label) + add_child(control) + + if has_delete_button: + var delete_button = ToolButton.new() + delete_button.set_button_icon(preload("res://addons/godot_data_editor/icons/icon_remove.png")) + delete_button.set_h_size_flags(Control.SIZE_EXPAND) + delete_button.set_margin(MARGIN_LEFT, get_parent().get_parent().get_parent().get_size().x - 34 ) + delete_button.set_custom_minimum_size(Vector2(28, 24)) + delete_button.connect("button_down", self, "route_delete_request") +# delete_button.connect("button_down", self, "emit_signal", ["custom_property_delete_requested") + add_child(delete_button) + +func route_delete_request(): + emit_signal("custom_property_delete_requested") + +func create_custom_editor_button(value): + var button = Button.new() + button.set_text(str(value)) + button.connect("button_down", self, "open_custom_editor") + return button + +func open_custom_editor(): + menu.set_pos(get_global_mouse_pos()) + menu.get_children()[1].grab_focus() + menu.popup() + + +################################################## +# All types +################################################## + +func create_bool(): + control = CheckBox.new() + control.set_text(str(value)) + control.set_pressed(value) + control.connect("toggled", self, "set_checkbox_label", []) + control.connect("toggled", self, "property_value_changed", []) + +func create_number(): + if hint == PROPERTY_HINT_RANGE: + var control_min = -16777216 + var control_max = 16777216 + + var control_step = 0 + if type == TYPE_INT: + control_step = 1 + else: + control_step = 0.00001 + + if number_of_hints >= 1: + if not hint_array[0].empty(): + control_min = int(hint_array[0]) + + if number_of_hints >= 2: + if not hint_array[1].empty(): + control_max = int(hint_array[1]) + + if number_of_hints >= 3: + if not hint_array[2].empty(): + control_step = float(hint_array[2]) + + # TODO: This does not seem to be exposed in GDScript yet? + if number_of_hints >= 4 and hint_array[3] == "slider": + control = HSlider.new() + control.set_min(control_min) + control.set_max(control_max) + control.set_step(control_step) + control.set_value(value); + control.connect("value_changed", self, "property_value_changed", []) + #controlset_size(Size2(110,30)*EDSCALE); + else: + control = SpinBox.new() + control.set_min(control_min) + control.set_max(control_max) + control.set_step(control_step) + control.set_value(value) + control.connect("value_changed", self, "property_value_changed", []) + #set_size(Size2(70,35)*EDSCALE); + elif hint == PROPERTY_HINT_ENUM: + control = MenuButton.new() + for i in range(0, hint_array.size()): + control.get_popup().add_item(hint_array[i]) + control.set_flat(false) +# control.set_pos(get_pos()) + control.set_text(control.get_popup().get_item_text(value)) + control.get_popup().connect("item_pressed", self, "int_enum_property_value_changed", []) + + elif hint == PROPERTY_HINT_EXP_EASING: + control = get_not_yet_supported() + elif hint == PROPERTY_HINT_FLAGS: + control = get_not_yet_supported() + else: + control = SpinBox.new() + control.set_value(value); + if type == TYPE_REAL: + control.set_min(-16777216) + control.set_max(16777216) + control.set_step(0.00001) + else: + control.set_max(2147483647) + control.set_min(-2147483647) + control.set_step(1) + control.connect("value_changed", self, "property_value_changed", []) + #control = create_custom_editor_button(value); + #create_custom_editor(1, 1, 50, ["value"]) + #custom_editor_value_applied() + +func create_string(): + if hint == PROPERTY_HINT_ENUM: + control = MenuButton.new() + for i in range(0, hint_array.size()): + control.get_popup().add_item(hint_array[i]) + control.set_flat(false) + control.set_text(str(value)) + control.get_popup().connect("item_pressed", self, "string_enum_property_value_changed", []) + elif hint == PROPERTY_HINT_MULTILINE_TEXT: + # RABRABRAB + control = HBoxContainer.new() + var line_edit = LineEdit.new() + line_edit.set_h_size_flags(SIZE_EXPAND_FILL) + var more_button = ToolButton.new() + more_button.set_button_icon(multi_line_icon) + line_edit.set_text(str(value)) + control.add_child(line_edit) + control.add_child(more_button) + + popup = Popup.new() + popup.set_size(Vector2(600, 400)) + var text_edit = TextEdit.new() + text_edit.set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 0) + text_edit.set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 0) + text_edit.set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0) + text_edit.set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0) + add_child(popup) + popup.add_child(text_edit) + text_edit.set_text(str(value)) + + line_edit.connect("text_changed", self, "property_value_changed", []) + more_button.connect("button_down", popup, "popup_centered_minsize", [Vector2(800, 600)]) + popup.connect("popup_hide", self, "text_edit_popup_closed", []) + else: + control = LineEdit.new() + control.set_text(str(value)) + control.connect("text_changed", self, "property_value_changed", []) + +func create_color(): + control = ColorPickerButton.new() + # If, for some reason, the color is still (de)serialized wrongly, split the string + if typeof(value) == TYPE_STRING and value.find(","): + var split_color = value.split(",") + value = Color(split_color[0], split_color[1], split_color[2], split_color[3]) + control.set_color(value) + control.connect("color_changed", self, "property_value_changed", []) + +func create_node_path(): + control = LineEdit.new() + control.set_text(value) + control.connect("text_changed", self, "property_value_changed", []) + + +# Adapted Port of property editor +func create_custom_editor(amount, columns, label_w, strings, read_only = false): + self.value_editor = [] + self.menu = PopupMenu.new() + menu.connect("popup_hide", self, "custom_editor_value_applied") + var w = 80 + var h = 20 + var m = 10 + var MAX_VALUE_EDITORS = 12 + var value_label = [] + for i in range(0, amount): + var line_edit = LineEdit.new() + line_edit.set_text(str(get_custom_editor_value(i))) + value_editor.append(line_edit) + menu.add_child(value_editor[i]) + value_label.append(Label.new()) + menu.add_child(value_label[i]) + pass + + var rows=((amount-1)/columns)+1 + menu.set_size(Vector2( m*(1+columns)+(w+label_w)*columns, m*(1+rows)+h*rows ) ); + for i in range(0, amount): + var c = i % columns; + var r = i / columns; + value_editor[i].show() + value_label[i].show() + if i < strings.size(): + value_label[i].set_text(strings[i]) + else: + value_label[i].set_text("") + + value_editor[i].set_pos( Vector2( m+label_w+c*(w+m+label_w), m+r*(h+m) )) + value_editor[i].set_size( Vector2( w, h ) ) + value_label[i].set_pos( Vector2( m+c*(w+m+label_w), m+r*(h+m) ) ) + value_editor[i].set_editable(!read_only) + + pass + + add_child(menu) + + +func custom_editor_value_applied(): + # TODO: Validate + var va = [] + for line in value_editor: + var v = float(line.get_text()) + va.append(v) + + var value = null + if type == TYPE_VECTOR2: + value = Vector2(va[0], va[1]) + if type == TYPE_VECTOR3: + value = Vector3(va[0], va[1], va[2]) + if type == TYPE_RECT2: + value = Rect2(va[0], va[1], va[2], va[3]) + if type == TYPE_PLANE: + value = Plane(va[0], va[1], va[2], va[3]) + if type == TYPE_QUAT: + value = Quat(va[0], va[1], va[2], va[3]) + if type == TYPE_TRANSFORM: + value = Transform(Vector3(va[0], va[1], va[2]), Vector3(va[4], va[5], va[6]), Vector3(va[8], va[9], va[10]), Vector3(va[3], va[7], va[11])) + + if value != self.value: + self.value = value + emit_signal("on_property_value_changed", property_name, value) + control.set_text(str(value)) + +func get_custom_editor_value(index): + if type == TYPE_VECTOR2: + if index == 0: return value.x + else: return value.y + elif type == TYPE_VECTOR3: + if index == 0: return value.x + elif index == 1: return value.y + else: return value.z + elif type == TYPE_RECT2: + if index == 0: return value.pos.x + elif index == 1: return value.pos.y + elif index == 2: return value.size.x + else: return value.size.y + elif type == TYPE_QUAT: + if index == 0: return value.x + elif index == 1: return value.y + elif index == 2: return value.z + else: return value.w + elif type == TYPE_PLANE: + if index == 0: return value.x + elif index == 1: return value.y + elif index == 2: return value.z + else: return value.d + elif type == TYPE_TRANSFORM: + if index == 0: return value.basis.x.x + elif index == 1: return value.basis.x.y + elif index == 2: return value.basis.x.z + elif index == 3: return value.origin.x + elif index == 4: return value.basis.y.x + elif index == 5: return value.basis.y.y + elif index == 6: return value.basis.y.z + elif index == 7: return value.origin.y + elif index == 8: return value.basis.z.x + elif index == 9: return value.basis.z.y + elif index == 10: return value.basis.z.z + else: return value.origin.z + +func create_object_or_image(): + value = str(value) + control = HBoxContainer.new() + object_type_line_edit = LineEdit.new() + object_type_line_edit.set_text(str(value)) + object_type_line_edit.set_h_size_flags(SIZE_EXPAND_FILL) + object_type_line_edit.connect("text_changed", self, "property_value_changed", []) + if hint_text == "Texture" or type == TYPE_IMAGE: + var f = File.new() + if value != null and f.file_exists(value): + var texture = load(value) + var texture_frame = TextureFrame.new() + texture_frame.set_expand(true) + texture_frame.set_custom_minimum_size(Vector2(get_parent_area_size().y, get_parent_area_size().y)) + texture_frame.set_texture(texture) + var texture_popup = Popup.new() + var texture_frame_full = TextureFrame.new() + texture_frame_full.set_texture(texture) + texture_popup.add_child(texture_frame_full) + texture_popup.set_size(texture.get_size()) +# texture_frame.set_process_input(true) +# texture_frame.connect("input_event", self, "open_image", []) + control.add_child(texture_frame) +# control.add_child(texture_popup) + + control.add_child(object_type_line_edit) + + + var load_button = ToolButton.new() + load_button.set_button_icon(load_icon) + control.add_child(load_button) + + + if Globals.get("debug_is_editor"): + dialog = EditorFileDialog.new() + dialog.set_access(EditorFileDialog.ACCESS_RESOURCES) + dialog.set_mode(EditorFileDialog.MODE_OPEN_FILE) + load_button.connect("button_down", dialog, "popup_centered_ratio") + + var filter = "" + var resource_type = "" + var extension_array = [] + + if hint == PROPERTY_HINT_RESOURCE_TYPE: + resource_type = hint_text + extension_array = ResourceLoader.get_recognized_extensions_for_type(resource_type) + else: + extension_array = hint_array + + for extension in extension_array: +# if filter.begins_with("."): +# filter = "*" + extension +# elif filter.begins_with("*"): +# filter = "*." + extension +# filter = filter + " ; " + extension.to_upper() + extension.replace("*", "").replace(".", "") + filter = "*." + extension + " ; " + extension.to_upper() + dialog.add_filter(filter) + pass + dialog.connect("file_selected", self, "fill_resource_name", []) + add_child(dialog) + + + #.add_icon_item(get_icon("Load","EditorIcons"), "Load") + + + +func get_not_yet_supported(): + var control = Label.new() + control.set_text(str("This type is not yet supported.")) + return control + +# TODO: That's all a bit too confusing... +func fill_resource_name(resource_path): + object_type_line_edit.set_text(resource_path) + property_value_changed(resource_path) + if hint_text == "Texture": + var texture = load(resource_path) + if texture: + control.get_child(0).set_texture(texture) + +# Sets the label of the checkboxe's text to the value +func set_checkbox_label(value): + control.set_text(str(value)) + +func property_value_changed(value): + if type == TYPE_INT: + value = int(value) + if type == TYPE_REAL: + value = float(value) + if type == TYPE_COLOR: + value = Color(value) + if self.value != value: + self.value = value + emit_signal("on_property_value_changed", property_name, value) + + +func text_edit_popup_closed(): + var text_edit = popup.get_child(0) + var value = text_edit.get_text() + if value and self.value != value: + self.value = value + emit_signal("on_property_value_changed", property_name, value) + control.get_child(0).set_text(value) + + + +func int_enum_property_value_changed(value): + control.set_text(control.get_popup().get_item_text(value)) + if self.value != value: + self.value = value + emit_signal("on_property_value_changed", property_name, value) + +# Simply changes the text of the calling menu to the selected value if it's an enum +func string_enum_property_value_changed(value): + control.set_text(control.get_popup().get_item_text(value)) + if str(self.value) != str(value): + self.value = value + emit_signal("on_property_value_changed", property_name, control.get_popup().get_item_text(value)) + + +func open_image(texture): + pass \ No newline at end of file diff --git a/demo/addons/godot_data_editor/property_item.tscn b/demo/addons/godot_data_editor/property_item.tscn new file mode 100644 index 0000000..5864420 --- /dev/null +++ b/demo/addons/godot_data_editor/property_item.tscn @@ -0,0 +1,55 @@ +[gd_scene load_steps=3 format=1] + +[ext_resource path="res://addons/godot_data_editor/property_item.gd" type="Script" id=1] +[ext_resource path="res://addons/godot_data_editor/icons/icon_remove.png" type="Texture" id=2] + +[node name="Panel" type="Panel"] + +anchor/right = 1 +anchor/bottom = 1 +rect/min_size = Vector2( 0, 26 ) +focus/ignore_mouse = false +focus/stop_mouse = false +size_flags/horizontal = 3 +size_flags/vertical = 2 +margin/left = 1.0 +margin/top = 0.0 +margin/right = -1.0 +margin/bottom = 574.0 +script/script = ExtResource( 1 ) + +[node name="DeleteButton" type="ToolButton" parent="."] + +visibility/visible = false +anchor/left = 1 +anchor/top = 3 +anchor/right = 1 +anchor/bottom = 3 +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 1280.0 +margin/top = 13.0 +margin/right = 1252.0 +margin/bottom = -11.0 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +icon = ExtResource( 2 ) +flat = true + +[node name="PopupMenu" type="PopupMenu" parent="."] + +focus/ignore_mouse = false +focus/stop_mouse = true +size_flags/horizontal = 2 +size_flags/vertical = 2 +margin/left = 0.0 +margin/top = 0.0 +margin/right = 20.0 +margin/bottom = 20.0 +popup/exclusive = false +items = [ ] + + diff --git a/demo/addons/godot_data_editor/screenshots/class.png b/demo/addons/godot_data_editor/screenshots/class.png new file mode 100644 index 0000000..ab9c021 Binary files /dev/null and b/demo/addons/godot_data_editor/screenshots/class.png differ diff --git a/demo/addons/godot_data_editor/screenshots/editor.png b/demo/addons/godot_data_editor/screenshots/editor.png new file mode 100644 index 0000000..fc98630 Binary files /dev/null and b/demo/addons/godot_data_editor/screenshots/editor.png differ diff --git a/demo/addons/godot_data_editor/style/light_gray_panel.tres b/demo/addons/godot_data_editor/style/light_gray_panel.tres new file mode 100644 index 0000000..8d41d13 --- /dev/null +++ b/demo/addons/godot_data_editor/style/light_gray_panel.tres @@ -0,0 +1,15 @@ +[gd_resource type="StyleBoxFlat" format=1] + +[resource] + +content_margin/left = -1.0 +content_margin/right = -1.0 +content_margin/top = -1.0 +content_margin/bottom = -1.0 +bg_color = Color( 0.172549, 0.164706, 0.196078, 1 ) +light_color = Color( 0.8, 0.8, 0.8, 1 ) +dark_color = Color( 0.8, 0.8, 0.8, 1 ) +border_size = 0 +border_blend = true +draw_bg = true + diff --git a/demo/addons/godot_data_editor/warn.gd b/demo/addons/godot_data_editor/warn.gd new file mode 100644 index 0000000..c27eab7 --- /dev/null +++ b/demo/addons/godot_data_editor/warn.gd @@ -0,0 +1,9 @@ +tool +extends AcceptDialog + +func warn(title, text): + set_title(title) + set_text(text) + popup_centered() + + # Probably this should be placed at get_base_control() diff --git a/demo/classes/element.gd b/demo/classes/element.gd new file mode 100644 index 0000000..85b290b --- /dev/null +++ b/demo/classes/element.gd @@ -0,0 +1,8 @@ +extends "res://addons/godot_data_editor/data_item.gd" + +export(String) var name = "" +export(Color) var color = Color(1,0,1) +export(Texture) var image = null + +func _init(id).(id): + pass diff --git a/demo/classes/element.png b/demo/classes/element.png new file mode 100644 index 0000000..e4b6016 Binary files /dev/null and b/demo/classes/element.png differ diff --git a/demo/classes/merchant.gd b/demo/classes/merchant.gd new file mode 100644 index 0000000..024e53a --- /dev/null +++ b/demo/classes/merchant.gd @@ -0,0 +1,8 @@ +extends "res://addons/godot_data_editor/data_item.gd" + +export(String, "Armor Shop", "Weapon Shop", "Inn", "Travelling Salesman") var name = "" +export(String) var greeting = "" + + +func _init(id).(id): + pass diff --git a/demo/classes/merchant.png b/demo/classes/merchant.png new file mode 100644 index 0000000..8a5724c Binary files /dev/null and b/demo/classes/merchant.png differ diff --git a/demo/classes/shop_item.gd b/demo/classes/shop_item.gd new file mode 100644 index 0000000..96f79fe --- /dev/null +++ b/demo/classes/shop_item.gd @@ -0,0 +1,10 @@ +extends "res://addons/godot_data_editor/data_item.gd" + +export(String) var name = "" +export(Texture) var icon = null +export(int, 0, 9999) var price = 0 +export(String, "Armor Shop", "Weapon Shop", "Inn", "Travelling Salesman") var seller = "Armor Shop" +export(String, MULTILINE) var description = "" + +func _init(id).(id): + pass diff --git a/demo/classes/shop_item.png b/demo/classes/shop_item.png new file mode 100644 index 0000000..e4c2732 Binary files /dev/null and b/demo/classes/shop_item.png differ diff --git a/demo/classes/spell.gd b/demo/classes/spell.gd new file mode 100644 index 0000000..6455e24 --- /dev/null +++ b/demo/classes/spell.gd @@ -0,0 +1,14 @@ +extends "res://addons/godot_data_editor/data_item.gd" + +export(String) var name = "" +export(String, MULTILINE) var description = "" +export(String, "water", "fire", "wind", "earth") var element = "water" +export(Texture) var icon = null +export(int, 0, 9999) var base_damage = 0 +export(String, "One Enemy", "All Enemies", "One Player", "All Players") var target = "One Enemy" +export(PackedScene) var effect = null +export(Sample) var sound = null + +func _init(id).(id): + pass + diff --git a/demo/classes/spell.png b/demo/classes/spell.png new file mode 100644 index 0000000..05992ee Binary files /dev/null and b/demo/classes/spell.png differ diff --git a/demo/data/element/earth.json b/demo/data/element/earth.json new file mode 100644 index 0000000..7653104 --- /dev/null +++ b/demo/data/element/earth.json @@ -0,0 +1 @@ +{"image":["res://graphics/icon_earth.png", 4], "_last_modified":[1501969193, 2], "_id":["earth", 4], "_display_name":["Earth", 4], "_class_name":["Element", 4], "_class":["element", 4], "_custom_properties":{}, "color":["ff746d63", 14], "_created":[1501962816, 3], "_persistent":[true, 1], "name":["Earth", 4]} \ No newline at end of file diff --git a/demo/data/element/fire.json b/demo/data/element/fire.json new file mode 100644 index 0000000..175c9d7 --- /dev/null +++ b/demo/data/element/fire.json @@ -0,0 +1 @@ +{"image":["res://graphics/icon_fire.png", 4], "_last_modified":[1501969193, 2], "_id":["fire", 4], "_display_name":["Fire", 4], "_class_name":["Element", 4], "_class":["element", 4], "_custom_properties":{}, "color":["ffd87a00", 14], "_created":[1501962794, 3], "_persistent":[true, 1], "name":["Fire", 4]} \ No newline at end of file diff --git a/demo/data/element/water.json b/demo/data/element/water.json new file mode 100644 index 0000000..d4af59b --- /dev/null +++ b/demo/data/element/water.json @@ -0,0 +1 @@ +{"image":["res://graphics/icon_water.png", 4], "_last_modified":[1501969193, 2], "_id":["water", 4], "_display_name":["Water", 4], "_class_name":["Element", 4], "_class":["element", 4], "_custom_properties":{}, "color":["ff007fd8", 14], "_created":[1501962806, 3], "_persistent":[true, 1], "name":["Water", 4]} \ No newline at end of file diff --git a/demo/data/element/wind.json b/demo/data/element/wind.json new file mode 100644 index 0000000..6ccab37 --- /dev/null +++ b/demo/data/element/wind.json @@ -0,0 +1 @@ +{"image":["res://graphics/icon_wind.png", 4], "_last_modified":[1501969193, 2], "_id":["wind", 4], "_display_name":["Wind", 4], "_class_name":["Element", 4], "_class":["element", 4], "_custom_properties":{}, "color":["ff00d866", 14], "_created":[1501962812, 3], "_persistent":[true, 1], "name":["Wind", 4]} \ No newline at end of file diff --git a/demo/data/merchant/armor_shop.json b/demo/data/merchant/armor_shop.json new file mode 100644 index 0000000..9c656b6 --- /dev/null +++ b/demo/data/merchant/armor_shop.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "_id":["armor_shop", 4], "greeting":["I sell armor.", 4], "_display_name":["Armor Shop", 4], "_class_name":["Merchant", 4], "_class":["merchant", 4], "_custom_properties":{}, "_created":[1501789305, 3], "_persistent":[true, 1], "name":["Armor Shop", 4]} \ No newline at end of file diff --git a/demo/data/merchant/inn.json b/demo/data/merchant/inn.json new file mode 100644 index 0000000..e65b394 --- /dev/null +++ b/demo/data/merchant/inn.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "_id":["inn", 4], "greeting":["100% HP!", 4], "_display_name":["Inn", 4], "_class_name":["Merchant", 4], "_class":["merchant", 4], "_custom_properties":{}, "_created":[1501789305, 3], "_persistent":[true, 1], "name":["Inn", 4]} \ No newline at end of file diff --git a/demo/data/merchant/travelling_salesman.json b/demo/data/merchant/travelling_salesman.json new file mode 100644 index 0000000..3579932 --- /dev/null +++ b/demo/data/merchant/travelling_salesman.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "_id":["travelling_salesman", 4], "greeting":["Howdy!", 4], "_display_name":["Travelling Salesman", 4], "_class_name":["Merchant", 4], "_class":["merchant", 4], "_custom_properties":{}, "_created":[1501789305, 3], "_persistent":[true, 1], "name":["Travelling Salesman", 4]} \ No newline at end of file diff --git a/demo/data/merchant/weapon_shop.json b/demo/data/merchant/weapon_shop.json new file mode 100644 index 0000000..5e1f688 --- /dev/null +++ b/demo/data/merchant/weapon_shop.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "_id":["weapon_shop", 4], "greeting":["Surprise: We sell weapons.", 4], "_display_name":["Weapon Shop", 4], "_class_name":["Merchant", 4], "_class":["merchant", 4], "_custom_properties":{}, "_created":[1501789357, 3], "_persistent":[true, 1], "name":["Weapon Shop", 4]} \ No newline at end of file diff --git a/demo/data/shop_item/armor_1.json b/demo/data/shop_item/armor_1.json new file mode 100644 index 0000000..dc1f434 --- /dev/null +++ b/demo/data/shop_item/armor_1.json @@ -0,0 +1 @@ +{"price":[25, 3], "_last_modified":[1501969193, 2], "description":["", 4], "_id":["armor_1", 4], "_display_name":["armor_1", 4], "_class_name":["Shop Item", 4], "_class":["shop_item", 4], "_custom_properties":{}, "seller":["Armor Shop", 4], "_created":[1501937294, 3], "_persistent":[true, 1], "icon":["res://icon.png", 4], "name":["Armor 1", 4]} \ No newline at end of file diff --git a/demo/data/shop_item/armor_2.json b/demo/data/shop_item/armor_2.json new file mode 100644 index 0000000..46108e7 --- /dev/null +++ b/demo/data/shop_item/armor_2.json @@ -0,0 +1 @@ +{"price":[35, 3], "_last_modified":[1501969193, 2], "description":["", 4], "_id":["armor_2", 4], "_display_name":["armor_2", 4], "_class_name":["Shop Item", 4], "_class":["shop_item", 4], "_custom_properties":{}, "seller":["Armor Shop", 4], "_created":[1501937298, 3], "_persistent":[true, 1], "icon":["res://icon.png", 4], "name":["Armor 2", 4]} \ No newline at end of file diff --git a/demo/data/shop_item/doge_axe.json b/demo/data/shop_item/doge_axe.json new file mode 100644 index 0000000..166427b --- /dev/null +++ b/demo/data/shop_item/doge_axe.json @@ -0,0 +1 @@ +{"price":[1500, 3], "_last_modified":[1501969193, 2], "description":["Much damage. Wow.", 4], "_id":["doge_axe", 4], "_display_name":["Doge Axe", 4], "_class_name":["Shop Item", 4], "_class":["shop_item", 4], "_custom_properties":{}, "seller":["Weapon Shop", 4], "_created":[1501786832, 3], "_persistent":[true, 1], "icon":["res://icon.png", 4], "name":["Doge Axe", 4]} \ No newline at end of file diff --git a/demo/data/shop_item/herb.json b/demo/data/shop_item/herb.json new file mode 100644 index 0000000..29c120c --- /dev/null +++ b/demo/data/shop_item/herb.json @@ -0,0 +1 @@ +{"price":[25, 3], "_last_modified":[1501969193, 2], "description":["", 4], "_id":["herb", 4], "_display_name":["herb", 4], "_class_name":["Shop Item", 4], "_class":["shop_item", 4], "_custom_properties":{}, "seller":["Travelling Salesman", 4], "_created":[1501786401, 3], "_persistent":[true, 1], "icon":["res://icon.png", 4], "name":["Herb", 4]} \ No newline at end of file diff --git a/demo/data/shop_item/potion.json b/demo/data/shop_item/potion.json new file mode 100644 index 0000000..47920d5 --- /dev/null +++ b/demo/data/shop_item/potion.json @@ -0,0 +1 @@ +{"price":[100, 3], "_last_modified":[1501969193, 2], "description":["", 4], "_id":["potion", 4], "_display_name":["potion", 4], "_class_name":["Shop Item", 4], "_class":["shop_item", 4], "_custom_properties":{}, "seller":["Travelling Salesman", 4], "_created":[1501786809, 3], "_persistent":[true, 1], "icon":["res://icon.png", 4], "name":["Potion", 4]} \ No newline at end of file diff --git a/demo/data/spell/earth_tremor.json b/demo/data/spell/earth_tremor.json new file mode 100644 index 0000000..36b8e75 --- /dev/null +++ b/demo/data/spell/earth_tremor.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "description":["Nam quam nunc, blandit vel, luctus pulvinar, hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus.", 4], "_id":["earth_tremor", 4], "effect":[null, 0], "_display_name":["Earth Tremor", 4], "_class_name":["Spell", 4], "_class":["spell", 4], "_custom_properties":{}, "target":["All Enemies", 4], "_created":[1501968711, 3], "_persistent":[true, 1], "sound":[null, 0], "base_damage":[43, 2], "icon":["res://graphics/icon_spell_earth_tremor.png", 4], "name":["Earth Tremor", 4], "element":["earth", 4]} \ No newline at end of file diff --git a/demo/data/spell/fireball.json b/demo/data/spell/fireball.json new file mode 100644 index 0000000..9cee87a --- /dev/null +++ b/demo/data/spell/fireball.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "description":["Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. ", 4], "_id":["fireball", 4], "effect":[null, 0], "_display_name":["Fireball", 4], "_class_name":["Spell", 4], "_class":["spell", 4], "_custom_properties":{}, "target":["One Enemy", 4], "_created":[1501964007, 3], "_persistent":[true, 1], "sound":[null, 0], "base_damage":[10, 3], "icon":["res://graphics/icon_spell_fireball.png", 4], "name":["Fireball", 4], "element":["fire", 4]} \ No newline at end of file diff --git a/demo/data/spell/storm.json b/demo/data/spell/storm.json new file mode 100644 index 0000000..18a0258 --- /dev/null +++ b/demo/data/spell/storm.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "description":["Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim.", 4], "_id":["storm", 4], "effect":[null, 0], "_display_name":["Storm", 4], "_class_name":["Spell", 4], "_class":["spell", 4], "_custom_properties":{}, "target":["One Enemy", 4], "_created":[1501968365, 3], "_persistent":[true, 1], "sound":[null, 0], "base_damage":[15, 3], "icon":["res://graphics/icon_spell_storm.png", 4], "name":["Storm", 4], "element":["wind", 4]} \ No newline at end of file diff --git a/demo/data/spell/wall_of_fire.json b/demo/data/spell/wall_of_fire.json new file mode 100644 index 0000000..ffcc01c --- /dev/null +++ b/demo/data/spell/wall_of_fire.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "description":["Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. ", 4], "_id":["wall_of_fire", 4], "effect":[null, 0], "_display_name":["Wall of Fire", 4], "_class_name":["Spell", 4], "_class":["spell", 4], "_custom_properties":{}, "target":["All Enemies", 4], "_created":[1501964040, 3], "_persistent":[true, 1], "sound":[null, 0], "base_damage":[16, 3], "icon":["res://graphics/icon_spell_wall_of_fire.png", 4], "name":["Wall of Fire", 4], "element":["fire", 4]} \ No newline at end of file diff --git a/demo/data/spell/water_bolt.json b/demo/data/spell/water_bolt.json new file mode 100644 index 0000000..d91ca71 --- /dev/null +++ b/demo/data/spell/water_bolt.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "description":["Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet.", 4], "_id":["water_bolt", 4], "effect":[null, 0], "_display_name":["Water Bolt", 4], "_class_name":["Spell", 4], "_class":["spell", 4], "_custom_properties":{}, "target":["One Enemy", 4], "_created":[1501968528, 3], "_persistent":[true, 1], "sound":[null, 0], "base_damage":[30, 2], "icon":["res://graphics/icon_spell_waterbolt.png", 4], "name":["Water Bolt", 4], "element":["water", 4]} \ No newline at end of file diff --git a/demo/data/spell/water_splash.json b/demo/data/spell/water_splash.json new file mode 100644 index 0000000..43966d3 --- /dev/null +++ b/demo/data/spell/water_splash.json @@ -0,0 +1 @@ +{"_last_modified":[1501969193, 2], "description":["Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum.", 4], "_id":["water_splash", 4], "effect":[null, 0], "_display_name":["Water Splash", 4], "_class_name":["Spell", 4], "_class":["spell", 4], "_custom_properties":{}, "target":["One Enemy", 4], "_created":[1501968621, 3], "_persistent":[true, 1], "sound":[null, 0], "base_damage":[17, 3], "icon":["res://graphics/icon_spell_watersplash.png", 4], "name":["Water Splash", 4], "element":["water", 4]} \ No newline at end of file diff --git a/demo/engine.cfg b/demo/engine.cfg new file mode 100644 index 0000000..6f56534 --- /dev/null +++ b/demo/engine.cfg @@ -0,0 +1,13 @@ +[application] + +name="DataEditorDemo" +main_scene="res://ShopDialog.tscn" +icon="res://icon.png" + +[autoload] + +data="*res://addons/godot_data_editor/data.gd" + +[editor_plugins] + +enabled=["godot_data_editor"] diff --git a/demo/graphics/icon_earth.png b/demo/graphics/icon_earth.png new file mode 100644 index 0000000..b2a86dd Binary files /dev/null and b/demo/graphics/icon_earth.png differ diff --git a/demo/graphics/icon_fire.png b/demo/graphics/icon_fire.png new file mode 100644 index 0000000..ba9f404 Binary files /dev/null and b/demo/graphics/icon_fire.png differ diff --git a/demo/graphics/icon_spell_earth_tremor.png b/demo/graphics/icon_spell_earth_tremor.png new file mode 100644 index 0000000..13e803d Binary files /dev/null and b/demo/graphics/icon_spell_earth_tremor.png differ diff --git a/demo/graphics/icon_spell_fireball.png b/demo/graphics/icon_spell_fireball.png new file mode 100644 index 0000000..57a61d4 Binary files /dev/null and b/demo/graphics/icon_spell_fireball.png differ diff --git a/demo/graphics/icon_spell_storm.png b/demo/graphics/icon_spell_storm.png new file mode 100644 index 0000000..ad62d02 Binary files /dev/null and b/demo/graphics/icon_spell_storm.png differ diff --git a/demo/graphics/icon_spell_unknown.png b/demo/graphics/icon_spell_unknown.png new file mode 100644 index 0000000..56ad721 Binary files /dev/null and b/demo/graphics/icon_spell_unknown.png differ diff --git a/demo/graphics/icon_spell_wall_of_fire.png b/demo/graphics/icon_spell_wall_of_fire.png new file mode 100644 index 0000000..7d9c679 Binary files /dev/null and b/demo/graphics/icon_spell_wall_of_fire.png differ diff --git a/demo/graphics/icon_spell_waterbolt.png b/demo/graphics/icon_spell_waterbolt.png new file mode 100644 index 0000000..8d8366c Binary files /dev/null and b/demo/graphics/icon_spell_waterbolt.png differ diff --git a/demo/graphics/icon_spell_watersplash.png b/demo/graphics/icon_spell_watersplash.png new file mode 100644 index 0000000..bf1eae4 Binary files /dev/null and b/demo/graphics/icon_spell_watersplash.png differ diff --git a/demo/graphics/icon_water.png b/demo/graphics/icon_water.png new file mode 100644 index 0000000..2bf4b61 Binary files /dev/null and b/demo/graphics/icon_water.png differ diff --git a/demo/graphics/icon_wind.png b/demo/graphics/icon_wind.png new file mode 100644 index 0000000..cf7cafc Binary files /dev/null and b/demo/graphics/icon_wind.png differ diff --git a/demo/icon.png b/demo/icon.png new file mode 100644 index 0000000..c019ef6 Binary files /dev/null and b/demo/icon.png differ diff --git a/demo/icon.png.flags b/demo/icon.png.flags new file mode 100644 index 0000000..5130fd1 --- /dev/null +++ b/demo/icon.png.flags @@ -0,0 +1 @@ +gen_mipmaps=false diff --git a/demo/title_font.fnt b/demo/title_font.fnt new file mode 100644 index 0000000..957f597 Binary files /dev/null and b/demo/title_font.fnt differ diff --git a/demo/title_font.inc b/demo/title_font.inc new file mode 100644 index 0000000..b4e5555 --- /dev/null +++ b/demo/title_font.inc @@ -0,0 +1,22782 @@ +static const int _builtin_font_height=21; +static const int _builtin_font_ascent=17; +static const int _builtin_font_charcount=191; +static const int _builtin_font_charrects[191][8]={ +/* charidx , ofs_x, ofs_y, size_x, size_y, valign, halign, advance */ +{224,227,103,11,15,2,0,11}, +{192,2,42,14,18,-1,0,13}, +{64,25,2,18,18,3,0,18}, +{96,241,179,6,3,2,0,7}, +{160,47,82,0,0,17,0,5}, +{32,0,0,0,0,17,0,5}, +{33,127,190,4,14,3,1,5}, +{225,2,82,11,15,2,0,11}, +{193,164,20,14,18,-1,0,13}, +{161,95,189,4,15,6,1,6}, +{65,110,20,14,14,3,0,13}, +{97,62,82,11,11,6,0,11}, +{98,122,83,11,15,2,0,11}, +{226,237,64,11,15,2,0,11}, +{194,146,21,14,18,-1,0,13}, +{162,128,143,10,17,3,1,12}, +{66,62,97,11,14,3,1,13}, +{34,32,202,6,5,2,0,6}, +{35,209,43,12,14,3,0,12}, +{227,222,64,11,15,2,0,11}, +{195,128,21,14,18,-1,0,13}, +{67,107,38,13,14,3,0,13}, +{163,182,102,11,14,3,1,12}, +{99,30,142,10,11,6,0,10}, +{100,152,84,11,15,2,0,11}, +{228,207,61,11,15,2,0,11}, +{36,167,102,11,19,0,0,11}, +{196,187,2,14,18,-1,0,13}, +{68,2,64,12,14,3,1,13}, +{164,218,23,14,14,4,0,14}, +{37,182,24,14,14,3,1,15}, +{69,44,165,10,14,3,1,11}, +{165,90,40,13,14,3,0,12}, +{197,236,22,14,19,-2,0,13}, +{229,227,83,11,16,1,0,11}, +{101,122,124,11,11,6,0,11}, +{38,192,43,13,14,3,0,13}, +{70,58,155,10,14,3,1,11}, +{198,2,2,19,14,3,0,19}, +{166,166,185,3,17,3,1,5}, +{102,38,183,8,15,2,0,7}, +{230,68,2,17,12,5,0,17}, +{71,50,64,12,14,3,1,14}, +{199,175,42,13,19,3,0,13}, +{167,32,101,11,18,3,1,13}, +{231,156,145,10,16,6,0,10}, +{103,137,124,11,15,6,0,11}, +{39,159,210,3,5,2,0,3}, +{72,146,65,12,14,3,1,14}, +{232,192,61,11,15,2,0,11}, +{40,181,169,6,20,1,1,7}, +{200,100,139,10,18,-1,1,11}, +{104,152,126,11,15,2,0,11}, +{168,178,162,9,3,2,0,9}, +{73,119,190,4,14,3,1,6}, +{169,92,17,14,14,3,1,16}, +{233,177,65,11,15,2,0,11}, +{41,191,162,6,20,1,0,7}, +{201,86,138,10,18,-1,1,11}, +{105,69,191,5,15,2,0,5}, +{234,162,65,11,15,2,0,11}, +{106,201,170,6,19,2,-1,5}, +{202,72,133,10,18,-1,1,11}, +{42,152,165,9,9,3,0,9}, +{170,62,173,7,7,3,1,9}, +{74,72,155,10,14,3,0,11}, +{171,2,171,8,8,8,1,10}, +{43,32,86,11,11,5,0,11}, +{107,170,143,10,15,2,1,11}, +{203,58,133,10,18,-1,1,11}, +{235,17,86,11,15,2,0,11}, +{75,114,61,12,14,3,1,13}, +{172,191,154,9,4,9,1,11}, +{44,151,210,4,7,14,0,5}, +{108,87,196,4,15,2,1,5}, +{204,221,179,6,18,-1,-1,6}, +{236,12,190,6,15,2,-1,5}, +{76,86,160,10,14,3,1,11}, +{173,231,179,6,3,10,1,8}, +{45,2,183,6,3,10,1,8}, +{109,89,2,17,11,6,0,17}, +{205,211,179,6,18,-1,1,6}, +{237,22,190,6,15,2,0,5}, +{77,110,2,16,14,3,1,18}, +{46,111,199,4,4,13,1,6}, +{110,77,97,11,11,6,0,11}, +{206,50,183,8,18,-1,-1,6}, +{238,14,171,8,15,2,-1,5}, +{174,168,2,15,14,3,0,16}, +{78,98,58,12,14,3,1,14}, +{175,26,170,8,2,2,1,10}, +{111,212,117,11,11,6,0,11}, +{207,139,164,9,18,-1,-2,6}, +{239,217,160,9,15,2,-2,5}, +{47,230,160,9,15,3,-1,7}, +{79,20,46,14,14,3,0,14}, +{176,171,172,6,6,3,1,8}, +{112,107,120,11,15,6,0,11}, +{240,77,78,11,15,2,1,12}, +{208,38,46,14,14,3,-1,13}, +{80,241,45,12,14,3,1,13}, +{48,17,123,11,14,3,0,11}, +{177,16,141,10,13,4,0,11}, +{113,92,119,11,15,6,0,11}, +{81,205,2,14,17,3,0,14}, +{209,18,64,12,18,-1,1,14}, +{241,92,78,11,15,2,0,11}, +{49,84,178,7,14,3,1,11}, +{178,139,186,7,8,3,0,7}, +{114,117,175,7,11,6,0,7}, +{210,2,20,14,18,-1,0,14}, +{242,107,79,11,15,2,0,11}, +{82,130,65,12,14,3,1,13}, +{50,62,115,11,14,3,0,11}, +{179,128,175,7,8,3,0,7}, +{115,184,139,10,11,6,0,10}, +{211,20,24,14,18,-1,0,14}, +{243,137,83,11,15,2,0,11}, +{83,66,60,12,14,3,0,12}, +{51,167,125,11,14,3,0,11}, +{180,161,178,6,3,2,0,7}, +{116,73,173,7,14,3,0,7}, +{244,182,120,11,15,2,0,11}, +{212,38,24,14,18,-1,0,14}, +{84,34,64,12,14,3,0,12}, +{52,197,114,11,14,3,0,11}, +{53,212,83,11,14,3,0,11}, +{85,167,84,11,14,3,1,13}, +{213,56,20,14,18,-1,0,14}, +{117,47,109,11,11,6,0,11}, +{181,212,132,10,15,6,1,12}, +{245,227,122,11,15,2,0,11}, +{54,242,83,11,14,3,0,11}, +{86,73,42,13,14,3,0,13}, +{182,243,156,9,14,3,0,10}, +{214,74,18,14,18,-1,0,14}, +{246,242,120,11,15,2,0,11}, +{118,240,141,10,11,6,0,10}, +{87,47,2,17,14,3,0,17}, +{55,2,101,11,14,3,0,11}, +{247,212,101,11,12,4,0,11}, +{119,149,2,15,11,6,0,15}, +{215,142,145,10,9,6,0,11}, +{183,103,199,4,4,9,1,6}, +{88,124,43,13,14,3,0,13}, +{216,223,2,14,16,2,0,14}, +{248,197,80,11,15,4,0,11}, +{56,17,105,11,14,3,0,11}, +{120,197,99,11,11,6,0,10}, +{184,42,205,5,5,17,0,5}, +{121,226,141,10,15,6,0,10}, +{217,92,97,11,18,-1,1,13}, +{249,77,112,11,15,2,0,11}, +{57,47,91,11,14,3,0,11}, +{89,158,43,13,14,3,0,12}, +{185,143,210,4,8,3,1,7}, +{250,2,119,11,15,2,0,11}, +{218,107,98,11,18,-1,1,13}, +{90,82,60,12,14,3,0,12}, +{58,135,198,4,11,6,1,6}, +{122,2,156,10,11,6,0,10}, +{186,95,178,7,7,3,1,9}, +{59,78,196,5,15,6,0,5}, +{251,242,101,11,15,2,0,11}, +{91,51,205,5,20,0,1,6}, +{123,150,186,7,20,1,0,7}, +{219,122,102,11,18,-1,1,13}, +{187,16,158,10,8,8,0,10}, +{188,56,42,13,14,3,1,14}, +{92,204,151,9,15,3,0,8}, +{220,137,102,11,18,-1,1,13}, +{124,173,182,3,17,3,1,5}, +{252,32,123,11,15,2,0,11}, +{60,113,162,9,9,6,0,10}, +{93,60,205,5,20,0,0,6}, +{125,106,175,7,20,1,0,7}, +{253,114,139,10,19,2,0,10}, +{221,141,43,13,18,-1,0,12}, +{189,200,24,14,15,2,1,15}, +{61,30,157,10,7,8,1,11}, +{222,182,84,11,14,3,1,12}, +{254,152,103,11,19,2,0,11}, +{190,130,2,15,15,2,0,16}, +{62,100,161,9,9,6,1,10}, +{94,126,164,9,7,3,0,9}, +{126,47,82,11,5,9,1,13}, +{223,225,45,12,15,2,1,13}, +{255,44,142,10,19,2,0,10}, +{191,198,132,10,15,6,0,10}, +{63,2,138,10,14,3,0,10}, +{95,165,165,9,3,17,0,9}, +}; +static const int _builtin_font_kerning_pair_count=0; +static const int _builtin_font_kerning_pairs[0][3]={ +}; +static const int _builtin_font_img_width=256; +static const int _builtin_font_img_height=256; +static const int _builtin_font_img_data_size=22577; +static const unsigned char _builtin_font_img_data[22577]={ +137, +80, +78, +71, +13, +10, +26, +10, +0, +0, +0, +13, +73, +72, +68, +82, +0, +0, +1, +0, +0, +0, +1, +0, +8, +6, +0, +0, +0, +92, +114, +168, +102, +0, +0, +32, +0, +73, +68, +65, +84, +120, +156, +237, +157, +121, +252, +110, +83, +245, +199, +215, +198, +53, +149, +161, +8, +63, +69, +26, +72, +253, +66, +146, +82, +41, +132, +146, +57, +115, +40, +99, +72, +18, +21, +137, +112, +149, +84, +191, +38, +69, +105, +228, +154, +34, +81, +166, +20, +201, +148, +121, +184, +198, +36, +146, +121, +118, +205, +220, +249, +190, +127, +127, +172, +189, +157, +117, +206, +179, +207, +124, +190, +211, +189, +231, +243, +122, +125, +95, +223, +231, +217, +123, +175, +125, +246, +57, +207, +57, +235, +236, +189, +246, +90, +159, +37, +210, +163, +71, +143, +30, +61, +122, +244, +232, +17, +5, +112, +12, +213, +48, +161, +70, +159, +175, +7, +190, +6, +252, +3, +120, +6, +152, +1, +60, +11, +92, +3, +28, +6, +44, +89, +161, +143, +27, +205, +177, +223, +148, +169, +251, +151, +47, +127, +32, +83, +254, +6, +35, +51, +177, +242, +69, +104, +1, +96, +113, +115, +204, +95, +1, +219, +2, +55, +3, +83, +128, +135, +129, +67, +0, +151, +41, +127, +12, +248, +62, +48, +79, +78, +159, +23, +103, +174, +253, +250, +5, +199, +191, +62, +211, +118, +205, +72, +155, +185, +128, +111, +3, +15, +1, +147, +129, +187, +128, +47, +52, +60, +223, +3, +98, +199, +2, +206, +246, +101, +199, +155, +178, +77, +77, +219, +189, +42, +244, +253, +14, +224, +39, +192, +63, +129, +151, +253, +117, +186, +12, +216, +5, +152, +191, +198, +24, +63, +8, +236, +9, +44, +104, +202, +182, +4, +182, +169, +121, +174, +139, +0, +7, +2, +19, +129, +231, +209, +123, +248, +122, +224, +75, +182, +239, +54, +240, +231, +188, +23, +176, +74, +23, +253, +213, +61, +248, +219, +129, +105, +84, +195, +132, +138, +125, +126, +202, +95, +44, +252, +15, +248, +87, +224, +120, +224, +143, +192, +131, +190, +252, +5, +96, +211, +146, +126, +126, +106, +142, +189, +169, +41, +95, +12, +152, +101, +234, +150, +49, +117, +31, +55, +229, +63, +43, +232, +251, +195, +192, +25, +192, +125, +232, +3, +249, +148, +31, +223, +42, +192, +174, +168, +242, +153, +236, +111, +194, +107, +129, +79, +23, +244, +101, +21, +192, +147, +57, +215, +238, +236, +156, +242, +111, +229, +244, +153, +85, +0, +39, +229, +180, +91, +33, +210, +103, +76, +1, +236, +237, +235, +30, +0, +206, +4, +94, +244, +223, +215, +206, +59, +175, +130, +243, +125, +191, +57, +214, +151, +124, +217, +60, +36, +191, +249, +35, +166, +237, +120, +211, +246, +157, +5, +125, +58, +244, +133, +49, +221, +159, +251, +238, +192, +186, +192, +230, +192, +145, +192, +227, +192, +157, +69, +125, +152, +190, +22, +68, +127, +83, +128, +111, +251, +178, +143, +154, +113, +108, +80, +241, +60, +87, +4, +254, +147, +243, +187, +1, +220, +6, +44, +87, +177, +175, +152, +34, +185, +1, +216, +223, +255, +127, +22, +88, +162, +74, +95, +157, +194, +223, +12, +89, +220, +227, +47, +124, +246, +239, +189, +21, +250, +59, +0, +125, +56, +159, +0, +182, +39, +242, +134, +67, +31, +210, +123, +125, +187, +162, +7, +107, +59, +51, +166, +195, +77, +249, +102, +153, +241, +126, +218, +212, +29, +100, +202, +119, +204, +233, +119, +15, +210, +10, +196, +98, +102, +193, +15, +126, +80, +78, +127, +139, +103, +218, +29, +11, +108, +5, +156, +144, +41, +191, +0, +216, +26, +125, +19, +7, +60, +156, +211, +103, +86, +1, +188, +72, +228, +141, +3, +124, +51, +50, +206, +152, +2, +88, +14, +88, +3, +88, +18, +152, +31, +184, +200, +183, +221, +36, +211, +110, +89, +244, +134, +252, +112, +193, +239, +50, +15, +137, +2, +57, +209, +151, +125, +36, +51, +134, +119, +251, +242, +115, +253, +247, +39, +242, +250, +51, +231, +49, +9, +248, +100, +78, +253, +130, +192, +73, +190, +205, +50, +177, +54, +166, +173, +243, +231, +247, +28, +176, +177, +47, +91, +26, +189, +231, +238, +167, +194, +67, +235, +175, +209, +93, +230, +124, +110, +2, +14, +6, +14, +5, +238, +48, +229, +55, +144, +51, +139, +51, +125, +189, +147, +98, +69, +2, +112, +64, +217, +152, +58, +135, +191, +33, +2, +206, +36, +185, +249, +111, +111, +216, +223, +90, +190, +143, +255, +2, +111, +41, +105, +187, +20, +58, +61, +126, +26, +120, +67, +78, +155, +101, +205, +248, +206, +49, +229, +63, +200, +92, +188, +159, +153, +186, +223, +155, +242, +183, +230, +244, +251, +144, +175, +159, +137, +46, +71, +54, +5, +254, +47, +211, +231, +77, +192, +14, +192, +78, +232, +77, +3, +250, +86, +25, +24, +43, +105, +5, +112, +157, +41, +31, +71, +50, +187, +122, +14, +152, +207, +212, +217, +155, +40, +246, +96, +7, +5, +48, +149, +68, +89, +109, +31, +105, +23, +110, +172, +201, +166, +191, +1, +5, +144, +115, +237, +126, +1, +184, +76, +253, +57, +126, +204, +239, +202, +235, +195, +183, +187, +208, +247, +113, +187, +255, +126, +100, +230, +250, +125, +197, +151, +63, +236, +191, +255, +161, +160, +175, +15, +250, +99, +174, +5, +188, +201, +244, +49, +19, +157, +177, +28, +133, +127, +200, +252, +248, +46, +45, +26, +91, +23, +64, +167, +248, +1, +23, +3, +115, +155, +186, +249, +128, +171, +77, +253, +78, +5, +253, +44, +0, +252, +219, +180, +13, +138, +228, +96, +224, +58, +83, +126, +51, +48, +239, +80, +159, +87, +118, +112, +87, +250, +131, +79, +67, +151, +2, +47, +248, +239, +247, +54, +232, +107, +110, +244, +193, +159, +69, +122, +93, +184, +38, +112, +57, +240, +18, +240, +8, +240, +75, +252, +122, +30, +93, +19, +3, +28, +86, +208, +111, +184, +129, +30, +52, +101, +215, +250, +178, +112, +211, +223, +98, +234, +238, +246, +101, +143, +23, +244, +57, +15, +186, +140, +88, +38, +83, +254, +152, +185, +241, +254, +199, +148, +239, +97, +126, +168, +45, +35, +253, +89, +5, +112, +89, +166, +238, +105, +95, +254, +112, +166, +252, +50, +35, +179, +88, +164, +207, +160, +0, +94, +0, +174, +240, +159, +47, +200, +180, +249, +160, +233, +227, +92, +243, +185, +72, +1, +172, +4, +236, +136, +218, +80, +166, +3, +31, +53, +117, +97, +189, +254, +157, +60, +121, +211, +246, +16, +223, +118, +6, +122, +147, +223, +16, +206, +223, +255, +191, +8, +88, +194, +140, +105, +159, +130, +190, +206, +0, +78, +240, +159, +131, +2, +248, +49, +176, +9, +250, +32, +190, +2, +124, +195, +215, +47, +237, +199, +93, +58, +27, +245, +237, +173, +162, +93, +175, +138, +140, +151, +187, +198, +200, +125, +36, +82, +191, +158, +169, +191, +176, +160, +159, +175, +152, +118, +23, +145, +86, +36, +231, +144, +198, +174, +85, +199, +215, +26, +232, +58, +61, +224, +39, +190, +236, +81, +255, +253, +177, +6, +253, +109, +236, +101, +207, +48, +101, +31, +71, +223, +96, +51, +129, +91, +80, +5, +1, +112, +170, +175, +31, +135, +26, +8, +175, +47, +232, +247, +15, +102, +156, +139, +163, +55, +91, +120, +171, +30, +235, +255, +207, +4, +22, +6, +22, +34, +121, +91, +254, +169, +160, +207, +185, +81, +163, +75, +48, +80, +230, +45, +7, +98, +248, +124, +164, +191, +182, +10, +96, +241, +72, +159, +65, +1, +204, +68, +215, +195, +160, +55, +254, +18, +166, +205, +207, +124, +249, +189, +164, +151, +2, +177, +37, +192, +166, +192, +126, +192, +242, +254, +251, +81, +190, +237, +120, +255, +253, +53, +232, +219, +246, +62, +42, +24, +183, +80, +197, +30, +176, +177, +31, +231, +12, +96, +85, +95, +54, +25, +216, +194, +180, +89, +41, +167, +31, +135, +62, +224, +107, +249, +239, +65, +1, +236, +108, +218, +156, +7, +92, +110, +190, +255, +21, +248, +102, +133, +49, +174, +158, +249, +237, +78, +45, +147, +49, +178, +47, +123, +153, +89, +192, +184, +72, +253, +2, +36, +247, +77, +209, +203, +230, +6, +115, +252, +213, +77, +249, +38, +190, +236, +90, +83, +255, +215, +170, +227, +107, +5, +244, +13, +24, +166, +37, +207, +225, +223, +64, +36, +111, +207, +24, +238, +40, +233, +243, +12, +223, +110, +83, +255, +125, +65, +146, +183, +247, +182, +190, +236, +11, +254, +251, +209, +70, +238, +18, +127, +33, +231, +202, +233, +119, +127, +51, +134, +245, +129, +117, +252, +231, +153, +232, +205, +50, +221, +127, +223, +128, +244, +58, +244, +192, +130, +177, +158, +102, +218, +77, +71, +31, +160, +187, +72, +20, +203, +76, +63, +246, +216, +223, +206, +145, +254, +170, +40, +128, +71, +50, +229, +85, +21, +0, +232, +186, +253, +21, +255, +121, +95, +95, +63, +14, +53, +92, +130, +26, +218, +236, +212, +62, +166, +0, +14, +247, +117, +143, +162, +203, +164, +48, +219, +251, +132, +175, +255, +190, +255, +190, +81, +222, +117, +203, +244, +55, +47, +201, +12, +236, +31, +254, +255, +149, +190, +238, +159, +153, +242, +73, +100, +150, +26, +166, +159, +165, +194, +57, +250, +239, +175, +42, +0, +84, +57, +172, +130, +26, +0, +79, +50, +50, +63, +6, +78, +169, +48, +198, +159, +147, +198, +100, +96, +209, +10, +114, +11, +27, +153, +92, +219, +5, +137, +29, +100, +38, +230, +205, +158, +105, +19, +140, +145, +175, +224, +239, +113, +84, +121, +220, +135, +206, +136, +151, +52, +199, +122, +178, +108, +108, +117, +17, +125, +168, +68, +100, +79, +17, +89, +193, +127, +62, +202, +57, +55, +201, +127, +126, +169, +197, +177, +86, +243, +255, +47, +241, +255, +183, +18, +145, +55, +138, +200, +53, +206, +185, +223, +251, +178, +240, +246, +178, +23, +245, +81, +17, +113, +34, +178, +112, +78, +191, +215, +152, +207, +239, +21, +145, +112, +115, +223, +234, +156, +123, +88, +68, +110, +244, +223, +215, +20, +145, +85, +77, +219, +171, +99, +157, +161, +107, +219, +237, +252, +215, +7, +68, +228, +109, +206, +185, +183, +57, +231, +86, +20, +145, +176, +204, +64, +68, +86, +112, +206, +189, +41, +242, +55, +33, +103, +156, +67, +137, +153, +34, +114, +174, +255, +252, +25, +255, +127, +3, +17, +9, +138, +227, +100, +17, +121, +77, +73, +31, +71, +137, +200, +15, +68, +100, +150, +136, +108, +42, +122, +174, +187, +58, +231, +46, +68, +223, +206, +251, +137, +200, +159, +156, +115, +127, +70, +183, +203, +2, +162, +6, +46, +231, +220, +52, +17, +185, +214, +127, +13, +191, +201, +5, +153, +255, +161, +252, +10, +231, +28, +37, +227, +203, +42, +136, +19, +252, +88, +111, +17, +145, +5, +69, +196, +238, +150, +204, +37, +250, +27, +229, +2, +221, +50, +12, +198, +225, +103, +252, +255, +249, +37, +249, +237, +171, +142, +37, +170, +184, +60, +230, +46, +106, +3, +188, +94, +68, +130, +221, +103, +146, +115, +110, +150, +255, +124, +168, +136, +44, +39, +34, +251, +59, +231, +158, +16, +145, +151, +125, +249, +98, +121, +138, +178, +41, +6, +20, +0, +176, +144, +136, +216, +53, +247, +247, +194, +47, +45, +233, +7, +104, +27, +17, +249, +148, +249, +219, +55, +239, +32, +168, +241, +226, +205, +34, +242, +184, +115, +46, +40, +145, +13, +253, +127, +187, +62, +10, +10, +192, +106, +186, +112, +81, +242, +110, +224, +137, +34, +50, +197, +127, +94, +85, +68, +194, +122, +236, +242, +204, +255, +53, +69, +21, +132, +136, +200, +116, +17, +185, +41, +167, +191, +229, +204, +231, +243, +156, +115, +15, +70, +218, +204, +45, +153, +27, +197, +191, +141, +222, +20, +105, +91, +21, +109, +126, +216, +215, +138, +72, +120, +3, +190, +15, +120, +135, +136, +236, +224, +191, +95, +229, +156, +187, +87, +74, +20, +128, +115, +110, +186, +115, +238, +0, +175, +196, +22, +112, +206, +189, +219, +57, +119, +130, +191, +225, +126, +33, +122, +141, +247, +245, +55, +109, +238, +246, +105, +6, +87, +100, +190, +103, +21, +64, +192, +229, +146, +143, +39, +68, +100, +178, +136, +172, +152, +41, +63, +70, +244, +190, +219, +219, +127, +31, +111, +234, +222, +41, +34, +247, +149, +140, +109, +115, +17, +9, +111, +251, +35, +68, +228, +121, +255, +185, +116, +157, +237, +156, +123, +222, +143, +73, +68, +100, +113, +34, +198, +57, +127, +157, +22, +240, +95, +39, +57, +231, +102, +150, +117, +235, +229, +86, +20, +145, +175, +136, +200, +69, +206, +185, +176, +92, +14, +207, +105, +153, +146, +108, +15, +6, +173, +181, +121, +120, +93, +141, +62, +131, +177, +231, +86, +83, +118, +187, +47, +219, +214, +148, +157, +229, +203, +54, +49, +101, +23, +161, +75, +128, +92, +39, +15, +18, +99, +229, +189, +36, +83, +215, +205, +125, +221, +39, +205, +20, +235, +78, +255, +185, +200, +166, +240, +110, +115, +142, +255, +1, +86, +3, +222, +5, +252, +136, +180, +45, +224, +21, +116, +218, +188, +41, +186, +116, +185, +22, +56, +47, +167, +207, +42, +75, +128, +71, +51, +229, +117, +150, +0, +239, +70, +237, +22, +193, +72, +121, +52, +201, +146, +96, +143, +204, +181, +133, +2, +35, +96, +228, +56, +193, +190, +240, +101, +255, +253, +20, +127, +141, +195, +181, +200, +221, +226, +2, +62, +102, +142, +105, +247, +254, +199, +145, +248, +4, +0, +172, +154, +215, +135, +111, +127, +58, +222, +121, +136, +184, +13, +224, +124, +224, +54, +255, +121, +25, +212, +214, +176, +90, +78, +119, +65, +38, +236, +82, +204, +68, +167, +217, +167, +152, +241, +252, +111, +133, +235, +98, +45, +244, +235, +70, +234, +55, +54, +245, +23, +231, +244, +49, +23, +201, +206, +218, +20, +244, +37, +114, +137, +255, +252, +118, +223, +102, +177, +216, +53, +28, +18, +160, +22, +212, +96, +220, +120, +20, +53, +132, +217, +191, +155, +205, +96, +10, +247, +90, +51, +253, +46, +232, +101, +238, +52, +101, +97, +29, +184, +133, +41, +11, +30, +107, +31, +240, +223, +199, +161, +142, +51, +119, +198, +250, +53, +114, +217, +45, +186, +89, +36, +118, +139, +133, +252, +13, +97, +113, +116, +73, +127, +23, +146, +143, +171, +11, +234, +94, +36, +162, +168, +168, +166, +0, +30, +203, +148, +215, +81, +0, +171, +249, +178, +31, +249, +239, +246, +166, +90, +212, +215, +157, +103, +218, +87, +82, +0, +126, +220, +147, +80, +3, +237, +220, +192, +70, +94, +126, +111, +146, +107, +90, +164, +0, +22, +64, +141, +188, +0, +191, +201, +212, +5, +133, +244, +28, +57, +246, +29, +211, +54, +108, +3, +126, +148, +184, +2, +56, +5, +221, +69, +114, +192, +159, +49, +6, +193, +156, +254, +222, +100, +174, +209, +21, +190, +204, +26, +189, +127, +80, +225, +218, +216, +109, +192, +203, +72, +91, +239, +199, +145, +222, +37, +248, +92, +65, +63, +19, +77, +187, +159, +248, +255, +214, +167, +197, +122, +74, +14, +173, +17, +16, +248, +173, +57, +216, +215, +34, +245, +191, +51, +245, +123, +162, +90, +46, +251, +23, +53, +162, +248, +27, +225, +37, +252, +26, +6, +248, +155, +239, +231, +167, +254, +251, +186, +166, +239, +53, +124, +217, +206, +254, +251, +55, +74, +198, +109, +127, +60, +48, +51, +13, +95, +159, +117, +133, +221, +54, +175, +47, +223, +254, +53, +192, +17, +168, +225, +111, +10, +250, +144, +158, +143, +119, +183, +69, +29, +144, +46, +71, +223, +98, +83, +209, +153, +194, +207, +129, +21, +138, +250, +237, +18, +164, +21, +192, +251, +124, +217, +123, +50, +231, +105, +119, +92, +206, +55, +229, +85, +21, +192, +4, +84, +153, +174, +129, +122, +170, +61, +140, +110, +57, +58, +42, +40, +128, +46, +129, +26, +50, +39, +225, +141, +146, +145, +250, +5, +129, +83, +125, +155, +101, +75, +250, +58, +196, +92, +139, +224, +169, +184, +0, +122, +127, +130, +58, +169, +149, +57, +239, +204, +79, +50, +163, +4, +245, +12, +61, +16, +245, +86, +180, +47, +202, +219, +139, +250, +34, +237, +152, +6, +234, +100, +55, +159, +175, +155, +151, +244, +76, +99, +151, +242, +43, +213, +16, +232, +52, +50, +252, +168, +47, +16, +121, +144, +129, +223, +80, +142, +53, +114, +250, +191, +220, +215, +175, +234, +191, +127, +198, +127, +159, +5, +220, +138, +62, +72, +97, +87, +224, +86, +212, +53, +120, +10, +186, +27, +81, +184, +126, +37, +109, +41, +5, +175, +84, +76, +253, +247, +51, +245, +149, +103, +47, +163, +21, +68, +20, +128, +47, +191, +213, +148, +111, +108, +202, +107, +41, +0, +18, +215, +216, +95, +248, +239, +251, +230, +252, +222, +247, +15, +201, +9, +14, +142, +199, +161, +15, +216, +52, +116, +134, +182, +59, +186, +196, +216, +12, +93, +182, +62, +70, +117, +87, +96, +187, +155, +101, +221, +196, +207, +48, +229, +155, +85, +232, +231, +29, +232, +3, +155, +135, +7, +129, +55, +151, +244, +177, +16, +106, +241, +15, +184, +14, +248, +50, +170, +72, +110, +49, +229, +19, +25, +74, +101, +139, +186, +161, +6, +252, +40, +167, +205, +79, +40, +71, +158, +2, +56, +208, +215, +255, +202, +127, +119, +232, +212, +253, +121, +244, +13, +251, +61, +96, +81, +212, +227, +112, +26, +186, +20, +249, +61, +176, +116, +197, +241, +223, +107, +198, +176, +101, +166, +206, +174, +199, +162, +174, +181, +99, +13, +228, +43, +128, +224, +88, +242, +164, +189, +97, +168, +175, +0, +54, +68, +103, +78, +175, +243, +223, +63, +138, +206, +8, +194, +95, +176, +1, +252, +112, +104, +206, +48, +119, +92, +43, +162, +193, +105, +119, +250, +123, +228, +113, +244, +229, +178, +59, +176, +64, +5, +121, +235, +159, +80, +132, +115, +202, +250, +242, +253, +45, +130, +62, +172, +193, +135, +127, +50, +201, +242, +98, +42, +176, +119, +133, +62, +62, +93, +50, +150, +59, +201, +241, +90, +29, +51, +64, +163, +255, +158, +240, +55, +206, +198, +37, +109, +11, +215, +132, +61, +70, +30, +12, +243, +18, +160, +43, +144, +94, +230, +22, +97, +58, +21, +34, +82, +115, +142, +177, +1, +234, +64, +22, +240, +243, +130, +182, +115, +123, +229, +49, +9, +53, +42, +223, +130, +206, +192, +159, +67, +221, +130, +191, +138, +238, +204, +141, +125, +160, +251, +199, +51, +209, +55, +252, +120, +116, +171, +36, +219, +230, +189, +212, +8, +235, +28, +203, +64, +141, +174, +227, +209, +53, +227, +115, +232, +76, +40, +76, +1, +75, +29, +82, +122, +212, +3, +106, +219, +9, +187, +68, +179, +80, +195, +246, +206, +153, +191, +75, +204, +131, +251, +213, +22, +199, +122, +27, +186, +254, +127, +128, +226, +40, +199, +181, +80, +207, +197, +220, +160, +183, +217, +10, +232, +212, +242, +57, +127, +129, +103, +160, +107, +214, +139, +128, +171, +80, +207, +39, +136, +108, +171, +140, +38, +208, +65, +44, +57, +58, +237, +123, +17, +53, +30, +125, +17, +117, +139, +222, +8, +157, +78, +222, +131, +174, +105, +215, +26, +154, +51, +152, +51, +129, +6, +110, +5, +252, +61, +167, +205, +39, +77, +155, +127, +182, +60, +222, +107, +128, +165, +218, +244, +49, +91, +2, +37, +229, +56, +8, +93, +187, +61, +229, +167, +91, +79, +249, +135, +225, +7, +152, +64, +155, +209, +6, +58, +136, +37, +247, +15, +255, +20, +252, +30, +125, +164, +126, +46, +224, +91, +232, +26, +50, +106, +83, +233, +81, +31, +164, +183, +86, +163, +17, +122, +232, +148, +252, +17, +211, +238, +3, +195, +61, +206, +17, +7, +240, +22, +212, +184, +2, +186, +197, +85, +106, +92, +25, +11, +64, +99, +28, +14, +71, +13, +158, +59, +251, +7, +109, +77, +116, +221, +85, +233, +237, +77, +203, +88, +114, +224, +141, +254, +205, +191, +187, +255, +190, +10, +240, +119, +212, +128, +244, +24, +112, +114, +120, +107, +160, +70, +210, +251, +169, +24, +6, +74, +195, +200, +182, +177, +0, +210, +91, +119, +223, +29, +233, +241, +204, +246, +64, +163, +182, +194, +122, +233, +251, +35, +61, +158, +46, +0, +124, +131, +52, +30, +34, +9, +152, +25, +150, +55, +45, +26, +149, +119, +141, +255, +188, +20, +202, +244, +114, +19, +58, +61, +253, +18, +106, +12, +250, +155, +175, +31, +231, +21, +241, +64, +156, +127, +164, +223, +198, +145, +109, +166, +143, +214, +10, +210, +244, +229, +208, +89, +12, +232, +108, +39, +55, +38, +190, +66, +95, +31, +35, +49, +58, +78, +104, +218, +79, +143, +154, +64, +99, +154, +167, +249, +139, +255, +190, +114, +137, +209, +13, +116, +235, +236, +113, +116, +71, +98, +19, +212, +254, +240, +44, +37, +142, +70, +145, +126, +22, +66, +183, +219, +110, +68, +103, +2, +129, +190, +105, +63, +202, +125, +22, +110, +6, +246, +244, +159, +195, +150, +221, +155, +76, +253, +23, +125, +191, +129, +224, +226, +104, +140, +67, +79, +65, +191, +141, +34, +219, +50, +125, +116, +162, +32, +253, +245, +9, +177, +236, +119, +146, +120, +59, +254, +144, +156, +168, +184, +146, +254, +142, +66, +61, +71, +207, +103, +140, +237, +58, +12, +53, +80, +87, +225, +191, +160, +187, +14, +127, +99, +36, +104, +195, +230, +36, +0, +203, +147, +166, +130, +202, +226, +14, +10, +216, +142, +188, +194, +8, +177, +237, +199, +1, +79, +149, +28, +111, +79, +224, +198, +146, +54, +243, +123, +37, +4, +58, +131, +8, +40, +37, +217, +204, +244, +211, +149, +130, +220, +221, +43, +177, +137, +168, +189, +103, +37, +116, +41, +115, +5, +21, +249, +246, +102, +87, +84, +121, +64, +253, +53, +171, +180, +21, +238, +149, +234, +41, +232, +140, +235, +36, +60, +119, +71, +219, +65, +54, +126, +195, +149, +244, +219, +120, +29, +71, +7, +83, +202, +182, +231, +133, +82, +61, +217, +117, +246, +45, +232, +91, +243, +16, +210, +30, +120, +19, +137, +144, +68, +248, +62, +158, +195, +19, +109, +162, +111, +237, +50, +5, +240, +121, +224, +134, +146, +54, +150, +27, +113, +95, +146, +93, +150, +220, +160, +167, +177, +4, +26, +216, +54, +80, +99, +222, +97, +232, +54, +220, +115, +40, +35, +82, +161, +87, +94, +78, +63, +139, +162, +59, +60, +191, +68, +61, +246, +178, +81, +137, +117, +250, +250, +30, +106, +96, +124, +39, +202, +34, +117, +45, +234, +204, +244, +138, +191, +15, +191, +128, +6, +51, +221, +237, +31, +230, +82, +37, +128, +206, +16, +3, +239, +226, +111, +129, +99, +155, +142, +47, +116, +216, +234, +13, +87, +208, +111, +227, +117, +28, +29, +76, +41, +187, +56, +47, +18, +194, +18, +208, +183, +217, +56, +83, +55, +142, +180, +149, +121, +183, +156, +62, +110, +198, +191, +153, +209, +253, +126, +128, +55, +154, +250, +125, +80, +15, +188, +64, +14, +241, +83, +74, +150, +0, +180, +140, +108, +139, +244, +215, +137, +49, +177, +139, +126, +104, +104, +219, +32, +161, +38, +255, +55, +73, +220, +201, +205, +230, +186, +46, +134, +62, +116, +27, +150, +244, +147, +101, +107, +110, +164, +0, +80, +133, +20, +104, +217, +44, +177, +236, +51, +36, +247, +51, +36, +164, +51, +87, +81, +237, +165, +180, +36, +106, +68, +158, +4, +92, +74, +155, +29, +52, +58, +120, +195, +21, +244, +221, +120, +29, +71, +203, +41, +101, +87, +231, +69, +194, +96, +3, +17, +30, +126, +210, +110, +166, +121, +251, +204, +227, +129, +171, +253, +231, +37, +73, +102, +33, +159, +69, +31, +254, +39, +241, +28, +114, +126, +220, +79, +2, +59, +196, +250, +242, +109, +90, +71, +182, +101, +250, +107, +109, +76, +236, +184, +159, +166, +172, +61, +33, +202, +110, +9, +255, +61, +196, +162, +172, +232, +191, +7, +143, +192, +143, +150, +244, +179, +37, +234, +187, +114, +143, +149, +247, +117, +165, +12, +201, +153, +190, +230, +37, +137, +119, +185, +26, +195, +91, +8, +172, +108, +198, +248, +44, +35, +225, +253, +71, +7, +111, +184, +209, +136, +174, +206, +139, +100, +87, +4, +224, +181, +145, +250, +113, +36, +20, +100, +79, +231, +244, +17, +182, +1, +119, +243, +223, +223, +131, +122, +159, +61, +143, +186, +74, +159, +74, +178, +13, +248, +99, +116, +10, +59, +95, +172, +47, +223, +166, +117, +100, +91, +166, +191, +214, +198, +196, +174, +250, +161, +133, +109, +3, +221, +82, +125, +201, +124, +159, +224, +101, +215, +69, +21, +245, +44, +76, +130, +146, +10, +253, +133, +23, +136, +85, +0, +149, +24, +146, +77, +251, +192, +143, +112, +43, +241, +176, +241, +113, +36, +28, +128, +149, +168, +215, +50, +99, +131, +54, +219, +191, +116, +240, +134, +203, +180, +239, +196, +150, +208, +182, +159, +46, +206, +11, +125, +168, +2, +158, +143, +181, +241, +237, +158, +50, +237, +162, +251, +247, +36, +142, +64, +209, +56, +113, +116, +251, +237, +40, +42, +56, +2, +209, +81, +100, +155, +151, +233, +202, +152, +216, +85, +63, +141, +109, +27, +232, +214, +234, +44, +6, +103, +0, +43, +163, +46, +186, +79, +19, +225, +89, +40, +232, +47, +165, +0, +168, +193, +144, +108, +250, +248, +133, +151, +249, +84, +65, +155, +16, +22, +127, +114, +197, +62, +59, +153, +105, +133, +206, +90, +191, +225, +76, +219, +78, +108, +9, +93, +244, +211, +197, +121, +161, +110, +157, +1, +47, +20, +28, +203, +6, +129, +228, +58, +240, +160, +148, +231, +47, +162, +235, +253, +224, +10, +188, +33, +234, +10, +124, +55, +106, +141, +95, +187, +228, +188, +186, +142, +108, +235, +196, +152, +216, +97, +63, +141, +109, +27, +36, +209, +167, +119, +147, +36, +57, +185, +21, +229, +219, +135, +154, +20, +219, +24, +5, +64, +77, +134, +100, +211, +199, +165, +190, +143, +220, +157, +0, +84, +121, +206, +162, +196, +240, +107, +218, +119, +50, +99, +235, +250, +13, +215, +213, +154, +187, +11, +171, +123, +151, +231, +245, +162, +105, +51, +176, +70, +35, +97, +62, +2, +152, +20, +235, +35, +211, +126, +105, +212, +49, +232, +22, +116, +9, +240, +12, +170, +16, +190, +74, +36, +80, +42, +34, +223, +105, +100, +27, +29, +25, +19, +187, +232, +135, +150, +182, +13, +212, +169, +233, +8, +52, +38, +255, +121, +212, +246, +180, +54, +106, +117, +255, +7, +53, +201, +53, +73, +43, +128, +90, +12, +201, +166, +143, +16, +114, +159, +251, +91, +144, +220, +175, +133, +172, +70, +190, +109, +39, +51, +173, +208, +89, +103, +111, +56, +186, +91, +115, +119, +97, +117, +239, +242, +188, +174, +50, +109, +6, +126, +124, +210, +201, +32, +46, +203, +59, +86, +23, +160, +227, +200, +54, +58, +50, +38, +118, +216, +79, +167, +182, +13, +47, +127, +46, +186, +102, +255, +48, +74, +110, +243, +164, +239, +231, +215, +64, +30, +235, +116, +144, +13, +10, +96, +107, +84, +161, +254, +209, +151, +239, +137, +186, +203, +191, +140, +42, +242, +220, +229, +22, +9, +159, +198, +64, +242, +24, +211, +38, +228, +174, +252, +77, +94, +27, +211, +182, +219, +237, +95, +58, +122, +195, +209, +145, +45, +161, +195, +126, +186, +58, +47, +171, +144, +174, +38, +173, +144, +230, +38, +173, +144, +6, +18, +132, +116, +9, +58, +142, +108, +163, +163, +7, +174, +195, +126, +58, +179, +109, +120, +185, +205, +189, +204, +119, +76, +31, +215, +146, +100, +152, +142, +38, +87, +205, +244, +225, +208, +151, +192, +139, +168, +162, +11, +125, +62, +141, +38, +142, +157, +234, +255, +150, +203, +145, +15, +73, +83, +111, +39, +18, +95, +131, +190, +212, +2, +125, +221, +218, +21, +198, +211, +233, +246, +111, +103, +111, +56, +58, +178, +37, +116, +216, +79, +87, +231, +21, +91, +146, +28, +132, +238, +57, +219, +12, +47, +119, +80, +96, +185, +239, +2, +116, +28, +217, +70, +119, +52, +89, +173, +251, +161, +123, +219, +198, +107, +208, +165, +192, +125, +168, +99, +207, +116, +255, +125, +110, +116, +107, +238, +73, +76, +98, +142, +130, +126, +178, +12, +201, +251, +163, +222, +147, +129, +129, +250, +82, +95, +191, +73, +142, +252, +82, +36, +108, +200, +215, +98, +152, +139, +81, +227, +100, +72, +241, +54, +149, +18, +126, +73, +58, +222, +254, +13, +157, +182, +126, +195, +209, +209, +154, +187, +171, +126, +186, +58, +47, +211, +126, +121, +210, +201, +28, +179, +184, +155, +97, +36, +7, +237, +2, +116, +244, +192, +117, +216, +79, +215, +182, +141, +144, +21, +105, +35, +116, +27, +22, +124, +150, +34, +95, +31, +184, +247, +6, +114, +48, +154, +54, +41, +134, +228, +72, +253, +234, +232, +242, +98, +26, +17, +206, +73, +212, +38, +17, +168, +240, +237, +139, +109, +18, +233, +123, +56, +76, +227, +31, +161, +96, +89, +194, +16, +44, +145, +58, +121, +195, +209, +209, +154, +187, +171, +126, +186, +58, +175, +76, +127, +11, +123, +217, +155, +252, +15, +246, +60, +106, +136, +252, +26, +176, +72, +153, +252, +104, +3, +29, +61, +112, +93, +244, +67, +247, +182, +141, +149, +253, +241, +206, +242, +223, +231, +245, +223, +31, +66, +31, +202, +185, +209, +29, +151, +201, +20, +204, +0, +48, +12, +201, +145, +186, +15, +161, +247, +225, +12, +138, +51, +1, +111, +129, +122, +37, +46, +140, +218, +14, +178, +174, +192, +251, +160, +203, +209, +115, +40, +127, +17, +117, +186, +68, +178, +29, +183, +126, +195, +209, +221, +154, +187, +51, +171, +123, +23, +231, +53, +59, +130, +142, +30, +184, +14, +251, +217, +201, +180, +233, +194, +182, +241, +81, +116, +157, +111, +35, +46, +195, +67, +114, +3, +73, +158, +135, +220, +253, +115, +50, +12, +201, +145, +177, +188, +140, +190, +4, +162, +83, +255, +186, +160, +100, +135, +130, +142, +151, +72, +177, +3, +180, +122, +195, +209, +221, +154, +187, +83, +171, +123, +219, +243, +154, +29, +65, +71, +15, +92, +135, +253, +116, +106, +219, +200, +145, +127, +29, +74, +59, +255, +36, +58, +253, +62, +158, +130, +189, +115, +50, +12, +201, +166, +124, +3, +18, +223, +253, +43, +208, +157, +133, +223, +80, +146, +119, +162, +45, +24, +6, +98, +211, +182, +3, +236, +100, +205, +221, +85, +63, +179, +35, +80, +214, +166, +31, +163, +179, +154, +87, +80, +101, +118, +53, +58, +141, +172, +28, +167, +65, +71, +15, +92, +87, +253, +140, +37, +48, +200, +159, +16, +80, +152, +121, +170, +229, +49, +135, +141, +216, +180, +205, +32, +59, +89, +115, +119, +213, +207, +236, +6, +116, +175, +216, +230, +214, +203, +226, +26, +74, +246, +181, +123, +140, +77, +48, +204, +196, +166, +141, +65, +71, +107, +238, +174, +250, +25, +105, +160, +177, +224, +1, +191, +139, +212, +239, +99, +234, +175, +140, +245, +225, +219, +189, +145, +196, +82, +12, +234, +93, +246, +53, +212, +163, +208, +38, +71, +25, +56, +70, +143, +177, +15, +198, +210, +76, +139, +142, +214, +220, +93, +245, +51, +146, +64, +89, +118, +44, +29, +250, +114, +166, +110, +110, +224, +191, +230, +7, +203, +165, +3, +71, +249, +1, +2, +190, +151, +169, +91, +152, +36, +220, +116, +22, +179, +65, +10, +180, +30, +35, +0, +102, +35, +86, +96, +58, +96, +116, +33, +157, +236, +113, +223, +156, +54, +95, +53, +109, +162, +174, +152, +192, +161, +166, +205, +49, +166, +220, +166, +134, +186, +176, +100, +44, +65, +179, +207, +36, +158, +88, +229, +56, +211, +215, +142, +117, +207, +117, +172, +130, +142, +108, +34, +61, +60, +152, +77, +88, +129, +41, +97, +116, +161, +2, +169, +3, +9, +187, +12, +228, +231, +122, +191, +194, +180, +249, +82, +78, +155, +215, +162, +14, +26, +160, +91, +71, +33, +133, +185, +85, +48, +185, +228, +171, +232, +27, +62, +224, +190, +156, +54, +14, +221, +223, +158, +135, +200, +118, +18, +73, +198, +101, +252, +88, +22, +202, +212, +175, +101, +234, +95, +161, +132, +230, +60, +35, +91, +153, +242, +141, +116, +10, +246, +88, +38, +234, +229, +72, +188, +60, +95, +161, +32, +71, +36, +29, +217, +68, +128, +29, +209, +89, +230, +139, +40, +225, +204, +79, +105, +198, +133, +16, +150, +115, +59, +250, +239, +151, +161, +51, +178, +198, +116, +122, +35, +2, +102, +3, +86, +96, +10, +24, +93, +124, +125, +41, +169, +3, +234, +118, +25, +146, +97, +78, +35, +179, +236, +64, +233, +165, +2, +221, +217, +12, +10, +178, +193, +160, +28, +6, +1, +135, +147, +4, +127, +128, +15, +48, +41, +144, +125, +187, +105, +123, +107, +81, +219, +130, +62, +28, +201, +222, +55, +192, +145, +153, +58, +107, +92, +61, +172, +70, +191, +181, +40, +223, +128, +247, +153, +227, +60, +70, +198, +136, +11, +28, +107, +234, +115, +95, +64, +116, +100, +19, +33, +61, +59, +179, +184, +129, +154, +76, +198, +192, +175, +188, +236, +202, +254, +251, +36, +224, +158, +58, +125, +244, +232, +24, +196, +25, +93, +42, +147, +58, +144, +54, +190, +108, +151, +169, +251, +172, +169, +187, +168, +164, +159, +249, +80, +63, +116, +208, +61, +232, +16, +240, +52, +147, +242, +24, +247, +214, +10, +192, +247, +179, +42, +137, +31, +249, +43, +120, +78, +66, +96, +7, +211, +255, +189, +212, +200, +209, +72, +3, +202, +55, +224, +44, +115, +188, +207, +153, +242, +55, +248, +113, +129, +206, +66, +139, +92, +116, +91, +219, +68, +80, +239, +192, +224, +116, +246, +111, +96, +27, +210, +75, +169, +181, +43, +94, +134, +208, +223, +181, +232, +139, +98, +94, +244, +229, +1, +37, +202, +221, +203, +237, +226, +101, +95, +68, +103, +52, +55, +2, +187, +81, +30, +163, +144, +157, +229, +6, +60, +75, +146, +107, +178, +82, +114, +153, +108, +199, +173, +168, +134, +232, +128, +17, +136, +244, +27, +211, +158, +216, +68, +148, +220, +225, +13, +53, +207, +37, +48, +186, +212, +34, +117, +64, +89, +92, +3, +126, +151, +169, +59, +211, +212, +237, +92, +161, +175, +221, +34, +231, +84, +37, +26, +109, +113, +211, +62, +186, +4, +168, +10, +224, +103, +166, +175, +19, +80, +197, +116, +191, +41, +43, +204, +224, +220, +5, +128, +119, +145, +40, +162, +187, +73, +8, +59, +143, +52, +227, +24, +95, +210, +71, +107, +155, +8, +186, +12, +12, +248, +162, +47, +91, +200, +148, +109, +94, +227, +156, +28, +250, +0, +223, +230, +191, +135, +45, +185, +111, +150, +200, +89, +69, +150, +197, +128, +7, +98, +70, +54, +79, +1, +88, +76, +164, +206, +214, +48, +45, +169, +134, +232, +142, +17, +40, +166, +0, +44, +30, +163, +132, +216, +209, +247, +147, +85, +0, +181, +72, +29, +80, +239, +177, +169, +94, +230, +89, +146, +196, +29, +243, +145, +188, +61, +38, +23, +93, +100, +210, +138, +34, +15, +167, +151, +140, +35, +216, +16, +102, +16, +217, +1, +65, +13, +97, +207, +249, +191, +92, +143, +52, +127, +62, +33, +8, +101, +38, +112, +162, +25, +195, +249, +37, +99, +232, +114, +253, +110, +143, +187, +37, +106, +39, +9, +241, +29, +79, +151, +92, +207, +214, +54, +17, +223, +198, +254, +134, +103, +145, +166, +160, +127, +153, +10, +212, +97, +168, +7, +96, +21, +12, +56, +9, +161, +36, +35, +97, +137, +249, +56, +240, +25, +52, +86, +192, +58, +252, +228, +178, +253, +146, +86, +0, +223, +37, +113, +8, +58, +4, +120, +212, +212, +253, +182, +236, +60, +108, +167, +141, +169, +134, +232, +144, +93, +152, +180, +2, +56, +219, +159, +216, +190, +192, +121, +166, +252, +5, +224, +173, +37, +253, +88, +70, +151, +149, +72, +147, +58, +108, +105, +250, +202, +157, +190, +146, +208, +58, +3, +124, +204, +151, +89, +167, +139, +50, +250, +238, +131, +208, +41, +242, +249, +153, +235, +112, +175, +41, +63, +176, +164, +143, +95, +27, +185, +195, +50, +117, +11, +147, +222, +255, +125, +123, +73, +95, +187, +51, +136, +41, +192, +219, +74, +228, +58, +89, +191, +251, +182, +111, +33, +113, +167, +189, +158, +36, +91, +18, +148, +7, +250, +116, +178, +36, +242, +125, +89, +63, +141, +16, +181, +55, +141, +234, +57, +35, +191, +232, +127, +191, +16, +89, +120, +155, +255, +30, +20, +246, +133, +254, +251, +0, +15, +36, +176, +183, +57, +246, +129, +166, +220, +62, +131, +185, +220, +144, +164, +21, +192, +218, +153, +186, +183, +147, +188, +184, +166, +80, +133, +194, +140, +150, +84, +67, +116, +200, +46, +76, +90, +1, +140, +207, +212, +29, +104, +234, +206, +43, +233, +39, +40, +128, +119, +146, +38, +117, +120, +61, +201, +150, +39, +20, +43, +128, +109, +77, +187, +31, +251, +50, +59, +197, +172, +51, +85, +180, +15, +95, +229, +216, +109, +116, +102, +245, +178, +145, +61, +19, +141, +75, +63, +28, +221, +178, +13, +40, +13, +4, +65, +223, +116, +215, +145, +198, +183, +42, +142, +163, +245, +250, +221, +200, +216, +229, +72, +8, +103, +125, +132, +146, +237, +103, +186, +85, +0, +175, +55, +199, +6, +141, +22, +92, +179, +65, +63, +97, +249, +178, +158, +255, +126, +23, +250, +44, +229, +6, +248, +160, +9, +76, +2, +182, +54, +229, +127, +241, +101, +51, +40, +142, +194, +204, +85, +0, +190, +126, +162, +169, +127, +103, +149, +147, +104, +69, +53, +68, +135, +236, +194, +20, +43, +128, +185, +72, +214, +173, +51, +40, +152, +106, +26, +153, +44, +169, +195, +41, +232, +141, +26, +166, +96, +69, +10, +96, +1, +146, +169, +226, +189, +232, +3, +20, +140, +76, +207, +82, +98, +104, +161, +131, +37, +128, +239, +231, +83, +36, +41, +202, +99, +184, +153, +106, +15, +222, +188, +12, +46, +211, +126, +94, +38, +231, +101, +91, +175, +223, +77, +95, +75, +145, +86, +106, +80, +33, +182, +131, +142, +108, +34, +232, +139, +224, +214, +204, +241, +159, +198, +123, +152, +146, +208, +126, +221, +86, +161, +175, +11, +209, +123, +105, +81, +116, +70, +54, +139, +114, +195, +240, +120, +115, +220, +173, +124, +217, +255, +146, +220, +147, +191, +47, +145, +47, +154, +1, +56, +210, +182, +157, +194, +153, +178, +61, +9, +104, +72, +53, +68, +183, +236, +194, +185, +10, +192, +215, +219, +53, +100, +161, +225, +138, +12, +169, +3, +74, +16, +1, +58, +5, +11, +91, +88, +133, +22, +108, +52, +125, +119, +192, +78, +230, +243, +175, +139, +228, +188, +108, +235, +37, +128, +233, +107, +69, +52, +138, +237, +1, +116, +138, +247, +60, +186, +223, +189, +31, +21, +227, +34, +128, +175, +51, +136, +153, +152, +132, +21, +37, +242, +141, +215, +239, +145, +190, +236, +20, +252, +62, +42, +58, +239, +208, +210, +38, +226, +239, +3, +59, +229, +63, +138, +228, +222, +252, +47, +122, +255, +135, +101, +215, +253, +57, +99, +176, +47, +204, +34, +220, +146, +35, +31, +83, +0, +223, +54, +101, +133, +118, +42, +114, +20, +0, +176, +4, +154, +98, +62, +224, +65, +202, +200, +80, +105, +207, +198, +218, +21, +35, +144, +93, +103, +102, +49, +193, +180, +251, +190, +41, +47, +92, +162, +96, +72, +29, +128, +69, +208, +183, +247, +21, +168, +150, +172, +170, +0, +54, +48, +199, +123, +194, +124, +94, +187, +72, +46, +210, +79, +163, +37, +64, +87, +64, +115, +208, +133, +183, +238, +116, +52, +199, +92, +192, +181, +84, +96, +205, +165, +197, +250, +61, +210, +215, +230, +70, +246, +204, +26, +114, +173, +108, +34, +164, +67, +202, +127, +238, +203, +182, +49, +247, +195, +141, +36, +247, +106, +116, +92, +232, +140, +246, +108, +148, +30, +12, +244, +65, +59, +27, +77, +99, +23, +174, +231, +217, +248, +101, +99, +68, +62, +166, +0, +236, +125, +125, +64, +201, +53, +168, +178, +11, +48, +139, +42, +97, +202, +180, +164, +26, +162, +59, +70, +160, +21, +253, +133, +179, +211, +151, +135, +125, +217, +161, +166, +221, +143, +77, +125, +81, +104, +113, +138, +212, +1, +93, +218, +196, +112, +127, +201, +245, +153, +135, +244, +131, +31, +198, +85, +41, +155, +171, +233, +103, +164, +21, +128, +93, +195, +31, +227, +207, +235, +95, +166, +108, +247, +138, +253, +52, +90, +191, +71, +250, +105, +170, +0, +90, +217, +68, +208, +135, +61, +224, +39, +166, +124, +39, +146, +41, +120, +192, +166, +37, +99, +9, +153, +127, +190, +237, +191, +7, +35, +222, +170, +37, +114, +49, +5, +240, +110, +18, +227, +221, +12, +10, +242, +24, +80, +174, +0, +30, +192, +216, +22, +10, +65, +55, +164, +142, +93, +50, +249, +148, +45, +1, +254, +104, +234, +115, +25, +89, +200, +144, +58, +160, +10, +97, +130, +249, +11, +63, +246, +15, +139, +198, +227, +101, +173, +149, +27, +198, +152, +171, +52, +105, +239, +195, +231, +240, +219, +92, +104, +74, +240, +128, +167, +168, +150, +155, +160, +209, +250, +61, +210, +79, +35, +5, +224, +101, +27, +219, +68, +208, +45, +203, +48, +227, +157, +130, +46, +139, +54, +70, +221, +191, +173, +1, +252, +126, +202, +153, +122, +242, +92, +128, +11, +45, +239, +68, +20, +128, +47, +223, +152, +68, +169, +206, +2, +62, +157, +35, +31, +219, +6, +220, +9, +85, +110, +171, +82, +245, +229, +68, +119, +164, +142, +157, +49, +249, +80, +108, +4, +156, +159, +100, +159, +115, +38, +134, +246, +169, +46, +168, +184, +4, +240, +109, +63, +152, +185, +30, +133, +26, +126, +52, +1, +53, +252, +89, +37, +127, +64, +166, +222, +146, +73, +20, +58, +160, +24, +153, +70, +235, +247, +76, +31, +141, +21, +128, +151, +111, +108, +19, +65, +221, +134, +171, +224, +200, +146, +126, +194, +27, +255, +189, +254, +251, +147, +192, +127, +43, +140, +61, +170, +0, +124, +221, +251, +72, +118, +85, +158, +36, +114, +127, +82, +178, +11, +80, +25, +116, +71, +14, +217, +37, +11, +111, +145, +2, +56, +220, +212, +93, +208, +248, +196, +231, +32, +144, +94, +226, +221, +199, +224, +30, +190, +117, +19, +158, +9, +172, +94, +161, +207, +86, +15, +111, +135, +125, +44, +64, +162, +200, +75, +179, +70, +103, +100, +183, +68, +105, +189, +159, +71, +103, +2, +255, +69, +151, +19, +155, +147, +142, +157, +200, +93, +26, +121, +249, +89, +232, +12, +119, +49, +223, +190, +208, +169, +202, +203, +229, +42, +0, +95, +255, +87, +83, +63, +240, +146, +163, +11, +5, +64, +135, +84, +67, +116, +200, +228, +67, +90, +1, +252, +17, +141, +216, +218, +155, +180, +35, +208, +139, +192, +242, +141, +78, +188, +71, +107, +208, +193, +195, +219, +209, +56, +222, +100, +238, +209, +89, +192, +39, +71, +106, +44, +117, +144, +85, +0, +168, +39, +224, +65, +254, +186, +126, +137, +100, +121, +243, +114, +236, +121, +233, +74, +1, +236, +100, +58, +233, +130, +141, +181, +43, +70, +160, +50, +87, +224, +210, +36, +154, +99, +1, +164, +21, +230, +222, +145, +250, +247, +152, +250, +104, +72, +242, +72, +129, +81, +162, +0, +204, +120, +130, +229, +127, +252, +72, +143, +165, +10, +24, +84, +0, +231, +231, +220, +235, +135, +231, +200, +55, +86, +0, +214, +56, +176, +139, +249, +156, +23, +152, +114, +145, +136, +60, +234, +63, +191, +139, +2, +170, +33, +231, +220, +61, +34, +178, +186, +136, +28, +40, +34, +19, +69, +228, +121, +17, +121, +65, +68, +110, +22, +145, +131, +68, +100, +117, +231, +220, +221, +117, +6, +107, +240, +188, +239, +243, +27, +34, +178, +146, +115, +238, +178, +134, +253, +140, +86, +28, +69, +65, +72, +113, +143, +124, +160, +252, +255, +75, +139, +8, +34, +82, +154, +96, +115, +148, +226, +63, +34, +242, +95, +17, +153, +34, +34, +79, +137, +200, +149, +34, +178, +181, +115, +238, +136, +88, +99, +231, +220, +230, +46, +193, +101, +195, +55, +204, +217, +16, +168, +7, +215, +97, +36, +17, +140, +147, +81, +71, +157, +227, +40, +240, +145, +39, +237, +31, +80, +134, +129, +117, +36, +233, +25, +0, +192, +105, +153, +250, +126, +6, +80, +109, +44, +255, +70, +93, +95, +163, +22, +243, +30, +61, +114, +1, +172, +64, +218, +113, +36, +139, +41, +192, +134, +57, +178, +117, +20, +192, +14, +17, +249, +172, +2, +0, +227, +70, +93, +166, +0, +128, +95, +152, +250, +44, +95, +193, +202, +164, +183, +234, +190, +210, +197, +245, +154, +93, +64, +75, +10, +60, +116, +87, +104, +79, +204, +118, +31, +106, +84, +172, +20, +72, +212, +99, +148, +0, +248, +187, +121, +72, +174, +242, +63, +234, +206, +192, +169, +166, +252, +89, +34, +46, +174, +40, +51, +77, +214, +104, +26, +254, +254, +96, +228, +111, +36, +178, +77, +150, +81, +0, +193, +146, +125, +15, +222, +232, +211, +84, +1, +160, +97, +191, +150, +25, +231, +148, +174, +175, +219, +236, +0, +26, +82, +224, +161, +22, +255, +96, +164, +11, +14, +64, +31, +53, +215, +187, +214, +110, +68, +143, +17, +2, +186, +61, +25, +124, +192, +7, +172, +173, +164, +67, +129, +63, +85, +163, +223, +101, +72, +34, +43, +95, +6, +222, +145, +211, +206, +42, +0, +235, +221, +120, +132, +175, +175, +173, +0, +80, +23, +231, +63, +155, +242, +27, +168, +193, +242, +51, +167, +129, +6, +20, +120, +254, +26, +95, +132, +46, +23, +55, +246, +101, +75, +123, +165, +123, +63, +53, +56, +21, +71, +20, +36, +126, +204, +1, +179, +80, +39, +155, +139, +209, +109, +137, +170, +52, +79, +243, +160, +251, +243, +23, +160, +111, +191, +185, +80, +7, +163, +91, +40, +152, +18, +81, +157, +80, +1, +96, +74, +65, +63, +175, +37, +97, +33, +122, +22, +213, +206, +247, +161, +222, +126, +171, +148, +140, +61, +68, +61, +206, +194, +199, +251, +155, +186, +101, +208, +24, +130, +53, +128, +37, +42, +94, +139, +185, +72, +82, +70, +67, +65, +172, +2, +105, +5, +176, +28, +73, +92, +249, +20, +116, +105, +210, +68, +1, +28, +97, +202, +30, +167, +133, +163, +84, +143, +161, +1, +13, +159, +23, +47, +107, +137, +75, +166, +80, +144, +152, +180, +202, +64, +178, +10, +32, +139, +43, +41, +96, +37, +49, +253, +100, +211, +37, +61, +68, +18, +76, +81, +68, +106, +208, +90, +1, +160, +15, +206, +63, +11, +228, +166, +19, +89, +127, +27, +249, +239, +152, +182, +179, +80, +7, +140, +157, +104, +192, +12, +235, +251, +59, +200, +244, +87, +149, +175, +0, +116, +63, +251, +3, +36, +14, +57, +23, +83, +83, +1, +160, +174, +207, +193, +189, +121, +42, +5, +172, +199, +94, +62, +239, +250, +191, +128, +186, +80, +31, +64, +193, +236, +129, +244, +253, +51, +240, +246, +68, +93, +134, +3, +238, +42, +232, +167, +147, +155, +154, +26, +12, +197, +190, +253, +56, +148, +218, +253, +118, +212, +243, +238, +25, +116, +246, +84, +120, +221, +188, +236, +199, +81, +191, +148, +167, +80, +163, +241, +191, +208, +96, +158, +210, +251, +134, +230, +207, +203, +66, +40, +161, +45, +104, +208, +209, +211, +254, +243, +15, +169, +73, +98, +26, +58, +180, +63, +224, +120, +148, +160, +240, +96, +210, +55, +230, +181, +148, +71, +203, +93, +140, +190, +109, +94, +143, +250, +150, +223, +138, +190, +137, +191, +81, +34, +247, +33, +210, +235, +102, +203, +145, +118, +101, +166, +238, +51, +17, +249, +185, +80, +215, +207, +128, +219, +208, +160, +144, +61, +209, +112, +230, +240, +48, +188, +66, +62, +57, +228, +220, +164, +163, +203, +2, +166, +2, +39, +81, +129, +194, +204, +244, +181, +26, +73, +164, +220, +19, +148, +204, +26, +50, +215, +249, +77, +190, +204, +146, +141, +216, +232, +176, +50, +5, +240, +21, +146, +27, +2, +34, +44, +52, +17, +249, +42, +10, +248, +70, +34, +177, +29, +94, +190, +181, +2, +160, +163, +155, +154, +250, +12, +197, +227, +72, +59, +185, +89, +204, +0, +182, +40, +144, +221, +39, +71, +14, +212, +215, +101, +32, +28, +62, +35, +223, +244, +121, +217, +221, +255, +30, +19, +81, +18, +150, +149, +208, +37, +199, +21, +52, +177, +59, +228, +253, +128, +168, +239, +184, +173, +27, +112, +82, +25, +10, +144, +222, +90, +154, +80, +161, +253, +102, +166, +253, +109, +100, +44, +185, +192, +15, +76, +253, +193, +37, +125, +125, +8, +248, +61, +137, +15, +118, +192, +75, +228, +236, +2, +100, +228, +23, +36, +77, +180, +81, +202, +59, +72, +92, +1, +44, +74, +98, +157, +158, +110, +234, +203, +20, +128, +101, +182, +121, +145, +10, +196, +169, +164, +21, +192, +177, +168, +162, +221, +21, +141, +75, +183, +156, +251, +223, +206, +145, +239, +66, +1, +116, +114, +83, +83, +147, +161, +152, +244, +91, +248, +44, +212, +130, +255, +69, +146, +96, +160, +199, +136, +71, +172, +206, +77, +18, +248, +246, +36, +106, +252, +123, +43, +74, +178, +26, +240, +197, +170, +227, +30, +81, +20, +253, +128, +232, +54, +82, +192, +141, +57, +242, +157, +122, +178, +81, +95, +1, +156, +100, +218, +127, +54, +82, +191, +12, +202, +86, +115, +36, +21, +67, +35, +81, +123, +194, +142, +164, +103, +22, +207, +83, +18, +37, +135, +102, +33, +10, +168, +202, +176, +51, +160, +0, +124, +185, +165, +234, +206, +189, +126, +164, +21, +64, +22, +133, +92, +133, +94, +222, +42, +128, +108, +64, +138, +141, +18, +188, +35, +71, +190, +147, +37, +192, +112, +3, +93, +114, +60, +228, +199, +245, +42, +179, +145, +175, +179, +75, +184, +1, +226, +89, +116, +214, +185, +156, +255, +91, +210, +148, +91, +66, +221, +223, +148, +28, +191, +205, +242, +161, +177, +108, +172, +179, +178, +31, +48, +104, +195, +153, +196, +35, +146, +236, +13, +252, +28, +25, +79, +54, +134, +94, +1, +92, +111, +218, +71, +45, +237, +37, +242, +239, +247, +63, +248, +65, +100, +214, +125, +254, +38, +177, +215, +167, +200, +152, +105, +103, +34, +119, +81, +133, +132, +81, +242, +21, +128, +75, +139, +113, +40, +0, +0, +32, +0, +73, +68, +65, +84, +175, +251, +27, +105, +84, +81, +0, +151, +147, +14, +203, +46, +84, +122, +20, +43, +0, +203, +241, +240, +68, +142, +124, +87, +54, +128, +54, +107, +241, +218, +178, +232, +246, +109, +21, +12, +44, +59, +189, +252, +92, +232, +114, +249, +114, +127, +188, +153, +25, +185, +220, +109, +87, +90, +44, +31, +218, +200, +90, +212, +33, +177, +120, +210, +200, +148, +25, +3, +23, +17, +145, +40, +251, +201, +16, +194, +78, +115, +159, +105, +32, +191, +156, +136, +124, +199, +255, +29, +98, +43, +156, +115, +136, +200, +253, +166, +40, +122, +113, +81, +35, +105, +208, +248, +211, +69, +100, +7, +231, +220, +43, +13, +198, +146, +197, +222, +34, +50, +181, +70, +251, +171, +69, +100, +67, +81, +151, +235, +128, +159, +81, +49, +135, +66, +4, +111, +52, +159, +31, +107, +216, +71, +41, +80, +255, +136, +11, +69, +228, +251, +34, +242, +110, +17, +89, +64, +68, +94, +39, +122, +46, +151, +83, +188, +22, +111, +42, +107, +175, +201, +52, +17, +153, +148, +243, +71, +142, +252, +113, +34, +114, +188, +136, +124, +84, +68, +94, +17, +145, +243, +252, +56, +10, +129, +218, +52, +66, +66, +154, +167, +68, +100, +45, +17, +121, +155, +136, +76, +240, +101, +203, +75, +218, +61, +191, +19, +217, +44, +42, +109, +237, +121, +212, +181, +44, +110, +7, +28, +239, +156, +251, +91, +77, +185, +166, +176, +202, +236, +85, +226, +6, +224, +97, +73, +223, +192, +34, +34, +127, +118, +206, +101, +249, +3, +207, +19, +145, +199, +69, +100, +41, +17, +249, +36, +106, +181, +63, +87, +52, +126, +97, +117, +17, +217, +57, +116, +41, +34, +215, +102, +15, +142, +146, +69, +76, +16, +145, +192, +33, +127, +165, +136, +188, +147, +56, +11, +235, +157, +206, +185, +137, +229, +167, +228, +79, +198, +185, +123, +208, +236, +69, +227, +43, +138, +28, +227, +156, +123, +25, +93, +126, +108, +43, +34, +31, +17, +189, +209, +127, +38, +34, +149, +189, +211, +252, +57, +45, +47, +34, +191, +50, +197, +165, +108, +195, +34, +114, +3, +228, +61, +47, +133, +248, +154, +136, +172, +227, +63, +255, +81, +68, +126, +39, +234, +215, +63, +94, +68, +94, +47, +170, +196, +206, +119, +206, +77, +235, +80, +246, +37, +243, +249, +54, +231, +92, +105, +248, +115, +0, +74, +49, +182, +135, +255, +122, +131, +136, +172, +233, +156, +155, +6, +188, +71, +68, +62, +81, +38, +46, +34, +43, +249, +207, +147, +157, +115, +79, +248, +62, +127, +46, +201, +189, +150, +183, +109, +221, +70, +54, +167, +199, +98, +27, +128, +35, +241, +118, +154, +201, +16, +120, +178, +69, +250, +107, +179, +4, +176, +233, +191, +30, +102, +16, +209, +24, +109, +212, +114, +159, +165, +251, +202, +34, +207, +8, +182, +118, +137, +156, +69, +231, +20, +96, +228, +123, +2, +174, +128, +174, +15, +3, +162, +75, +1, +170, +237, +2, +220, +76, +206, +212, +146, +242, +109, +100, +139, +129, +37, +0, +237, +214, +226, +109, +100, +231, +38, +113, +212, +154, +9, +188, +63, +83, +191, +15, +57, +206, +60, +164, +109, +35, +71, +153, +242, +53, +76, +121, +209, +18, +160, +205, +242, +161, +177, +172, +69, +213, +25, +192, +7, +69, +36, +120, +198, +221, +230, +156, +155, +94, +210, +254, +24, +17, +217, +79, +68, +222, +46, +34, +7, +139, +72, +52, +140, +177, +99, +220, +37, +250, +166, +22, +17, +249, +144, +255, +46, +162, +211, +163, +113, +162, +26, +177, +144, +114, +219, +57, +119, +19, +26, +162, +252, +5, +17, +217, +76, +244, +237, +183, +144, +232, +20, +240, +122, +17, +57, +206, +57, +247, +151, +28, +241, +81, +233, +97, +231, +156, +187, +27, +13, +35, +13, +121, +243, +126, +6, +92, +230, +156, +123, +170, +102, +87, +231, +136, +200, +246, +21, +151, +52, +135, +137, +72, +150, +166, +123, +17, +17, +57, +182, +64, +102, +105, +17, +9, +182, +143, +229, +69, +100, +38, +241, +89, +196, +155, +187, +148, +117, +206, +205, +4, +126, +41, +58, +131, +152, +75, +68, +46, +64, +149, +252, +3, +162, +203, +135, +221, +68, +100, +119, +224, +3, +206, +185, +236, +50, +236, +113, +243, +121, +107, +224, +47, +34, +178, +160, +232, +50, +36, +160, +104, +153, +125, +156, +36, +51, +136, +71, +68, +228, +10, +209, +251, +168, +108, +246, +208, +86, +118, +16, +228, +111, +3, +206, +135, +238, +195, +7, +236, +155, +35, +223, +202, +147, +45, +210, +95, +221, +25, +192, +198, +166, +253, +191, +25, +204, +224, +107, +181, +114, +41, +75, +203, +88, +3, +197, +193, +64, +115, +147, +38, +98, +25, +216, +21, +32, +190, +13, +120, +176, +41, +187, +159, +130, +32, +153, +188, +251, +199, +212, +23, +26, +1, +51, +247, +199, +84, +212, +7, +32, +246, +55, +144, +223, +175, +141, +172, +151, +159, +143, +124, +63, +0, +128, +227, +115, +228, +28, +250, +6, +206, +98, +134, +249, +28, +181, +7, +144, +78, +106, +114, +61, +126, +155, +49, +115, +46, +209, +183, +120, +27, +217, +44, +242, +102, +0, +159, +68, +215, +174, +75, +139, +200, +103, +68, +36, +228, +2, +184, +81, +84, +243, +148, +97, +134, +136, +236, +41, +106, +140, +154, +79, +68, +126, +46, +34, +181, +104, +162, +27, +224, +2, +209, +248, +239, +181, +68, +100, +5, +17, +185, +25, +205, +133, +246, +168, +136, +44, +33, +34, +91, +14, +241, +241, +71, +20, +206, +185, +189, +68, +36, +234, +106, +236, +156, +155, +41, +201, +236, +168, +10, +46, +115, +206, +157, +41, +162, +138, +83, +68, +54, +17, +125, +123, +30, +32, +34, +133, +73, +46, +91, +160, +241, +90, +188, +165, +172, +56, +231, +166, +2, +159, +16, +145, +207, +139, +200, +103, +69, +228, +93, +34, +50, +83, +68, +110, +23, +157, +245, +157, +156, +35, +7, +234, +255, +63, +94, +244, +254, +90, +74, +68, +110, +17, +157, +77, +252, +65, +212, +238, +242, +126, +96, +30, +231, +220, +140, +140, +184, +181, +13, +93, +108, +108, +19, +85, +102, +146, +109, +100, +227, +160, +124, +13, +119, +53, +197, +73, +30, +91, +121, +178, +69, +250, +171, +53, +3, +240, +50, +75, +163, +142, +36, +69, +120, +133, +170, +20, +201, +115, +16, +200, +217, +6, +36, +157, +91, +238, +21, +96, +217, +28, +249, +182, +51, +128, +54, +107, +241, +198, +178, +35, +5, +210, +190, +2, +247, +0, +31, +1, +62, +129, +58, +177, +5, +252, +174, +107, +217, +162, +1, +21, +5, +3, +125, +150, +242, +36, +158, +173, +60, +217, +34, +253, +213, +86, +0, +94, +110, +62, +224, +243, +232, +178, +229, +41, +212, +29, +247, +9, +116, +170, +118, +24, +61, +211, +78, +20, +20, +251, +1, +216, +236, +50, +81, +167, +34, +186, +241, +4, +252, +174, +105, +243, +52, +234, +202, +189, +133, +25, +219, +45, +228, +112, +72, +182, +145, +29, +9, +208, +110, +249, +208, +88, +118, +40, +79, +168, +149, +39, +219, +88, +4, +234, +160, +115, +150, +63, +199, +185, +125, +217, +107, +169, +150, +78, +186, +113, +20, +216, +80, +128, +98, +5, +176, +16, +233, +4, +170, +107, +69, +228, +187, +80, +0, +141, +214, +226, +109, +101, +71, +10, +254, +186, +254, +16, +181, +175, +76, +65, +99, +109, +214, +66, +221, +138, +193, +164, +161, +239, +82, +118, +168, +78, +166, +149, +39, +219, +88, +3, +105, +131, +11, +104, +240, +202, +1, +104, +90, +168, +211, +42, +200, +55, +138, +2, +243, +178, +173, +24, +108, +70, +51, +80, +111, +190, +125, +209, +165, +220, +43, +168, +55, +227, +213, +228, +120, +226, +117, +37, +219, +163, +37, +74, +20, +192, +242, +164, +51, +183, +204, +14, +10, +96, +89, +52, +174, +224, +73, +210, +184, +149, +106, +25, +117, +26, +69, +129, +25, +249, +70, +12, +54, +61, +218, +1, +157, +126, +191, +137, +26, +137, +79, +231, +8, +20, +41, +0, +95, +127, +248, +236, +164, +0, +2, +80, +103, +12, +155, +67, +110, +22, +53, +24, +131, +90, +30, +187, +54, +131, +77, +143, +118, +32, +73, +148, +187, +246, +72, +143, +101, +200, +65, +77, +82, +133, +145, +128, +159, +242, +61, +228, +103, +24, +151, +1, +171, +153, +186, +229, +209, +236, +46, +185, +17, +121, +180, +139, +198, +90, +1, +53, +110, +78, +32, +157, +94, +234, +9, +242, +61, +230, +108, +78, +251, +95, +3, +123, +160, +193, +43, +83, +209, +176, +211, +239, +210, +132, +208, +161, +71, +231, +64, +103, +121, +199, +145, +164, +27, +123, +196, +207, +218, +174, +28, +233, +177, +13, +57, +168, +73, +170, +48, +18, +32, +189, +83, +16, +48, +5, +141, +229, +94, +132, +196, +57, +38, +202, +15, +79, +7, +17, +85, +24, +146, +16, +224, +66, +35, +255, +229, +156, +246, +86, +1, +100, +147, +106, +6, +20, +198, +144, +231, +220, +152, +191, +1, +98, +94, +114, +65, +102, +81, +211, +127, +235, +27, +152, +49, +240, +114, +104, +3, +52, +4, +222, +166, +176, +183, +120, +10, +120, +119, +129, +236, +146, +5, +247, +21, +192, +115, +21, +142, +191, +24, +240, +23, +212, +205, +247, +111, +84, +164, +161, +51, +242, +171, +163, +47, +152, +127, +162, +182, +144, +74, +217, +158, +109, +7, +181, +72, +21, +70, +2, +36, +57, +6, +175, +64, +45, +233, +87, +228, +92, +240, +1, +70, +28, +90, +146, +57, +0, +75, +160, +10, +230, +97, +84, +233, +220, +137, +146, +136, +4, +92, +150, +35, +103, +21, +0, +190, +143, +173, +72, +19, +129, +222, +94, +112, +220, +162, +27, +115, +18, +176, +82, +142, +92, +103, +10, +128, +142, +94, +14, +164, +125, +54, +6, +148, +45, +9, +71, +99, +214, +137, +38, +212, +135, +49, +188, +20, +169, +179, +125, +215, +118, +144, +33, +241, +100, +5, +248, +21, +176, +53, +233, +108, +193, +55, +145, +147, +45, +24, +141, +41, +41, +66, +21, +5, +240, +67, +148, +201, +202, +161, +92, +23, +63, +41, +147, +241, +114, +227, +208, +116, +239, +89, +212, +83, +0, +99, +1, +232, +67, +247, +44, +126, +253, +139, +110, +165, +29, +69, +218, +231, +224, +76, +226, +252, +5, +141, +201, +28, +80, +195, +221, +127, +75, +126, +228, +103, +115, +100, +173, +2, +184, +58, +83, +23, +242, +217, +231, +250, +219, +51, +120, +99, +110, +131, +102, +197, +13, +184, +149, +200, +141, +73, +183, +10, +160, +147, +151, +3, +163, +84, +1, +144, +118, +27, +191, +192, +151, +173, +239, +191, +219, +224, +178, +247, +230, +200, +219, +153, +233, +145, +40, +169, +140, +253, +43, +221, +230, +5, +142, +6, +78, +244, +159, +127, +11, +20, +197, +81, +88, +185, +19, +205, +177, +167, +162, +47, +180, +125, +169, +74, +103, +71, +187, +53, +113, +235, +4, +9, +232, +91, +253, +14, +224, +212, +170, +50, +145, +62, +150, +70, +243, +24, +174, +92, +210, +174, +81, +68, +21, +233, +116, +216, +215, +162, +198, +184, +247, +163, +121, +12, +45, +9, +71, +140, +70, +202, +42, +128, +139, +51, +117, +215, +154, +186, +88, +18, +200, +129, +27, +211, +212, +217, +173, +214, +15, +70, +100, +59, +93, +2, +116, +1, +70, +175, +2, +248, +162, +145, +253, +130, +47, +187, +28, +85, +190, +118, +217, +184, +103, +142, +188, +109, +179, +98, +172, +77, +133, +49, +44, +137, +230, +169, +152, +132, +50, +75, +87, +33, +228, +181, +209, +137, +247, +81, +55, +97, +46, +237, +24, +74, +58, +73, +144, +64, +178, +191, +61, +16, +115, +223, +53, +72, +83, +119, +61, +140, +38, +89, +180, +169, +152, +243, +20, +192, +173, +166, +205, +178, +153, +58, +27, +56, +21, +123, +136, +171, +42, +128, +129, +155, +150, +200, +141, +153, +83, +55, +176, +116, +33, +163, +0, +128, +47, +163, +54, +132, +41, +254, +124, +182, +203, +202, +68, +250, +168, +109, +123, +40, +233, +111, +184, +20, +64, +192, +84, +212, +79, +227, +20, +140, +177, +56, +34, +123, +152, +145, +217, +26, +117, +181, +5, +125, +153, +109, +111, +234, +162, +220, +146, +164, +95, +16, +149, +152, +121, +186, +0, +106, +51, +8, +120, +127, +185, +132, +9, +85, +164, +61, +203, +200, +100, +209, +144, +196, +231, +69, +228, +26, +95, +22, +146, +28, +62, +32, +73, +120, +238, +168, +0, +131, +100, +14, +111, +117, +206, +109, +46, +105, +22, +157, +60, +4, +79, +191, +23, +156, +115, +15, +102, +234, +130, +177, +230, +153, +72, +248, +104, +91, +44, +102, +62, +103, +195, +121, +39, +153, +207, +101, +179, +181, +53, +68, +228, +135, +34, +178, +172, +104, +176, +214, +202, +34, +114, +26, +5, +14, +51, +232, +108, +234, +38, +209, +128, +163, +101, +69, +100, +94, +209, +96, +177, +221, +68, +100, +34, +57, +182, +7, +35, +191, +13, +250, +6, +13, +121, +26, +246, +41, +25, +227, +80, +96, +94, +17, +89, +70, +68, +118, +16, +145, +235, +129, +93, +115, +218, +217, +229, +219, +235, +68, +228, +80, +17, +185, +83, +148, +104, +196, +50, +8, +189, +152, +35, +31, +88, +167, +103, +136, +200, +201, +232, +91, +124, +50, +106, +55, +24, +224, +171, +204, +130, +6, +179, +112, +116, +214, +189, +158, +255, +250, +111, +17, +89, +15, +77, +78, +50, +13, +93, +174, +30, +74, +209, +238, +18, +29, +16, +28, +118, +1, +134, +105, +6, +64, +11, +50, +7, +224, +58, +211, +102, +121, +83, +190, +2, +201, +50, +226, +172, +28, +217, +54, +51, +128, +253, +77, +253, +94, +153, +186, +47, +153, +186, +178, +25, +0, +232, +218, +112, +107, +210, +244, +235, +79, +18, +89, +182, +120, +249, +70, +182, +7, +47, +27, +115, +7, +135, +180, +173, +102, +40, +103, +0, +155, +163, +185, +27, +63, +5, +252, +200, +28, +119, +50, +230, +94, +55, +178, +31, +52, +178, +193, +191, +101, +123, +95, +103, +119, +122, +162, +92, +131, +228, +27, +163, +3, +114, +89, +169, +105, +56, +11, +71, +239, +189, +128, +236, +82, +54, +224, +183, +121, +199, +13, +157, +180, +98, +25, +161, +25, +41, +227, +126, +37, +23, +43, +32, +75, +225, +213, +10, +180, +139, +198, +178, +211, +237, +127, +251, +107, +182, +11, +137, +17, +111, +22, +17, +246, +25, +47, +219, +70, +1, +216, +37, +213, +57, +153, +186, +194, +27, +147, +180, +2, +184, +53, +83, +119, +142, +169, +91, +39, +34, +219, +198, +246, +48, +47, +105, +111, +201, +159, +163, +202, +195, +230, +91, +132, +161, +85, +0, +175, +205, +212, +89, +138, +248, +129, +44, +194, +232, +115, +96, +29, +219, +94, +241, +99, +182, +57, +35, +110, +39, +95, +225, +109, +230, +219, +158, +9, +172, +3, +188, +11, +189, +103, +66, +84, +229, +100, +96, +177, +136, +92, +227, +157, +41, +52, +142, +36, +96, +6, +186, +139, +176, +9, +234, +128, +55, +213, +212, +229, +110, +95, +54, +94, +19, +123, +217, +70, +201, +21, +232, +64, +1, +160, +179, +150, +223, +248, +49, +135, +41, +211, +33, +20, +68, +127, +209, +46, +26, +107, +110, +116, +138, +150, +135, +67, +11, +142, +219, +70, +1, +204, +229, +207, +45, +224, +23, +232, +91, +188, +244, +198, +164, +192, +8, +136, +218, +3, +2, +62, +31, +145, +109, +99, +123, +88, +207, +212, +159, +111, +202, +29, +137, +194, +132, +225, +85, +0, +246, +158, +219, +35, +43, +235, +219, +172, +134, +190, +192, +98, +120, +134, +146, +52, +115, +57, +125, +254, +204, +244, +177, +89, +164, +190, +205, +206, +212, +71, +76, +155, +227, +51, +117, +54, +82, +242, +75, +182, +206, +218, +0, +218, +172, +137, +69, +6, +73, +25, +183, +18, +145, +125, +69, +25, +122, +231, +22, +165, +162, +138, +77, +47, +111, +18, +93, +143, +134, +191, +176, +5, +246, +88, +166, +252, +222, +216, +65, +253, +15, +113, +179, +232, +90, +244, +141, +162, +164, +8, +43, +138, +200, +145, +34, +114, +113, +206, +49, +3, +211, +239, +198, +34, +242, +35, +81, +27, +197, +84, +17, +185, +78, +68, +214, +149, +100, +125, +253, +126, +34, +219, +92, +158, +96, +99, +51, +209, +245, +240, +245, +162, +107, +193, +231, +68, +228, +82, +17, +217, +216, +57, +247, +173, +216, +49, +219, +194, +57, +55, +75, +68, +118, +244, +199, +18, +81, +210, +149, +51, +68, +36, +236, +241, +62, +43, +34, +59, +250, +115, +171, +3, +203, +162, +28, +155, +98, +182, +177, +61, +88, +242, +138, +87, +21, +170, +31, +227, +192, +131, +59, +148, +0, +22, +0, +214, +21, +37, +54, +9, +184, +33, +214, +214, +57, +119, +147, +136, +92, +38, +122, +77, +255, +35, +202, +24, +252, +152, +168, +77, +108, +53, +231, +220, +173, +49, +185, +18, +252, +199, +124, +30, +136, +23, +241, +191, +239, +131, +162, +207, +209, +25, +94, +209, +204, +20, +189, +199, +2, +242, +118, +52, +236, +111, +56, +43, +83, +103, +9, +104, +227, +113, +42, +180, +91, +19, +55, +38, +101, +140, +244, +85, +203, +6, +64, +122, +202, +126, +44, +58, +85, +179, +214, +208, +220, +183, +241, +88, +5, +240, +54, +212, +253, +248, +81, +116, +61, +251, +40, +58, +77, +204, +221, +235, +165, +120, +6, +96, +215, +157, +177, +25, +64, +27, +219, +131, +253, +253, +63, +157, +169, +179, +118, +133, +216, +12, +224, +241, +188, +122, +52, +236, +58, +224, +201, +136, +108, +25, +49, +12, +64, +148, +233, +199, +203, +255, +47, +186, +148, +27, +184, +30, +69, +64, +119, +74, +94, +242, +127, +231, +102, +234, +78, +49, +199, +142, +114, +247, +209, +124, +103, +106, +30, +146, +12, +78, +255, +34, +253, +12, +218, +25, +64, +220, +33, +136, +118, +107, +226, +86, +201, +21, +50, +125, +85, +86, +0, +164, +61, +174, +206, +53, +229, +243, +161, +91, +84, +160, +219, +62, +209, +181, +218, +156, +4, +138, +109, +0, +118, +61, +190, +110, +68, +182, +141, +237, +97, +111, +83, +255, +249, +76, +93, +153, +2, +248, +135, +169, +223, +58, +83, +183, +181, +169, +187, +34, +34, +91, +164, +0, +38, +161, +91, +125, +185, +78, +76, +104, +106, +178, +247, +80, +66, +132, +19, +145, +115, +164, +237, +7, +199, +162, +198, +199, +239, +144, +216, +212, +38, +17, +95, +226, +181, +226, +250, +35, +109, +219, +248, +163, +191, +70, +135, +147, +216, +0, +166, +144, +231, +82, +76, +187, +53, +113, +43, +82, +198, +76, +95, +117, +20, +192, +118, +230, +184, +7, +102, +234, +206, +50, +117, +217, +188, +0, +115, +28, +24, +220, +5, +248, +45, +106, +29, +255, +38, +233, +27, +51, +230, +187, +208, +198, +246, +176, +150, +105, +115, +86, +166, +238, +30, +83, +23, +83, +0, +187, +154, +250, +151, +208, +27, +252, +115, +40, +67, +145, +205, +127, +184, +115, +68, +214, +42, +128, +77, +208, +93, +128, +245, +128, +119, +51, +196, +193, +86, +232, +203, +212, +230, +83, +180, +152, +14, +108, +158, +35, +215, +150, +102, +124, +65, +210, +59, +84, +22, +51, +201, +223, +246, +124, +181, +131, +70, +44, +35, +164, +53, +87, +116, +77, +85, +21, +168, +241, +238, +187, +84, +72, +66, +10, +108, +106, +142, +251, +211, +76, +221, +4, +83, +55, +199, +135, +202, +146, +86, +0, +86, +169, +91, +228, +250, +139, +163, +179, +173, +103, +115, +228, +114, +141, +98, +232, +212, +244, +49, +211, +246, +71, +232, +27, +241, +228, +76, +31, +49, +5, +224, +72, +187, +182, +198, +112, +2, +113, +197, +211, +42, +22, +160, +45, +208, +92, +148, +199, +161, +207, +210, +84, +244, +197, +118, +22, +144, +75, +88, +74, +7, +92, +127, +168, +18, +56, +12, +77, +75, +55, +21, +245, +37, +56, +7, +88, +179, +251, +179, +76, +14, +58, +34, +164, +140, +168, +187, +100, +216, +211, +125, +17, +213, +242, +11, +160, +110, +192, +129, +44, +131, +216, +69, +39, +173, +32, +2, +102, +162, +111, +193, +43, +252, +152, +163, +211, +63, +90, +134, +244, +50, +2, +140, +62, +164, +21, +192, +209, +126, +140, +143, +248, +49, +223, +65, +53, +7, +149, +218, +182, +7, +47, +103, +103, +106, +22, +86, +17, +21, +121, +153, +110, +13, +92, +228, +127, +155, +25, +232, +108, +242, +34, +50, +212, +101, +25, +153, +17, +85, +0, +77, +192, +104, +228, +250, +171, +10, +70, +136, +148, +145, +120, +228, +83, +22, +43, +68, +228, +98, +10, +32, +139, +75, +137, +207, +120, +186, +8, +233, +237, +132, +209, +135, +49, +18, +150, +139, +186, +209, +222, +130, +42, +156, +135, +208, +165, +199, +177, +102, +236, +195, +230, +50, +59, +154, +193, +104, +227, +250, +171, +10, +70, +136, +148, +17, +157, +98, +126, +151, +196, +129, +98, +22, +106, +0, +249, +167, +255, +62, +157, +72, +134, +94, +210, +10, +224, +167, +104, +56, +241, +231, +208, +41, +170, +125, +168, +7, +12, +151, +180, +12, +233, +53, +253, +180, +98, +244, +97, +12, +112, +54, +140, +69, +160, +78, +93, +1, +39, +155, +114, +107, +147, +56, +97, +36, +199, +56, +42, +193, +8, +146, +50, +250, +99, +191, +5, +120, +157, +127, +64, +131, +229, +243, +234, +156, +246, +86, +1, +108, +158, +169, +251, +186, +169, +251, +89, +68, +182, +85, +72, +111, +87, +96, +12, +112, +54, +140, +69, +160, +70, +207, +176, +67, +49, +19, +53, +28, +206, +79, +178, +213, +253, +50, +179, +155, +97, +25, +216, +139, +106, +168, +148, +114, +168, +230, +177, +231, +1, +62, +141, +206, +32, +30, +68, +223, +138, +147, +252, +247, +29, +169, +177, +141, +135, +238, +15, +255, +217, +140, +55, +47, +29, +84, +145, +2, +216, +201, +212, +13, +76, +207, +105, +23, +210, +219, +216, +187, +173, +199, +240, +129, +180, +7, +227, +57, +192, +215, +204, +247, +35, +106, +244, +243, +122, +212, +29, +120, +56, +163, +2, +29, +240, +45, +63, +214, +41, +192, +78, +85, +132, +170, +42, +128, +95, +118, +60, +216, +121, +73, +152, +125, +242, +112, +98, +73, +31, +75, +249, +241, +255, +20, +53, +76, +5, +92, +72, +190, +191, +246, +128, +2, +64, +21, +209, +123, +72, +194, +125, +103, +18, +55, +32, +182, +113, +231, +109, +227, +222, +218, +137, +242, +160, +201, +13, +162, +114, +173, +249, +30, +218, +2, +165, +202, +170, +252, +48, +161, +51, +195, +131, +208, +153, +210, +20, +116, +251, +240, +218, +42, +231, +140, +230, +108, +8, +8, +203, +194, +71, +129, +215, +84, +60, +246, +2, +36, +254, +40, +183, +85, +29, +115, +27, +160, +54, +132, +16, +219, +113, +39, +106, +143, +3, +181, +43, +20, +70, +3, +46, +131, +90, +209, +99, +127, +118, +203, +38, +55, +176, +167, +225, +128, +173, +226, +185, +211, +223, +96, +155, +161, +137, +41, +237, +94, +234, +64, +50, +10, +211, +135, +213, +214, +1, +231, +21, +221, +40, +148, +27, +1, +159, +35, +103, +233, +194, +24, +86, +0, +52, +188, +65, +104, +200, +247, +64, +247, +92, +132, +47, +81, +49, +42, +21, +85, +116, +246, +33, +206, +162, +208, +104, +138, +6, +241, +100, +183, +76, +119, +171, +49, +214, +37, +72, +24, +163, +95, +198, +120, +231, +21, +200, +180, +218, +33, +2, +118, +71, +151, +224, +19, +81, +103, +166, +149, +80, +131, +226, +21, +121, +191, +81, +89, +135, +227, +80, +2, +8, +128, +235, +203, +37, +106, +247, +111, +3, +36, +54, +200, +212, +125, +142, +196, +173, +242, +192, +130, +62, +214, +245, +55, +231, +127, +80, +175, +182, +210, +19, +165, +92, +1, +76, +71, +247, +160, +7, +126, +0, +198, +182, +2, +104, +116, +131, +160, +15, +211, +69, +126, +12, +27, +251, +178, +165, +209, +152, +243, +251, +201, +207, +219, +55, +146, +10, +224, +147, +230, +216, +147, +208, +160, +167, +131, +73, +118, +95, +102, +80, +144, +239, +210, +247, +113, +147, +233, +99, +26, +53, +243, +1, +160, +4, +34, +199, +23, +93, +219, +136, +204, +232, +201, +249, +128, +90, +199, +3, +10, +89, +99, +80, +141, +121, +26, +170, +193, +166, +163, +123, +226, +191, +163, +128, +22, +9, +205, +166, +19, +112, +57, +21, +153, +76, +218, +130, +180, +2, +216, +5, +125, +168, +23, +71, +227, +170, +79, +48, +117, +63, +141, +200, +142, +89, +5, +48, +220, +160, +3, +5, +128, +174, +163, +143, +65, +149, +13, +168, +129, +249, +92, +74, +102, +163, +192, +17, +230, +216, +95, +55, +229, +251, +249, +223, +233, +90, +224, +3, +5, +242, +31, +103, +16, +67, +149, +29, +57, +123, +236, +90, +59, +68, +153, +123, +242, +178, +76, +157, +189, +39, +171, +219, +34, +80, +173, +127, +167, +23, +124, +144, +98, +223, +233, +247, +146, +118, +207, +180, +120, +17, +88, +53, +71, +110, +49, +223, +183, +197, +35, +168, +171, +234, +166, +69, +199, +108, +3, +210, +10, +32, +155, +11, +239, +181, +36, +83, +183, +7, +34, +178, +99, +78, +1, +140, +160, +108, +43, +5, +128, +102, +225, +121, +132, +56, +166, +81, +28, +38, +110, +125, +83, +6, +152, +161, +75, +142, +59, +55, +234, +220, +133, +63, +191, +224, +205, +248, +50, +145, +196, +55, +70, +238, +23, +84, +195, +87, +235, +140, +167, +194, +120, +27, +41, +128, +178, +53, +201, +230, +146, +132, +115, +30, +19, +201, +113, +110, +241, +61, +17, +9, +198, +145, +83, +68, +195, +129, +131, +219, +226, +107, +125, +125, +12, +47, +73, +58, +92, +81, +68, +169, +166, +118, +21, +145, +115, +68, +228, +94, +96, +163, +146, +113, +118, +141, +197, +69, +36, +24, +15, +163, +225, +196, +61, +26, +193, +161, +83, +240, +144, +200, +229, +22, +202, +83, +181, +127, +93, +244, +126, +16, +17, +249, +147, +136, +108, +32, +34, +135, +136, +134, +188, +142, +19, +145, +159, +146, +111, +187, +152, +98, +62, +215, +181, +194, +239, +38, +34, +129, +60, +227, +4, +73, +66, +136, +23, +20, +145, +111, +215, +236, +171, +22, +104, +65, +204, +219, +245, +64, +130, +230, +120, +169, +236, +224, +36, +86, +210, +167, +73, +50, +229, +206, +67, +194, +165, +30, +157, +150, +102, +180, +244, +129, +192, +87, +208, +93, +1, +203, +70, +52, +131, +238, +141, +143, +118, +6, +240, +19, +18, +202, +230, +175, +160, +44, +63, +1, +81, +106, +175, +22, +199, +29, +139, +111, +241, +174, +102, +0, +54, +133, +154, +197, +0, +43, +143, +145, +183, +193, +45, +139, +155, +242, +179, +77, +249, +0, +251, +45, +131, +198, +59, +139, +194, +252, +139, +232, +12, +48, +24, +226, +94, +70, +109, +29, +14, +184, +217, +156, +71, +30, +37, +248, +10, +192, +218, +21, +254, +150, +201, +145, +111, +74, +9, +214, +237, +18, +0, +245, +50, +11, +56, +166, +66, +251, +16, +11, +240, +80, +166, +60, +56, +79, +60, +147, +35, +103, +183, +220, +230, +49, +229, +203, +160, +30, +125, +1, +3, +177, +219, +109, +78, +154, +106, +174, +192, +79, +211, +144, +214, +57, +15, +140, +205, +135, +184, +43, +5, +0, +186, +163, +180, +3, +105, +62, +193, +71, +201, +121, +139, +147, +78, +59, +254, +126, +83, +254, +33, +116, +7, +105, +47, +34, +134, +60, +218, +41, +128, +35, +77, +219, +111, +155, +114, +107, +19, +184, +180, +168, +15, +35, +243, +70, +52, +248, +105, +128, +2, +44, +210, +182, +13, +37, +88, +231, +10, +224, +34, +47, +48, +19, +101, +11, +42, +107, +111, +163, +182, +118, +7, +94, +227, +255, +7, +68, +93, +129, +129, +171, +76, +155, +253, +49, +55, +2, +105, +158, +129, +11, +34, +178, +67, +161, +0, +194, +148, +235, +39, +12, +129, +183, +23, +237, +72, +46, +198, +186, +2, +152, +152, +169, +187, +204, +212, +13, +240, +9, +250, +54, +159, +51, +109, +158, +65, +29, +114, +170, +60, +76, +155, +146, +222, +97, +58, +31, +13, +127, +222, +156, +72, +108, +200, +80, +0, +125, +6, +194, +54, +235, +61, +21, +218, +183, +161, +4, +235, +78, +1, +160, +6, +189, +128, +179, +203, +79, +85, +4, +117, +193, +189, +134, +56, +174, +2, +22, +201, +145, +219, +45, +211, +246, +113, +148, +21, +101, +115, +210, +252, +236, +3, +212, +100, +157, +158, +244, +48, +129, +118, +36, +23, +99, +81, +121, +20, +49, +17, +89, +239, +186, +157, +99, +125, +251, +118, +150, +119, +0, +212, +126, +112, +2, +176, +84, +158, +140, +151, +219, +201, +200, +28, +87, +212, +118, +40, +128, +222, +159, +225, +218, +60, +79, +53, +63, +128, +166, +201, +106, +58, +53, +2, +126, +221, +124, +254, +113, +217, +160, +61, +2, +159, +89, +12, +15, +137, +72, +148, +167, +206, +57, +247, +91, +81, +62, +193, +201, +190, +104, +73, +81, +110, +194, +63, +137, +72, +112, +185, +60, +93, +148, +23, +112, +212, +128, +230, +14, +27, +54, +136, +228, +4, +12, +201, +69, +166, +46, +54, +99, +178, +111, +145, +79, +102, +234, +236, +247, +81, +149, +131, +161, +0, +150, +127, +63, +87, +73, +59, +231, +62, +39, +34, +155, +136, +114, +54, +138, +104, +46, +131, +157, +69, +228, +86, +10, +18, +124, +100, +250, +124, +180, +225, +24, +27, +195, +57, +247, +180, +168, +33, +253, +199, +34, +178, +145, +231, +252, +43, +195, +113, +162, +191, +253, +71, +69, +249, +49, +207, +19, +195, +165, +88, +128, +23, +37, +225, +2, +204, +242, +254, +85, +15, +135, +70, +83, +106, +7, +173, +115, +83, +13, +185, +16, +9, +56, +3, +248, +54, +186, +238, +249, +46, +137, +225, +231, +111, +37, +242, +139, +163, +129, +68, +151, +160, +219, +59, +22, +151, +19, +89, +35, +54, +213, +122, +93, +129, +6, +14, +27, +180, +35, +185, +104, +195, +144, +51, +26, +103, +0, +7, +23, +141, +57, +231, +88, +171, +0, +103, +24, +185, +187, +136, +135, +108, +111, +139, +58, +59, +5, +28, +204, +96, +142, +190, +29, +129, +183, +85, +57, +238, +112, +128, +246, +148, +96, +247, +153, +118, +227, +209, +89, +244, +111, +72, +163, +248, +89, +200, +8, +148, +82, +120, +121, +153, +85, +141, +204, +73, +153, +186, +211, +76, +93, +62, +39, +121, +90, +102, +81, +244, +198, +182, +83, +222, +24, +141, +242, +136, +47, +1, +104, +24, +210, +75, +51, +146, +139, +54, +202, +99, +52, +40, +128, +27, +51, +117, +151, +154, +186, +1, +135, +28, +212, +162, +254, +85, +255, +247, +161, +76, +157, +37, +202, +28, +184, +238, +228, +251, +164, +100, +81, +41, +107, +46, +234, +17, +123, +187, +145, +139, +210, +122, +181, +1, +237, +41, +193, +44, +189, +187, +133, +205, +87, +217, +253, +179, +128, +198, +11, +4, +156, +152, +169, +179, +76, +168, +49, +194, +201, +243, +209, +109, +183, +187, +128, +133, +50, +117, +95, +48, +178, +3, +142, +19, +116, +160, +0, +80, +170, +171, +211, +81, +71, +143, +105, +254, +255, +25, +192, +123, +106, +95, +136, +97, +2, +205, +148, +71, +27, +251, +65, +27, +217, +236, +46, +192, +207, +208, +217, +225, +113, +166, +236, +1, +34, +235, +99, +116, +187, +44, +224, +244, +76, +221, +175, +76, +221, +218, +17, +217, +174, +21, +192, +215, +51, +114, +67, +161, +0, +90, +81, +130, +161, +246, +131, +175, +162, +207, +211, +20, +255, +127, +79, +210, +207, +224, +144, +40, +128, +165, +72, +168, +185, +194, +18, +96, +115, +52, +226, +44, +188, +29, +166, +3, +111, +136, +200, +90, +107, +252, +53, +232, +52, +119, +19, +224, +243, +164, +83, +112, +15, +92, +112, +148, +132, +36, +44, +87, +110, +203, +212, +21, +50, +206, +250, +54, +219, +50, +184, +220, +8, +152, +66, +14, +143, +26, +163, +96, +230, +81, +23, +180, +51, +62, +182, +145, +45, +243, +3, +152, +5, +124, +42, +103, +204, +11, +144, +248, +145, +204, +68, +89, +132, +214, +65, +153, +134, +95, +241, +229, +83, +129, +56, +215, +125, +71, +64, +183, +226, +94, +73, +15, +123, +72, +20, +192, +152, +166, +4, +59, +56, +50, +112, +139, +175, +231, +200, +45, +75, +226, +43, +144, +135, +11, +201, +223, +39, +190, +207, +180, +171, +188, +238, +65, +31, +226, +224, +188, +52, +5, +165, +79, +222, +138, +180, +239, +193, +85, +57, +199, +28, +139, +10, +160, +141, +253, +160, +141, +172, +85, +0, +87, +161, +20, +102, +15, +163, +15, +238, +45, +228, +60, +252, +70, +254, +211, +228, +43, +105, +40, +217, +211, +239, +2, +36, +203, +13, +251, +32, +22, +42, +0, +26, +102, +82, +102, +172, +82, +130, +137, +136, +0, +27, +161, +73, +57, +38, +249, +31, +237, +126, +212, +165, +49, +55, +148, +215, +203, +189, +30, +157, +45, +76, +68, +215, +43, +51, +252, +137, +254, +3, +157, +9, +228, +114, +179, +211, +112, +221, +131, +18, +121, +6, +28, +105, +202, +231, +37, +73, +9, +21, +205, +238, +203, +216, +84, +0, +109, +236, +7, +109, +100, +187, +8, +6, +90, +13, +85, +204, +97, +79, +253, +101, +224, +239, +116, +156, +47, +50, +231, +216, +159, +246, +199, +124, +137, +180, +243, +82, +174, +2, +0, +86, +70, +221, +120, +99, +152, +68, +73, +38, +229, +81, +3, +198, +0, +225, +36, +13, +215, +61, +192, +250, +232, +46, +197, +119, +129, +255, +205, +212, +133, +165, +199, +115, +89, +57, +95, +223, +133, +237, +97, +123, +212, +11, +114, +10, +250, +118, +248, +14, +105, +78, +193, +33, +97, +178, +165, +129, +253, +160, +141, +44, +29, +134, +3, +3, +43, +250, +126, +246, +42, +111, +221, +30, +126, +236, +193, +254, +241, +53, +116, +134, +25, +80, +164, +0, +26, +103, +82, +30, +53, +96, +14, +37, +156, +4, +62, +96, +126, +168, +223, +231, +180, +105, +165, +0, +72, +79, +169, +45, +172, +211, +71, +44, +146, +208, +62, +76, +39, +161, +1, +34, +143, +146, +4, +214, +108, +219, +201, +69, +232, +16, +116, +171, +0, +150, +71, +119, +36, +118, +169, +41, +215, +148, +1, +41, +164, +233, +186, +19, +221, +5, +40, +85, +0, +180, +200, +164, +220, +5, +232, +138, +181, +137, +57, +144, +112, +18, +245, +102, +12, +129, +64, +83, +201, +204, +12, +76, +187, +54, +46, +200, +243, +147, +206, +58, +123, +12, +106, +140, +204, +166, +203, +46, +83, +0, +121, +216, +190, +179, +11, +210, +1, +232, +152, +16, +164, +193, +241, +155, +50, +32, +125, +136, +196, +104, +185, +142, +47, +171, +162, +0, +26, +103, +82, +110, +11, +26, +178, +54, +245, +16, +17, +212, +111, +251, +74, +115, +177, +114, +51, +19, +209, +78, +1, +88, +150, +154, +108, +242, +200, +187, +76, +93, +21, +5, +240, +115, +6, +243, +214, +63, +198, +28, +162, +176, +171, +128, +6, +12, +72, +164, +247, +252, +79, +53, +229, +85, +20, +128, +109, +179, +77, +166, +110, +123, +83, +87, +148, +66, +126, +30, +212, +40, +125, +1, +74, +200, +51, +23, +176, +38, +58, +203, +203, +125, +147, +211, +144, +181, +41, +8, +119, +177, +174, +93, +142, +36, +115, +204, +52, +212, +218, +251, +107, +42, +4, +213, +48, +130, +132, +147, +232, +118, +211, +165, +230, +28, +203, +184, +226, +26, +111, +63, +146, +54, +90, +126, +177, +64, +182, +76, +1, +100, +157, +106, +108, +212, +220, +208, +165, +129, +154, +3, +64, +58, +47, +64, +17, +158, +142, +200, +54, +206, +164, +108, +218, +125, +35, +115, +156, +135, +72, +140, +138, +107, +116, +121, +174, +165, +193, +9, +85, +129, +186, +84, +94, +47, +34, +59, +137, +200, +255, +136, +146, +53, +188, +81, +52, +119, +253, +245, +20, +179, +168, +44, +40, +34, +151, +138, +200, +47, +68, +201, +30, +4, +77, +37, +126, +166, +136, +252, +158, +33, +156, +186, +248, +7, +237, +28, +17, +89, +219, +23, +253, +216, +57, +55, +16, +120, +100, +225, +156, +155, +42, +73, +220, +195, +74, +152, +237, +71, +17, +137, +230, +200, +51, +176, +73, +74, +6, +110, +160, +26, +152, +146, +249, +254, +23, +243, +185, +136, +130, +109, +28, +106, +52, +189, +29, +221, +219, +126, +6, +165, +81, +47, +229, +91, +64, +35, +236, +110, +64, +35, +38, +159, +66, +149, +253, +209, +230, +70, +93, +174, +225, +185, +12, +25, +104, +182, +29, +215, +38, +121, +168, +117, +159, +207, +198, +107, +108, +104, +62, +103, +73, +112, +44, +214, +22, +145, +39, +68, +100, +49, +17, +217, +84, +68, +158, +17, +145, +121, +68, +228, +80, +231, +92, +97, +210, +220, +134, +231, +219, +137, +97, +235, +92, +211, +230, +120, +212, +98, +124, +146, +41, +43, +242, +96, +106, +62, +117, +105, +1, +116, +203, +207, +178, +198, +30, +93, +67, +182, +233, +246, +227, +190, +166, +126, +239, +76, +93, +157, +25, +64, +214, +175, +222, +26, +22, +247, +203, +25, +243, +56, +242, +179, +55, +205, +0, +182, +40, +56, +223, +109, +201, +39, +244, +8, +88, +174, +234, +245, +171, +3, +84, +241, +92, +136, +238, +62, +76, +69, +239, +137, +223, +82, +226, +199, +79, +195, +237, +56, +212, +177, +45, +198, +142, +109, +119, +150, +142, +0, +62, +22, +145, +109, +156, +73, +185, +45, +154, +158, +111, +16, +110, +179, +174, +93, +148, +100, +199, +32, +59, +37, +14, +41, +186, +166, +50, +138, +146, +52, +162, +15, +195, +57, +230, +188, +110, +200, +249, +209, +223, +154, +35, +223, +116, +251, +113, +93, +83, +127, +118, +166, +206, +50, +17, +213, +85, +0, +7, +154, +186, +168, +123, +43, +233, +169, +229, +89, +232, +18, +235, +139, +36, +222, +118, +143, +225, +3, +80, +50, +114, +243, +145, +56, +162, +128, +250, +4, +108, +79, +218, +29, +23, +34, +10, +0, +125, +152, +2, +46, +206, +214, +151, +1, +248, +30, +249, +120, +129, +28, +102, +30, +47, +219, +233, +118, +28, +213, +183, +1, +27, +101, +82, +54, +242, +77, +157, +136, +154, +159, +47, +237, +20, +192, +71, +76, +253, +113, +153, +58, +75, +146, +56, +64, +12, +218, +230, +184, +109, +64, +250, +65, +44, +66, +167, +158, +102, +232, +172, +195, +62, +76, +63, +65, +125, +227, +143, +207, +28, +183, +76, +1, +220, +148, +169, +179, +91, +76, +3, +211, +121, +116, +150, +21, +60, +46, +239, +198, +248, +222, +163, +137, +51, +2, +62, +26, +145, +221, +200, +212, +95, +148, +169, +251, +187, +169, +91, +46, +34, +219, +88, +1, +160, +41, +185, +194, +172, +227, +89, +116, +214, +181, +37, +240, +123, +211, +231, +229, +57, +178, +157, +111, +199, +81, +81, +1, +248, +182, +77, +51, +41, +55, +157, +181, +52, +58, +223, +174, +172, +197, +214, +23, +123, +82, +166, +238, +153, +156, +118, +35, +141, +17, +113, +196, +112, +206, +77, +3, +190, +44, +34, +129, +226, +108, +95, +255, +39, +162, +241, +220, +85, +237, +50, +239, +69, +243, +22, +94, +44, +34, +235, +249, +63, +17, +145, +71, +68, +36, +182, +78, +92, +90, +68, +130, +29, +102, +121, +17, +153, +9, +81, +138, +134, +216, +91, +198, +222, +116, +127, +202, +212, +77, +150, +161, +195, +210, +34, +18, +20, +206, +137, +206, +185, +211, +68, +68, +208, +153, +211, +135, +69, +109, +76, +31, +6, +230, +138, +196, +218, +219, +140, +78, +127, +206, +212, +157, +43, +201, +245, +122, +159, +136, +92, +83, +101, +48, +206, +185, +241, +34, +50, +190, +98, +219, +123, +69, +57, +11, +234, +226, +36, +81, +82, +90, +17, +145, +95, +139, +254, +190, +27, +136, +200, +46, +162, +207, +207, +41, +192, +123, +156, +115, +217, +31, +175, +209, +249, +118, +165, +0, +114, +93, +117, +37, +33, +41, +40, +107, +55, +172, +112, +206, +93, +44, +35, +167, +4, +78, +1, +166, +137, +26, +60, +87, +20, +145, +199, +69, +228, +104, +81, +3, +106, +153, +17, +49, +96, +150, +136, +236, +237, +255, +2, +16, +145, +253, +156, +115, +51, +35, +237, +109, +32, +214, +52, +81, +2, +137, +24, +98, +90, +193, +70, +105, +62, +81, +113, +124, +173, +225, +156, +187, +72, +18, +5, +96, +203, +103, +2, +65, +241, +76, +149, +248, +152, +45, +109, +216, +83, +153, +58, +251, +146, +26, +94, +166, +221, +2, +160, +22, +254, +240, +251, +255, +197, +57, +183, +135, +255, +124, +6, +74, +34, +186, +158, +136, +172, +44, +34, +107, +200, +160, +210, +106, +116, +190, +246, +109, +211, +13, +163, +72, +143, +74, +112, +206, +157, +225, +156, +91, +197, +57, +55, +159, +115, +238, +205, +206, +185, +170, +204, +75, +1, +215, +136, +50, +41, +61, +36, +250, +64, +223, +42, +34, +91, +57, +231, +206, +204, +105, +111, +99, +245, +111, +115, +206, +45, +158, +243, +23, +139, +55, +183, +202, +162, +213, +44, +14, +93, +238, +220, +134, +174, +109, +31, +64, +131, +200, +234, +172, +195, +23, +6, +190, +34, +34, +129, +167, +242, +196, +200, +219, +80, +68, +228, +249, +130, +49, +91, +101, +24, +117, +247, +30, +33, +148, +189, +197, +3, +98, +188, +19, +141, +206, +247, +85, +5, +208, +114, +107, +107, +122, +172, +207, +208, +181, +249, +60, +173, +164, +159, +30, +53, +224, +156, +251, +63, +231, +220, +178, +94, +137, +188, +199, +57, +247, +199, +130, +230, +247, +73, +242, +227, +191, +151, +76, +6, +38, +148, +142, +122, +185, +28, +89, +107, +216, +221, +52, +83, +87, +231, +229, +176, +154, +136, +156, +37, +186, +164, +152, +87, +68, +150, +21, +229, +216, +47, +245, +138, +195, +19, +204, +138, +222, +232, +63, +240, +197, +167, +139, +200, +254, +57, +34, +93, +108, +199, +13, +55, +218, +204, +90, +26, +157, +111, +246, +97, +181, +244, +223, +135, +139, +174, +247, +118, +147, +244, +219, +35, +6, +59, +184, +44, +99, +235, +226, +57, +237, +122, +12, +35, +252, +178, +32, +100, +118, +158, +75, +68, +46, +64, +157, +86, +182, +240, +74, +254, +24, +17, +57, +155, +72, +74, +115, +17, +249, +187, +36, +55, +228, +38, +168, +143, +252, +54, +222, +6, +49, +64, +242, +82, +128, +69, +69, +121, +15, +63, +45, +34, +199, +154, +242, +90, +89, +123, +60, +16, +125, +185, +44, +148, +83, +127, +165, +36, +220, +136, +155, +98, +182, +227, +68, +228, +227, +190, +252, +14, +17, +185, +186, +244, +64, +137, +151, +232, +139, +192, +62, +37, +109, +163, +134, +107, +224, +125, +166, +124, +66, +142, +120, +155, +89, +75, +251, +243, +165, +249, +214, +214, +194, +36, +219, +128, +119, +102, +234, +238, +240, +229, +83, +98, +55, +23, +195, +188, +11, +64, +67, +143, +67, +26, +6, +148, +212, +28, +91, +99, +63, +128, +138, +253, +207, +71, +190, +31, +0, +228, +80, +183, +123, +217, +109, +136, +251, +1, +216, +0, +166, +229, +34, +114, +118, +23, +224, +170, +76, +221, +125, +190, +124, +6, +37, +203, +0, +127, +159, +188, +15, +101, +9, +250, +166, +25, +203, +117, +5, +50, +173, +182, +227, +76, +63, +107, +27, +185, +219, +75, +218, +54, +86, +0, +164, +253, +246, +207, +201, +212, +93, +104, +234, +162, +78, +91, +93, +157, +111, +35, +144, +73, +226, +129, +106, +31, +187, +181, +149, +71, +103, +220, +138, +213, +167, +230, +24, +155, +166, +184, +110, +150, +115, +189, +99, +208, +77, +108, +253, +56, +212, +25, +233, +70, +212, +19, +240, +69, +224, +106, +114, +82, +161, +103, +100, +55, +70, +253, +37, +166, +160, +219, +90, +223, +34, +189, +13, +24, +75, +208, +145, +187, +13, +72, +250, +97, +137, +205, +60, +138, +198, +98, +239, +183, +92, +174, +73, +26, +110, +199, +101, +250, +88, +208, +159, +231, +51, +192, +158, +37, +109, +219, +40, +128, +214, +78, +68, +93, +156, +111, +35, +160, +52, +217, +79, +16, +199, +163, +20, +187, +2, +223, +103, +218, +190, +106, +123, +200, +244, +209, +133, +2, +104, +154, +226, +186, +219, +156, +235, +99, +20, +100, +82, +112, +161, +145, +141, +33, +105, +230, +20, +226, +188, +126, +85, +21, +64, +108, +198, +115, +36, +170, +108, +159, +38, +195, +28, +68, +90, +1, +12, +73, +104, +109, +19, +208, +110, +9, +48, +178, +111, +241, +182, +0, +222, +140, +106, +155, +199, +72, +180, +207, +241, +228, +228, +65, +51, +114, +35, +195, +102, +218, +163, +50, +208, +183, +255, +52, +116, +214, +179, +54, +176, +33, +233, +105, +105, +222, +12, +175, +141, +2, +216, +220, +212, +63, +129, +6, +211, +124, +138, +116, +252, +193, +179, +84, +207, +201, +208, +8, +232, +172, +41, +160, +44, +173, +88, +43, +5, +224, +219, +142, +204, +91, +124, +164, +192, +48, +176, +153, +146, +142, +150, +203, +195, +128, +3, +77, +83, +185, +217, +13, +12, +206, +200, +44, +238, +5, +150, +200, +145, +107, +172, +0, +124, +27, +155, +3, +32, +139, +233, +192, +150, +67, +113, +190, +153, +49, +124, +216, +28, +115, +183, +146, +182, +173, +21, +192, +136, +1, +117, +83, +61, +4, +93, +231, +78, +65, +93, +86, +175, +164, +60, +133, +243, +168, +7, +163, +64, +1, +48, +6, +40, +214, +242, +128, +42, +233, +157, +80, +214, +218, +23, +80, +94, +190, +59, +80, +59, +192, +194, +5, +114, +109, +21, +128, +67, +3, +157, +174, +66, +103, +132, +211, +80, +151, +230, +147, +25, +134, +233, +48, +74, +18, +19, +12, +217, +51, +40, +9, +120, +202, +156, +211, +235, +77, +249, +168, +84, +0, +54, +27, +175, +19, +77, +67, +244, +113, +83, +255, +6, +255, +247, +97, +224, +40, +231, +220, +33, +195, +60, +190, +161, +194, +17, +34, +114, +127, +164, +60, +187, +247, +218, +149, +156, +160, +145, +99, +33, +213, +217, +137, +69, +33, +199, +232, +84, +239, +26, +209, +52, +105, +247, +138, +200, +74, +206, +185, +218, +46, +183, +192, +33, +34, +18, +8, +79, +191, +87, +22, +230, +92, +4, +239, +106, +123, +162, +255, +27, +54, +120, +39, +159, +227, +37, +158, +42, +173, +18, +252, +189, +189, +131, +136, +236, +35, +34, +239, +16, +117, +120, +187, +71, +212, +213, +246, +68, +231, +92, +94, +194, +147, +249, +69, +29, +114, +2, +51, +212, +247, +157, +115, +247, +215, +56, +244, +10, +146, +184, +101, +191, +166, +254, +200, +135, +17, +164, +153, +106, +30, +70, +105, +159, +191, +130, +198, +126, +227, +53, +111, +52, +193, +231, +88, +0, +233, +55, +121, +157, +12, +62, +141, +228, +34, +253, +212, +162, +88, +163, +65, +218, +177, +140, +252, +168, +224, +116, +108, +59, +3, +232, +104, +12, +217, +168, +69, +139, +179, +10, +228, +126, +98, +218, +157, +74, +181, +228, +158, +246, +156, +38, +162, +81, +147, +123, +160, +249, +35, +3, +38, +116, +122, +130, +93, +0, +117, +201, +124, +201, +255, +125, +214, +148, +255, +206, +12, +124, +32, +125, +83, +164, +159, +141, +128, +237, +128, +213, +203, +218, +14, +39, +154, +62, +200, +77, +229, +186, +0, +13, +211, +142, +121, +217, +57, +142, +211, +49, +6, +52, +169, +71, +192, +37, +168, +66, +90, +22, +184, +174, +232, +190, +6, +22, +35, +73, +118, +243, +32, +21, +21, +84, +70, +1, +228, +97, +66, +68, +206, +110, +121, +175, +106, +202, +87, +54, +229, +3, +62, +8, +164, +51, +114, +47, +111, +202, +109, +134, +239, +129, +120, +138, +0, +235, +10, +124, +148, +115, +238, +181, +254, +207, +230, +247, +179, +198, +55, +155, +205, +53, +15, +63, +17, +145, +211, +68, +164, +112, +191, +212, +12, +116, +53, +224, +108, +116, +171, +103, +42, +26, +170, +58, +158, +130, +125, +97, +70, +144, +62, +172, +42, +232, +192, +118, +224, +156, +187, +216, +57, +55, +175, +115, +110, +30, +231, +220, +141, +69, +109, +35, +178, +7, +59, +231, +254, +215, +57, +183, +113, +222, +20, +119, +14, +129, +245, +76, +253, +143, +115, +238, +113, +231, +220, +131, +162, +65, +84, +95, +244, +127, +207, +68, +228, +86, +147, +100, +137, +124, +142, +115, +110, +138, +200, +171, +59, +93, +33, +177, +104, +25, +191, +255, +213, +162, +209, +146, +247, +138, +70, +124, +94, +231, +255, +238, +141, +180, +181, +169, +207, +108, +190, +131, +141, +114, +218, +4, +216, +25, +204, +250, +230, +243, +122, +57, +109, +170, +3, +216, +140, +196, +73, +39, +154, +37, +39, +34, +19, +166, +58, +191, +169, +208, +246, +147, +254, +161, +143, +225, +82, +226, +25, +129, +155, +58, +243, +148, +61, +144, +119, +12, +179, +28, +116, +104, +116, +164, +225, +27, +36, +210, +207, +202, +168, +193, +106, +216, +28, +156, +170, +128, +196, +249, +234, +241, +154, +114, +243, +161, +65, +71, +1, +183, +160, +25, +141, +54, +162, +248, +37, +179, +142, +145, +249, +149, +41, +183, +164, +42, +3, +110, +193, +52, +244, +94, +69, +249, +52, +3, +174, +51, +229, +150, +168, +118, +128, +1, +9, +245, +191, +9, +248, +163, +41, +15, +91, +180, +51, +129, +37, +243, +142, +155, +59, +53, +4, +54, +17, +145, +63, +136, +206, +18, +30, +23, +145, +82, +79, +177, +58, +64, +247, +110, +39, +136, +6, +133, +76, +19, +145, +111, +138, +26, +102, +190, +44, +34, +31, +16, +229, +69, +251, +180, +136, +100, +247, +151, +39, +139, +200, +21, +34, +242, +126, +73, +66, +34, +255, +35, +34, +255, +21, +229, +114, +187, +75, +70, +31, +26, +27, +15, +107, +224, +116, +73, +130, +182, +54, +22, +145, +155, +253, +231, +178, +55, +72, +22, +23, +136, +198, +217, +191, +78, +70, +87, +164, +92, +35, +56, +231, +166, +2, +27, +138, +222, +107, +239, +19, +189, +70, +8, +40, +107, +151, +0, +0, +23, +224, +73, +68, +65, +84, +171, +136, +200, +1, +34, +242, +40, +176, +135, +115, +46, +27, +121, +39, +162, +65, +51, +83, +69, +100, +62, +17, +217, +30, +248, +167, +136, +32, +34, +33, +73, +45, +162, +49, +18, +93, +141, +243, +126, +175, +216, +215, +16, +145, +213, +253, +67, +59, +221, +127, +23, +17, +185, +209, +115, +12, +100, +229, +238, +3, +110, +22, +145, +85, +69, +100, +29, +212, +78, +49, +143, +136, +4, +98, +216, +43, +157, +115, +245, +66, +184, +81, +239, +184, +144, +243, +237, +49, +224, +157, +5, +109, +173, +230, +202, +195, +45, +17, +185, +173, +76, +253, +15, +76, +249, +50, +166, +252, +132, +90, +3, +47, +62, +39, +251, +102, +221, +15, +117, +108, +177, +127, +3, +76, +56, +29, +202, +53, +181, +57, +140, +71, +105, +161, +179, +127, +27, +69, +228, +26, +189, +65, +34, +253, +60, +236, +219, +150, +198, +201, +163, +54, +138, +11, +24, +204, +24, +188, +17, +154, +18, +110, +193, +2, +217, +90, +75, +63, +26, +206, +0, +140, +188, +3, +222, +143, +114, +249, +221, +104, +174, +201, +84, +114, +28, +213, +128, +195, +200, +199, +177, +57, +50, +141, +227, +87, +72, +179, +6, +239, +2, +236, +96, +190, +127, +165, +64, +206, +110, +47, +191, +159, +116, +236, +194, +190, +121, +114, +85, +7, +178, +126, +73, +219, +166, +10, +224, +72, +83, +191, +69, +166, +238, +109, +192, +219, +129, +165, +34, +114, +77, +141, +37, +195, +106, +4, +28, +110, +57, +47, +27, +12, +66, +179, +128, +37, +209, +156, +139, +97, +39, +224, +134, +18, +217, +61, +72, +231, +37, +248, +55, +26, +45, +24, +245, +59, +71, +215, +194, +97, +135, +232, +42, +188, +47, +0, +234, +189, +23, +150, +117, +39, +231, +200, +54, +89, +250, +53, +93, +2, +108, +134, +122, +14, +30, +141, +201, +78, +141, +6, +20, +5, +236, +88, +32, +191, +19, +112, +61, +26, +55, +17, +50, +48, +237, +93, +112, +93, +218, +40, +128, +255, +33, +89, +114, +159, +69, +98, +128, +159, +69, +177, +43, +253, +138, +230, +152, +7, +147, +60, +91, +133, +114, +69, +3, +9, +57, +234, +94, +200, +59, +81, +211, +246, +53, +36, +70, +145, +29, +73, +114, +169, +93, +106, +202, +54, +140, +200, +217, +45, +150, +1, +118, +213, +130, +227, +89, +254, +186, +67, +77, +185, +205, +223, +62, +224, +175, +192, +24, +121, +144, +155, +202, +121, +217, +166, +111, +144, +34, +226, +205, +159, +23, +200, +125, +1, +19, +149, +7, +236, +70, +98, +57, +255, +55, +145, +124, +16, +104, +14, +134, +16, +51, +50, +21, +125, +123, +109, +67, +250, +193, +25, +120, +32, +137, +40, +0, +116, +6, +18, +20, +220, +139, +68, +140, +114, +153, +107, +240, +91, +52, +170, +112, +81, +210, +94, +166, +159, +168, +118, +133, +135, +30, +36, +209, +154, +47, +144, +100, +144, +250, +71, +5, +185, +64, +190, +123, +9, +201, +139, +96, +248, +61, +84, +169, +104, +4, +36, +173, +129, +43, +187, +115, +210, +220, +88, +98, +31, +172, +67, +73, +43, +173, +240, +151, +37, +82, +232, +74, +46, +134, +42, +198, +195, +186, +10, +160, +246, +27, +4, +88, +133, +228, +33, +126, +16, +93, +154, +109, +76, +50, +27, +152, +69, +78, +138, +52, +47, +255, +57, +6, +195, +132, +239, +36, +50, +123, +243, +237, +27, +45, +253, +200, +40, +0, +116, +134, +24, +30, +144, +153, +64, +150, +168, +36, +200, +205, +67, +58, +102, +33, +139, +203, +24, +69, +6, +79, +210, +89, +171, +3, +114, +179, +84, +25, +185, +240, +60, +77, +33, +81, +138, +7, +52, +29, +196, +231, +252, +197, +189, +132, +130, +117, +92, +142, +108, +85, +5, +176, +165, +57, +193, +31, +154, +242, +69, +129, +123, +124, +63, +81, +119, +89, +26, +76, +117, +169, +102, +93, +31, +216, +106, +27, +66, +185, +78, +119, +29, +140, +124, +173, +55, +8, +106, +17, +15, +216, +218, +148, +111, +104, +202, +11, +9, +59, +72, +135, +125, +207, +164, +88, +97, +52, +93, +250, +189, +170, +0, +80, +254, +137, +59, +77, +63, +7, +150, +140, +111, +28, +186, +156, +153, +136, +218, +182, +158, +67, +237, +0, +95, +100, +20, +81, +213, +139, +136, +160, +247, +242, +52, +115, +110, +51, +200, +137, +179, +200, +200, +173, +18, +185, +87, +74, +109, +62, +121, +187, +0, +95, +16, +181, +2, +175, +35, +202, +83, +22, +165, +94, +206, +193, +141, +162, +187, +6, +247, +148, +180, +187, +64, +212, +10, +254, +6, +17, +217, +7, +120, +70, +68, +254, +45, +34, +123, +72, +194, +247, +150, +103, +209, +63, +93, +212, +58, +234, +68, +233, +142, +166, +73, +146, +205, +165, +138, +165, +123, +184, +177, +191, +232, +78, +133, +197, +11, +67, +116, +172, +211, +69, +127, +55, +203, +148, +115, +90, +65, +123, +235, +79, +111, +201, +53, +254, +106, +250, +152, +154, +39, +236, +149, +195, +206, +166, +104, +46, +81, +18, +203, +117, +157, +115, +177, +245, +186, +29, +87, +106, +151, +33, +102, +229, +206, +193, +201, +34, +18, +12, +211, +39, +57, +231, +254, +175, +168, +177, +115, +110, +186, +136, +252, +216, +255, +141, +106, +56, +231, +158, +1, +254, +38, +9, +141, +215, +37, +206, +185, +39, +43, +200, +221, +10, +220, +43, +34, +225, +161, +191, +165, +198, +245, +76, +3, +93, +219, +189, +136, +78, +171, +75, +125, +152, +81, +142, +253, +172, +117, +220, +254, +69, +119, +17, +80, +107, +241, +52, +226, +184, +4, +136, +178, +8, +211, +208, +88, +50, +156, +160, +27, +27, +64, +229, +93, +7, +35, +95, +235, +13, +130, +26, +240, +2, +114, +131, +122, +114, +100, +247, +38, +109, +3, +216, +157, +114, +27, +64, +211, +165, +223, +211, +12, +226, +49, +106, +18, +137, +180, +5, +112, +147, +63, +246, +52, +10, +246, +215, +91, +30, +99, +55, +115, +142, +187, +214, +144, +179, +182, +156, +220, +228, +163, +157, +131, +100, +235, +40, +15, +63, +40, +144, +93, +29, +101, +219, +153, +132, +174, +95, +254, +133, +58, +91, +20, +254, +176, +52, +52, +150, +12, +23, +24, +65, +215, +99, +52, +215, +95, +64, +174, +27, +168, +111, +251, +87, +211, +118, +217, +26, +199, +120, +51, +13, +118, +1, +104, +184, +244, +35, +174, +0, +96, +24, +194, +129, +51, +227, +216, +203, +28, +251, +107, +67, +116, +140, +99, +125, +255, +83, +169, +176, +29, +59, +226, +160, +133, +2, +104, +113, +204, +70, +198, +146, +225, +2, +221, +24, +15, +155, +42, +128, +202, +111, +16, +210, +111, +141, +45, +77, +249, +123, +209, +25, +224, +149, +228, +167, +194, +94, +31, +248, +11, +113, +63, +128, +243, +137, +216, +143, +208, +93, +128, +144, +25, +41, +236, +2, +108, +133, +50, +53, +5, +236, +28, +145, +179, +10, +224, +97, +18, +37, +243, +24, +240, +186, +202, +23, +167, +37, +80, +251, +195, +203, +254, +216, +247, +208, +97, +142, +63, +224, +19, +232, +203, +47, +204, +224, +154, +185, +240, +206, +9, +160, +161, +177, +100, +184, +64, +55, +198, +195, +202, +138, +35, +211, +71, +229, +55, +8, +234, +63, +17, +166, +241, +247, +161, +44, +193, +27, +144, +76, +117, +161, +32, +255, +94, +19, +208, +96, +233, +71, +162, +0, +94, +1, +150, +7, +190, +109, +100, +126, +219, +112, +28, +87, +82, +140, +188, +28, +139, +214, +232, +89, +121, +11, +187, +194, +120, +108, +196, +224, +84, +10, +184, +14, +123, +72, +237, +169, +110, +149, +7, +178, +50, +73, +7, +105, +54, +227, +172, +129, +111, +216, +119, +29, +188, +108, +163, +55, +8, +13, +253, +0, +218, +128, +154, +75, +63, +6, +183, +1, +23, +64, +153, +136, +2, +234, +208, +147, +135, +62, +191, +5, +156, +25, +249, +187, +199, +247, +153, +167, +0, +62, +104, +142, +91, +100, +96, +173, +59, +158, +203, +209, +101, +213, +141, +116, +168, +88, +170, +30, +220, +238, +175, +231, +97, +187, +97, +29, +84, +9, +168, +55, +213, +29, +86, +5, +208, +20, +21, +199, +153, +167, +0, +26, +191, +65, +208, +173, +95, +203, +72, +251, +79, +74, +56, +240, +219, +2, +125, +136, +195, +246, +109, +33, +185, +42, +113, +71, +32, +203, +97, +113, +47, +53, +183, +172, +11, +142, +21, +56, +7, +163, +10, +192, +183, +177, +116, +247, +217, +92, +24, +35, +10, +224, +141, +104, +118, +225, +251, +73, +140, +178, +80, +180, +53, +79, +53, +5, +16, +117, +182, +104, +56, +200, +51, +43, +28, +175, +108, +250, +90, +103, +170, +91, +197, +199, +126, +181, +26, +227, +31, +18, +5, +208, +6, +116, +240, +6, +161, +70, +44, +64, +91, +0, +111, +34, +49, +230, +206, +162, +96, +105, +67, +142, +43, +48, +240, +7, +243, +59, +252, +48, +79, +190, +230, +184, +170, +40, +0, +235, +117, +249, +229, +46, +142, +219, +5, +80, +63, +138, +60, +118, +238, +66, +5, +176, +0, +186, +246, +179, +127, +103, +27, +225, +75, +137, +211, +62, +47, +136, +122, +144, +61, +132, +242, +167, +165, +190, +23, +28, +175, +177, +2, +160, +193, +84, +151, +142, +137, +61, +24, +133, +10, +160, +11, +48, +140, +10, +192, +28, +243, +17, +127, +204, +241, +195, +117, +204, +182, +64, +109, +80, +33, +44, +253, +95, +35, +61, +158, +0, +212, +40, +155, +135, +210, +16, +125, +219, +209, +106, +230, +1, +123, +134, +226, +96, +132, +237, +124, +187, +211, +99, +223, +115, +100, +86, +71, +183, +140, +138, +254, +242, +252, +0, +106, +79, +117, +123, +5, +80, +13, +192, +154, +168, +143, +253, +176, +176, +8, +161, +126, +28, +160, +51, +128, +117, +134, +227, +152, +93, +1, +165, +9, +11, +88, +179, +92, +98, +200, +199, +243, +26, +146, +37, +85, +115, +5, +128, +190, +197, +109, +100, +216, +86, +21, +100, +46, +247, +109, +119, +136, +125, +239, +18, +52, +152, +234, +14, +183, +2, +232, +250, +120, +179, +43, +80, +135, +161, +137, +192, +167, +71, +122, +44, +117, +65, +58, +236, +246, +164, +146, +182, +173, +89, +172, +208, +164, +52, +211, +209, +153, +199, +128, +211, +22, +234, +155, +81, +132, +202, +10, +224, +151, +70, +168, +18, +27, +43, +186, +157, +52, +3, +245, +179, +94, +38, +251, +61, +210, +190, +181, +13, +160, +14, +104, +233, +99, +31, +233, +111, +72, +20, +0, +186, +236, +250, +26, +163, +104, +75, +179, +71, +62, +80, +30, +3, +208, +237, +201, +188, +37, +107, +35, +22, +171, +72, +63, +123, +251, +246, +209, +37, +47, +13, +102, +0, +177, +53, +253, +102, +162, +254, +248, +34, +234, +191, +94, +159, +80, +160, +71, +27, +188, +93, +68, +190, +43, +34, +15, +163, +73, +49, +214, +165, +161, +179, +9, +234, +180, +178, +55, +112, +69, +183, +67, +28, +157, +160, +230, +91, +214, +95, +219, +83, +104, +103, +197, +15, +15, +213, +2, +34, +146, +199, +43, +16, +88, +172, +158, +151, +65, +22, +171, +7, +164, +58, +139, +213, +246, +254, +127, +116, +235, +209, +57, +247, +178, +180, +97, +41, +66, +125, +236, +159, +242, +218, +98, +58, +153, +28, +242, +37, +178, +151, +121, +185, +29, +98, +223, +35, +237, +27, +219, +0, +26, +158, +91, +153, +131, +205, +198, +229, +189, +164, +250, +27, +170, +25, +192, +175, +25, +36, +203, +184, +7, +56, +16, +67, +104, +81, +210, +199, +106, +190, +159, +192, +234, +52, +230, +169, +189, +202, +64, +131, +183, +44, +26, +107, +1, +74, +242, +209, +200, +155, +16, +88, +130, +196, +86, +118, +107, +219, +243, +40, +56, +206, +178, +168, +157, +228, +5, +10, +34, +24, +129, +119, +152, +103, +56, +139, +194, +93, +0, +71, +58, +110, +250, +60, +6, +119, +5, +222, +158, +35, +91, +219, +8, +56, +220, +104, +241, +64, +174, +143, +250, +127, +239, +133, +241, +149, +39, +205, +119, +63, +160, +193, +155, +30, +207, +203, +46, +138, +50, +209, +156, +79, +90, +25, +76, +37, +39, +55, +29, +58, +253, +219, +29, +205, +222, +107, +49, +11, +184, +176, +228, +120, +97, +43, +238, +226, +162, +118, +190, +237, +168, +100, +100, +166, +121, +226, +215, +64, +12, +114, +126, +139, +99, +219, +229, +108, +33, +117, +62, +233, +157, +181, +232, +152, +114, +228, +14, +244, +50, +165, +137, +89, +208, +37, +248, +47, +209, +221, +184, +202, +126, +0, +214, +160, +145, +135, +241, +17, +185, +176, +237, +247, +48, +233, +109, +192, +135, +25, +2, +31, +109, +186, +97, +219, +173, +163, +0, +172, +61, +100, +31, +83, +110, +157, +80, +6, +30, +156, +166, +199, +139, +244, +243, +54, +52, +11, +113, +192, +153, +145, +54, +91, +0, +207, +103, +174, +193, +245, +104, +210, +213, +129, +136, +188, +140, +236, +138, +25, +185, +21, +11, +218, +182, +90, +203, +154, +107, +86, +24, +150, +75, +241, +58, +22, +26, +242, +2, +230, +28, +235, +117, +168, +55, +34, +52, +84, +98, +232, +182, +116, +64, +161, +91, +50, +205, +21, +64, +160, +194, +171, +157, +141, +26, +248, +174, +151, +29, +80, +0, +118, +171, +167, +17, +49, +130, +115, +238, +21, +17, +201, +70, +145, +85, +142, +42, +27, +3, +248, +155, +36, +54, +145, +241, +104, +120, +244, +52, +73, +216, +97, +69, +154, +242, +174, +231, +0, +85, +156, +155, +139, +200, +182, +34, +178, +174, +36, +191, +211, +52, +17, +137, +77, +51, +87, +16, +145, +96, +21, +190, +79, +68, +118, +118, +206, +85, +93, +247, +135, +0, +170, +151, +68, +115, +64, +236, +45, +249, +118, +159, +182, +140, +204, +97, +41, +242, +124, +197, +177, +13, +57, +156, +115, +207, +162, +180, +223, +7, +249, +191, +51, +26, +244, +113, +161, +40, +55, +197, +144, +192, +43, +229, +85, +68, +249, +51, +74, +103, +105, +117, +240, +170, +2, +112, +206, +253, +85, +134, +240, +36, +134, +8, +195, +65, +183, +253, +71, +17, +185, +72, +52, +103, +226, +98, +162, +6, +58, +139, +139, +69, +115, +204, +117, +2, +224, +215, +34, +242, +89, +81, +186, +244, +128, +123, +253, +49, +78, +200, +33, +135, +184, +91, +148, +96, +100, +97, +17, +121, +139, +136, +92, +6, +92, +45, +122, +51, +159, +233, +156, +123, +52, +231, +88, +175, +241, +199, +18, +17, +217, +213, +183, +223, +9, +56, +216, +57, +247, +82, +182, +189, +207, +211, +247, +241, +76, +217, +163, +146, +144, +80, +196, +142, +177, +137, +136, +236, +37, +154, +83, +48, +216, +74, +94, +0, +62, +44, +34, +59, +137, +200, +221, +206, +185, +108, +180, +232, +7, +164, +248, +94, +156, +94, +80, +215, +4, +231, +137, +62, +252, +171, +2, +171, +59, +231, +10, +9, +84, +71, +0, +193, +248, +247, +135, +57, +60, +201, +75, +171, +169, +124, +155, +53, +249, +56, +52, +125, +249, +205, +232, +118, +207, +203, +232, +222, +245, +254, +228, +56, +204, +180, +24, +103, +240, +49, +159, +134, +186, +185, +174, +71, +133, +93, +0, +212, +6, +240, +57, +210, +148, +215, +160, +196, +41, +127, +201, +145, +217, +211, +183, +185, +218, +127, +15, +84, +107, +123, +85, +56, +222, +15, +204, +49, +138, +92, +102, +15, +35, +177, +99, +188, +146, +249, +63, +11, +147, +204, +98, +164, +224, +127, +223, +96, +48, +29, +210, +4, +184, +52, +88, +2, +144, +108, +53, +54, +114, +54, +162, +96, +9, +48, +230, +208, +230, +65, +30, +78, +180, +80, +0, +231, +160, +204, +199, +141, +253, +0, +208, +204, +62, +191, +161, +100, +23, +128, +100, +93, +185, +171, +255, +30, +130, +171, +170, +100, +16, +170, +164, +0, +124, +219, +5, +209, +245, +127, +176, +78, +79, +69, +147, +102, +14, +121, +16, +13, +234, +178, +123, +50, +240, +145, +146, +118, +33, +87, +96, +84, +89, +118, +56, +158, +90, +10, +0, +221, +45, +3, +205, +110, +212, +116, +59, +120, +228, +21, +0, +176, +45, +48, +33, +231, +47, +151, +151, +61, +210, +207, +108, +173, +0, +58, +30, +195, +194, +40, +189, +219, +128, +61, +0, +248, +176, +31, +219, +11, +120, +218, +55, +116, +22, +17, +50, +18, +151, +81, +143, +85, +86, +0, +190, +253, +17, +190, +109, +32, +254, +248, +85, +153, +76, +91, +248, +243, +15, +188, +6, +133, +145, +141, +104, +130, +19, +40, +112, +8, +3, +190, +227, +31, +196, +198, +220, +130, +13, +20, +192, +143, +124, +219, +239, +53, +61, +102, +45, +152, +3, +110, +110, +63, +231, +180, +117, +104, +76, +53, +168, +117, +120, +167, +130, +126, +237, +13, +147, +69, +52, +203, +74, +78, +63, +157, +122, +244, +13, +21, +168, +70, +236, +177, +194, +72, +143, +179, +41, +168, +55, +3, +216, +26, +157, +238, +95, +7, +204, +77, +178, +237, +184, +219, +16, +143, +49, +108, +207, +149, +18, +134, +160, +179, +4, +128, +40, +1, +39, +186, +76, +176, +244, +231, +139, +52, +28, +83, +101, +5, +0, +204, +69, +18, +40, +245, +158, +38, +199, +171, +59, +184, +143, +249, +147, +188, +200, +126, +206, +105, +187, +16, +58, +93, +5, +165, +104, +14, +225, +154, +63, +100, +8, +121, +214, +199, +168, +2, +200, +195, +144, +198, +219, +15, +37, +168, +167, +0, +62, +130, +198, +150, +172, +228, +191, +175, +128, +210, +123, +215, +218, +118, +243, +15, +196, +81, +232, +82, +226, +191, +24, +26, +243, +72, +219, +176, +229, +248, +56, +176, +80, +94, +59, +211, +126, +130, +111, +255, +88, +65, +155, +95, +161, +246, +159, +83, +235, +140, +59, +211, +71, +29, +5, +16, +18, +148, +14, +125, +180, +33, +234, +124, +242, +16, +234, +56, +240, +33, +243, +57, +143, +209, +119, +119, +212, +224, +52, +17, +13, +82, +88, +9, +117, +184, +184, +130, +6, +123, +149, +53, +198, +217, +138, +53, +55, +211, +87, +32, +193, +152, +140, +58, +140, +228, +26, +191, +208, +117, +117, +192, +132, +154, +227, +204, +195, +28, +161, +0, +124, +251, +185, +50, +223, +23, +104, +112, +204, +144, +137, +232, +88, +212, +73, +106, +58, +57, +57, +8, +208, +240, +117, +128, +195, +42, +246, +125, +190, +111, +63, +164, +47, +144, +154, +10, +224, +87, +190, +221, +208, +51, +252, +146, +80, +107, +255, +200, +126, +30, +242, +3, +215, +4, +221, +57, +216, +4, +237, +122, +45, +74, +76, +25, +214, +138, +81, +247, +231, +186, +10, +96, +118, +71, +93, +5, +208, +209, +49, +255, +12, +252, +221, +127, +30, +135, +46, +59, +247, +143, +180, +123, +11, +201, +116, +189, +18, +159, +33, +234, +56, +5, +112, +65, +65, +155, +87, +35, +100, +91, +156, +67, +37, +5, +224, +207, +47, +56, +40, +45, +223, +244, +120, +101, +24, +8, +6, +170, +139, +58, +26, +109, +148, +225, +22, +209, +253, +230, +13, +157, +115, +223, +22, +145, +160, +101, +71, +165, +97, +17, +245, +57, +191, +9, +216, +182, +66, +91, +27, +167, +112, +60, +234, +17, +248, +4, +113, +151, +229, +113, +94, +233, +63, +130, +206, +132, +238, +2, +190, +48, +52, +103, +209, +26, +143, +139, +200, +59, +80, +151, +236, +53, +69, +83, +119, +199, +188, +2, +215, +17, +245, +35, +120, +78, +244, +119, +46, +4, +186, +100, +125, +135, +255, +122, +117, +55, +67, +141, +195, +57, +183, +185, +75, +112, +127, +65, +187, +233, +206, +185, +197, +124, +187, +178, +36, +59, +237, +65, +205, +37, +128, +145, +27, +86, +5, +64, +7, +172, +185, +190, +159, +249, +208, +36, +168, +247, +147, +246, +183, +223, +47, +210, +246, +50, +226, +24, +182, +41, +60, +186, +166, +13, +111, +181, +104, +60, +128, +105, +107, +21, +192, +227, +230, +243, +3, +145, +182, +193, +199, +252, +223, +168, +223, +193, +139, +254, +251, +218, +37, +199, +24, +137, +25, +192, +91, +73, +211, +93, +93, +69, +156, +65, +248, +23, +190, +190, +82, +158, +8, +96, +13, +211, +231, +234, +5, +237, +90, +207, +0, +70, +53, +72, +27, +1, +215, +165, +192, +8, +104, +100, +70, +82, +1, +228, +33, +74, +154, +153, +233, +39, +220, +248, +135, +2, +239, +4, +62, +235, +191, +143, +74, +5, +224, +199, +241, +13, +127, +220, +233, +20, +228, +125, +35, +173, +0, +64, +157, +138, +110, +34, +18, +240, +130, +42, +194, +215, +162, +73, +52, +231, +39, +217, +166, +219, +164, +100, +44, +195, +174, +0, +252, +113, +23, +67, +249, +27, +183, +34, +159, +49, +42, +172, +231, +207, +174, +216, +103, +200, +87, +120, +115, +73, +187, +217, +78, +1, +164, +150, +0, +206, +185, +75, +68, +228, +104, +17, +89, +95, +52, +135, +219, +209, +34, +178, +62, +57, +219, +128, +99, +28, +129, +126, +122, +25, +209, +60, +108, +193, +223, +63, +198, +44, +187, +153, +136, +172, +103, +190, +159, +46, +154, +211, +176, +44, +1, +234, +252, +232, +118, +234, +105, +228, +164, +106, +246, +55, +243, +29, +168, +117, +249, +95, +20, +39, +55, +9, +20, +221, +243, +248, +49, +85, +193, +211, +34, +242, +14, +231, +220, +106, +206, +185, +129, +144, +103, +231, +220, +84, +239, +246, +251, +93, +81, +95, +255, +245, +69, +228, +151, +34, +210, +56, +58, +174, +41, +80, +91, +76, +64, +148, +161, +217, +57, +55, +201, +57, +55, +193, +57, +119, +166, +207, +249, +23, +67, +8, +66, +123, +166, +194, +49, +23, +150, +228, +183, +255, +118, +253, +81, +207, +225, +96, +140, +218, +0, +208, +37, +207, +185, +168, +183, +220, +3, +40, +83, +240, +253, +64, +52, +209, +36, +21, +141, +128, +192, +188, +104, +226, +139, +147, +72, +71, +232, +13, +88, +151, +81, +111, +56, +208, +253, +241, +195, +129, +127, +248, +239, +185, +74, +192, +244, +249, +211, +130, +54, +118, +6, +112, +89, +241, +149, +120, +85, +102, +37, +116, +249, +244, +47, +116, +134, +209, +169, +35, +80, +133, +227, +127, +140, +36, +10, +112, +66, +203, +190, +174, +245, +253, +148, +178, +89, +1, +39, +248, +182, +231, +85, +104, +91, +105, +6, +80, +166, +200, +80, +35, +101, +88, +154, +253, +135, +156, +29, +17, +226, +233, +208, +6, +124, +102, +170, +246, +55, +36, +96, +140, +42, +128, +186, +160, +186, +2, +216, +57, +242, +163, +65, +92, +1, +92, +132, +250, +197, +47, +228, +191, +207, +143, +166, +205, +202, +13, +70, +49, +55, +69, +238, +236, +131, +26, +10, +0, +216, +23, +221, +3, +95, +195, +127, +63, +202, +203, +141, +47, +145, +235, +90, +1, +28, +133, +230, +34, +56, +159, +150, +132, +164, +36, +9, +99, +10, +151, +0, +254, +220, +65, +93, +162, +75, +233, +231, +168, +160, +0, +168, +168, +200, +128, +85, +73, +188, +46, +191, +159, +211, +166, +146, +2, +168, +218, +95, +12, +195, +194, +252, +58, +7, +98, +186, +104, +216, +236, +121, +162, +203, +168, +60, +188, +73, +68, +30, +115, +206, +189, +40, +34, +226, +156, +155, +2, +220, +39, +26, +209, +151, +135, +174, +215, +159, +227, +68, +163, +242, +54, +0, +46, +17, +145, +176, +76, +184, +38, +95, +164, +123, +56, +231, +14, +22, +145, +131, +59, +234, +238, +17, +255, +191, +44, +214, +224, +159, +34, +114, +170, +136, +124, +201, +57, +215, +21, +107, +210, +122, +162, +105, +238, +239, +19, +145, +92, +197, +232, +156, +187, +25, +216, +66, +68, +46, +16, +145, +253, +129, +223, +59, +231, +178, +182, +171, +109, +36, +29, +21, +42, +162, +20, +98, +77, +251, +235, +30, +244, +51, +128, +108, +187, +37, +49, +140, +173, +70, +38, +54, +3, +248, +43, +186, +246, +15, +190, +248, +227, +208, +169, +220, +77, +5, +253, +135, +183, +80, +238, +219, +141, +122, +51, +128, +185, +80, +119, +238, +7, +209, +109, +192, +59, +128, +93, +138, +100, +70, +26, +168, +93, +5, +114, +28, +183, +72, +130, +154, +158, +33, +146, +203, +162, +197, +113, +103, +95, +35, +96, +157, +233, +198, +112, +2, +117, +57, +62, +18, +221, +166, +154, +140, +102, +131, +125, +125, +78, +219, +202, +177, +9, +77, +134, +98, +62, +231, +222, +84, +206, +185, +39, +156, +115, +47, +84, +236, +243, +4, +81, +163, +227, +95, +129, +3, +69, +228, +207, +34, +178, +164, +104, +236, +124, +30, +130, +163, +202, +39, +128, +181, +218, +222, +224, +206, +185, +89, +206, +185, +67, +157, +115, +203, +58, +231, +22, +112, +206, +189, +219, +57, +119, +66, +155, +62, +71, +1, +46, +245, +255, +95, +39, +34, +43, +15, +215, +65, +169, +239, +29, +57, +34, +59, +41, +22, +157, +105, +199, +33, +196, +159, +68, +228, +16, +81, +214, +155, +249, +69, +100, +41, +137, +144, +69, +160, +235, +232, +179, +69, +228, +27, +34, +242, +47, +81, +134, +155, +9, +116, +23, +155, +96, +131, +68, +214, +65, +183, +13, +43, +167, +18, +139, +193, +57, +247, +123, +17, +217, +69, +244, +70, +61, +92, +68, +222, +44, +34, +95, +22, +145, +99, +10, +196, +14, +23, +93, +94, +204, +47, +34, +151, +73, +66, +22, +209, +195, +195, +57, +247, +95, +209, +107, +35, +146, +44, +105, +122, +68, +96, +109, +0, +149, +215, +27, +195, +5, +224, +45, +162, +148, +88, +34, +34, +147, +68, +31, +238, +167, +69, +228, +197, +72, +243, +109, +69, +228, +141, +34, +114, +179, +136, +124, +66, +84, +81, +156, +39, +34, +171, +139, +110, +109, +253, +181, +229, +112, +30, +22, +145, +59, +69, +228, +93, +162, +107, +247, +19, +69, +228, +123, +34, +146, +59, +93, +175, +2, +231, +220, +4, +17, +153, +80, +67, +4, +81, +106, +176, +217, +26, +126, +233, +178, +150, +136, +220, +228, +156, +107, +226, +157, +249, +127, +34, +178, +182, +136, +236, +13, +28, +29, +99, +56, +106, +128, +64, +155, +247, +74, +7, +125, +245, +40, +3, +240, +1, +51, +69, +26, +241, +105, +41, +240, +46, +224, +239, +168, +181, +245, +49, +42, +184, +204, +154, +241, +119, +18, +100, +226, +103, +52, +97, +137, +51, +108, +41, +188, +204, +241, +247, +70, +183, +154, +94, +70, +25, +146, +42, +189, +97, +81, +166, +232, +155, +168, +72, +2, +66, +226, +124, +21, +75, +161, +94, +104, +3, +48, +237, +66, +226, +208, +86, +148, +109, +232, +118, +237, +120, +243, +91, +78, +204, +105, +55, +230, +150, +0, +163, +22, +12, +82, +91, +5, +20, +58, +168, +140, +182, +139, +58, +4, +10, +32, +24, +162, +206, +233, +162, +191, +154, +199, +222, +202, +31, +251, +41, +224, +143, +168, +135, +225, +20, +34, +153, +159, +50, +114, +225, +225, +153, +5, +172, +95, +241, +88, +93, +40, +128, +69, +208, +104, +85, +40, +118, +176, +42, +27, +75, +22, +159, +205, +105, +55, +230, +20, +192, +88, +176, +1, +244, +72, +35, +188, +65, +187, +36, +62, +173, +138, +229, +68, +51, +207, +236, +234, +156, +219, +66, +68, +174, +23, +245, +168, +204, +77, +206, +138, +146, +158, +132, +64, +171, +175, +57, +231, +254, +54, +212, +131, +12, +112, +206, +61, +47, +186, +45, +119, +170, +136, +180, +81, +192, +143, +136, +122, +73, +222, +46, +34, +187, +57, +231, +10, +243, +0, +142, +37, +140, +102, +63, +128, +117, +69, +100, +13, +73, +214, +238, +167, +136, +200, +254, +50, +27, +173, +127, +209, +88, +246, +243, +68, +211, +74, +109, +227, +156, +171, +18, +188, +50, +98, +204, +205, +158, +189, +247, +7, +34, +34, +40, +171, +239, +7, +68, +100, +170, +196, +169, +202, +3, +54, +151, +228, +69, +51, +228, +52, +96, +89, +56, +231, +158, +145, +252, +148, +93, +85, +251, +200, +205, +140, +61, +214, +81, +123, +6, +64, +77, +183, +67, +42, +248, +119, +199, +224, +181, +183, +229, +143, +159, +234, +156, +123, +186, +198, +22, +219, +88, +192, +167, +68, +157, +126, +150, +146, +234, +214, +252, +16, +0, +51, +165, +172, +97, +217, +20, +147, +244, +214, +111, +44, +6, +34, +175, +223, +181, +36, +217, +142, +220, +57, +143, +118, +220, +99, +57, +255, +255, +121, +255, +155, +246, +24, +69, +168, +173, +0, +156, +115, +247, +137, +200, +39, +69, +45, +241, +111, +19, +145, +111, +230, +181, +69, +83, +119, +31, +225, +191, +158, +232, +156, +59, +168, +201, +32, +71, +2, +192, +255, +161, +49, +2, +89, +206, +250, +46, +113, +166, +40, +167, +255, +67, +34, +114, +114, +133, +49, +189, +94, +146, +4, +32, +3, +249, +8, +27, +192, +90, +179, +75, +21, +138, +31, +195, +166, +162, +179, +178, +89, +34, +178, +177, +115, +174, +44, +253, +91, +80, +44, +115, +54, +159, +253, +40, +69, +35, +27, +128, +115, +238, +102, +17, +217, +66, +212, +229, +117, +127, +242, +153, +121, +130, +91, +228, +159, +165, +192, +45, +114, +180, +1, +77, +190, +120, +128, +104, +134, +163, +175, +224, +61, +245, +154, +192, +144, +63, +12, +172, +147, +157, +115, +119, +57, +231, +222, +225, +157, +112, +170, +16, +81, +4, +163, +215, +12, +209, +165, +67, +91, +76, +246, +255, +167, +58, +231, +102, +149, +53, +6, +54, +18, +205, +130, +52, +191, +232, +180, +127, +107, +148, +126, +60, +151, +155, +207, +138, +215, +25, +152, +115, +110, +109, +127, +221, +70, +37, +65, +203, +236, +130, +198, +54, +0, +231, +220, +197, +50, +232, +55, +144, +109, +211, +165, +127, +247, +176, +193, +251, +228, +159, +32, +34, +219, +137, +102, +99, +121, +121, +164, +199, +132, +146, +156, +28, +233, +191, +142, +119, +206, +221, +219, +65, +183, +65, +1, +84, +221, +215, +94, +93, +146, +123, +102, +45, +255, +39, +162, +204, +59, +127, +200, +145, +89, +220, +255, +127, +186, +246, +232, +122, +12, +57, +26, +239, +2, +80, +33, +6, +160, +74, +155, +209, +10, +231, +220, +174, +206, +185, +5, +157, +115, +93, +186, +19, +167, +64, +58, +193, +104, +97, +18, +79, +17, +185, +81, +148, +222, +106, +59, +79, +97, +214, +5, +194, +131, +63, +185, +176, +149, +135, +115, +110, +188, +139, +227, +171, +217, +182, +104, +140, +193, +218, +146, +240, +40, +228, +114, +237, +197, +64, +193, +54, +96, +143, +238, +48, +154, +119, +1, +70, +20, +104, +6, +218, +37, +69, +100, +146, +115, +110, +241, +178, +246, +13, +97, +19, +178, +22, +26, +83, +157, +115, +79, +137, +72, +37, +130, +203, +26, +152, +156, +249, +223, +37, +182, +151, +196, +174, +113, +185, +168, +11, +115, +143, +81, +134, +222, +15, +160, +5, +80, +102, +225, +199, +129, +123, +136, +36, +249, +0, +174, +52, +111, +248, +88, +188, +249, +252, +57, +159, +135, +11, +117, +151, +0, +77, +49, +219, +68, +207, +205, +110, +232, +21, +64, +59, +236, +36, +58, +75, +120, +187, +232, +150, +94, +93, +84, +158, +1, +12, +17, +106, +45, +1, +106, +226, +116, +209, +152, +140, +105, +162, +62, +249, +179, +253, +12, +192, +57, +247, +85, +179, +44, +42, +205, +195, +87, +183, +253, +80, +96, +84, +43, +0, +231, +220, +181, +230, +2, +141, +198, +93, +132, +211, +69, +121, +231, +30, +148, +102, +86, +249, +209, +50, +3, +136, +42, +128, +178, +25, +78, +17, +156, +115, +51, +156, +115, +23, +137, +200, +37, +190, +104, +163, +22, +227, +236, +49, +68, +24, +213, +10, +96, +180, +195, +57, +247, +87, +167, +220, +237, +111, +118, +206, +221, +217, +160, +139, +66, +5, +128, +210, +179, +63, +10, +220, +7, +116, +30, +215, +238, +156, +219, +201, +43, +215, +181, +115, +154, +180, +157, +225, +136, +136, +60, +225, +255, +191, +161, +161, +252, +0, +156, +115, +103, +251, +113, +255, +162, +171, +62, +231, +84, +244, +10, +96, +100, +81, +182, +4, +216, +94, +68, +254, +71, +212, +155, +110, +96, +175, +29, +165, +110, +127, +218, +43, +136, +21, +135, +96, +124, +109, +103, +56, +22, +35, +230, +194, +220, +35, +31, +179, +157, +2, +24, +13, +235, +170, +26, +40, +91, +2, +252, +94, +52, +232, +231, +97, +81, +7, +156, +44, +62, +35, +26, +28, +180, +156, +168, +207, +125, +45, +160, +121, +227, +159, +39, +39, +217, +101, +7, +51, +28, +145, +196, +206, +208, +239, +56, +141, +66, +140, +184, +2, +48, +254, +234, +251, +160, +180, +212, +0, +115, +202, +212, +174, +112, +6, +224, +156, +251, +135, +115, +110, +9, +231, +220, +50, +206, +185, +88, +138, +171, +83, +69, +21, +196, +127, +69, +217, +144, +234, +98, +31, +81, +215, +226, +237, +129, +37, +27, +200, +87, +193, +253, +254, +255, +34, +57, +59, +33, +81, +244, +158, +128, +195, +131, +17, +87, +0, +6, +83, +114, +62, +207, +206, +152, +207, +124, +174, +109, +4, +116, +206, +253, +205, +43, +136, +183, +57, +231, +6, +242, +254, +85, +192, +113, +162, +111, +232, +51, +36, +77, +121, +214, +37, +254, +40, +34, +51, +253, +231, +61, +138, +26, +246, +24, +67, +232, +202, +19, +208, +204, +0, +54, +52, +51, +128, +175, +13, +229, +216, +171, +128, +36, +226, +49, +215, +133, +213, +27, +233, +246, +2, +182, +202, +169, +47, +243, +3, +152, +35, +128, +38, +61, +129, +26, +132, +32, +61, +230, +16, +24, +5, +176, +138, +81, +0, +3, +140, +43, +192, +2, +36, +9, +23, +54, +200, +233, +235, +14, +210, +136, +133, +192, +222, +159, +105, +179, +93, +78, +95, +85, +20, +192, +209, +190, +77, +30, +69, +84, +175, +0, +60, +80, +90, +173, +137, +228, +48, +58, +247, +24, +25, +140, +166, +37, +192, +163, +57, +159, +3, +22, +19, +101, +195, +21, +17, +185, +128, +10, +25, +128, +219, +192, +57, +183, +148, +95, +131, +86, +113, +3, +158, +45, +67, +93, +233, +112, +151, +193, +57, +247, +59, +231, +220, +123, +157, +18, +116, +244, +232, +209, +12, +104, +30, +123, +136, +164, +174, +202, +204, +0, +222, +13, +188, +46, +210, +102, +5, +52, +45, +120, +225, +12, +160, +226, +88, +78, +245, +125, +156, +155, +83, +63, +166, +103, +0, +104, +202, +176, +128, +49, +195, +229, +208, +163, +58, +70, +211, +12, +160, +20, +192, +89, +34, +178, +180, +168, +111, +249, +229, +69, +109, +157, +115, +119, +56, +231, +158, +141, +148, +223, +45, +137, +115, +74, +155, +177, +56, +81, +202, +50, +145, +196, +219, +109, +118, +67, +219, +93, +134, +30, +163, +28, +99, +109, +111, +246, +221, +162, +188, +255, +223, +119, +206, +93, +90, +214, +120, +136, +177, +158, +136, +188, +85, +52, +95, +65, +81, +38, +159, +49, +11, +167, +4, +158, +75, +140, +244, +56, +122, +12, +29, +198, +212, +12, +192, +41, +123, +206, +123, +157, +115, +167, +141, +244, +88, +68, +9, +46, +174, +17, +145, +207, +197, +102, +26, +115, +2, +128, +55, +2, +187, +0, +167, +161, +73, +77, +99, +109, +114, +119, +74, +140, +17, +245, +200, +152, +108, +143, +161, +199, +88, +155, +1, +140, +26, +56, +165, +69, +251, +80, +73, +155, +53, +135, +105, +56, +35, +133, +235, +68, +179, +49, +137, +136, +228, +177, +38, +109, +35, +34, +95, +18, +157, +185, +157, +153, +211, +102, +122, +199, +227, +234, +81, +17, +99, +106, +6, +208, +99, +212, +225, +72, +169, +158, +123, +175, +104, +167, +100, +82, +7, +99, +233, +209, +0, +253, +12, +160, +71, +99, +56, +231, +126, +129, +18, +168, +22, +33, +68, +1, +62, +94, +208, +166, +87, +0, +35, +132, +126, +6, +208, +99, +200, +80, +99, +167, +164, +39, +12, +29, +33, +244, +10, +160, +199, +80, +162, +112, +167, +196, +57, +183, +159, +119, +182, +26, +182, +116, +97, +61, +210, +232, +21, +64, +143, +161, +196, +28, +191, +83, +50, +218, +209, +219, +0, +122, +12, +25, +170, +236, +148, +244, +24, +89, +244, +10, +160, +71, +43, +56, +231, +166, +72, +207, +246, +51, +102, +209, +47, +1, +122, +244, +152, +131, +209, +43, +128, +30, +61, +230, +96, +244, +10, +160, +71, +143, +57, +24, +179, +173, +2, +40, +10, +7, +22, +165, +186, +238, +209, +163, +199, +236, +4, +58, +100, +4, +234, +209, +99, +78, +192, +108, +59, +3, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +122, +244, +232, +209, +163, +71, +143, +30, +61, +58, +196, +255, +3, +107, +103, +214, +183, +200, +189, +172, +179, +0, +0, +0, +0, +73, +69, +78, +68, +174, +66, +96, +130, +}; diff --git a/demo/title_font.sv.png b/demo/title_font.sv.png new file mode 100644 index 0000000..6d65e7e Binary files /dev/null and b/demo/title_font.sv.png differ diff --git a/demo/title_font.sv.png.flags b/demo/title_font.sv.png.flags new file mode 100644 index 0000000..5130fd1 --- /dev/null +++ b/demo/title_font.sv.png.flags @@ -0,0 +1 @@ +gen_mipmaps=false