Add files via upload

This commit is contained in:
0000OOOO0000 2020-11-20 17:33:46 +02:00 committed by GitHub
parent 08b88e29fc
commit 774f049e12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 19571 additions and 0 deletions

View file

@ -0,0 +1,125 @@
import bpy
import gpu
import blf
from gpu_extras.batch import batch_for_shader
def RA_modal_Draw(self, context, prefs):
height = bpy.context.region.height
width = bpy.context.region.width
CO = context.object
font_id = 0
#+ text
if CO.RA_Unq_mode == True:
blf.color (font_id,0.9,0.32,0.35,1)
else:
blf.color (font_id,0.85,0.85,0.85,1)
#* Offset
blf.position(font_id, (width/2) - 200, (height/2) - 250, 0)
blf.size(font_id, 20, 60)
blf.draw(font_id, ("{} {}".format("Offset: ",str(round(CO.RA_Offset, 2)))) )
#* Object Selectable
blf.position(font_id, (width/2) + 50, (height/2) - 250, 0)
blf.draw(font_id, ("{} {}".format("Selectable: ",str(CO.RA_Sel_Status))) )
#* Object Number "Count"
blf.position(font_id, (width/2) - 50, (height/2) - 250, 0)
if CO.RA_Unq_mode == True:
blf.color (font_id,0.5,0.5,0.5,1)
else:
blf.color (font_id,0.85,0.85,0.85,1)
blf.draw(font_id, ("{} {}".format("Count: ",str(round(CO.RA_ObjNum, 2)))) )
#* Show/Hide Help
blf.color (font_id,1,1,1,1)
text = "Show/Hide Help 'H'"
blf.position(font_id, (width/2 - blf.dimensions(font_id, text)[0] / 2), (height/2) - 230, 0)
blf.draw(font_id, text)
#+--------------------------------------------------------------+#
#* Unique Mode
blf.color (font_id,0.8,0.4,0.0,1)
text = "Unique Mode: "
blf.position(font_id, (width/2 - 84), (height/2) - 270, 0)
blf.draw(font_id, text)
#-------------------------#
if CO.RA_Unq_mode == True:
blf.color (font_id,0.1,0.94,0.4,1)
unq_text = "Active"
else:
blf.color (font_id,0.6,0.1,0.0,1)
unq_text = "--------"
blf.position(font_id, (width/2 + 34), (height/2) - 270, 0)
blf.draw(font_id, unq_text)
#+--------------------------------------------------------------+#
#* Help
blf.color (font_id,0.6,1,0.6,1)
if prefs.modal_help == True:
lines = ["Reset 'R'",
"Apply 'A'",
"Join 'J' ends radial mode and merges all objects",
"Grab 'G'",
"Unique Mode 'Q' unlinks objects data block",
"'RMB' and Esc to Cancel",
"'Shift' to snap offset",
"'Mouse Wheel' Increase/Decrease Count"
]
for index, l in enumerate(lines):
text = l
blf.position(font_id, (width/2) - 200, (height/2 -200) + 20 * index, 0)
blf.draw(font_id, text)
def RA_draw_B(self, context, prefs):
height = bpy.context.region.height
width = bpy.context.region.width
CO = bpy.context.object
#+-----------------------------------------------------------------------+#
vertices = (
(width/2 - 80 , height/2 - 215),(width/2 + 80, height/2 - 215),
(width/2 - 90, height/2 - 233),( width/2 + 90, height/2 - 233) )
indices = (
(0, 1, 2), (2, 1, 3))
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=indices)
shader.bind()
shader.uniform_float("color", (0.8,0.4,0.0,1))
batch.draw(shader)
#+-----------------------------------------------------------------------+#
vertices = (
(width/2 - 216 , height/2 - 234),(width/2 + 206, height/2 - 234),
(width/2 - 220, height/2 - 254),( width/2 + 200, height/2 - 254) )
indices = (
(0, 1, 2), (2, 1, 3))
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=indices)
shader.bind()
shader.uniform_float("color", (0.15,0.15,0.15,1))
batch.draw(shader)
#+-----------------------------------------------------------------------+#
vertices = (
(width/2 - 96 , height/2 - 253),(width/2 + 96, height/2 - 253),
(width/2 - 86, height/2 - 274),( width/2 + 86, height/2 - 274) )
indices = (
(0, 1, 2), (2, 1, 3))
shader = gpu.shader.from_builtin('2D_UNIFORM_COLOR')
batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=indices)
shader.bind()
shader.uniform_float("color", (0.15,0.15,0.15,1))
batch.draw(shader)

View file

@ -0,0 +1,666 @@
import bpy,math,mathutils,blf,rna_keymap_ui
from .RA_draw_ui import *
from mathutils import Matrix
from bpy.types import (
PropertyGroup,
Menu
)
from bpy.props import (
IntProperty,
FloatProperty,
BoolProperty
)
#// join objects option in modal operator
#// Reset array option in modal operator
#// Modal operator Ui
#// add Radial Array hotkey
#// preferences add hotkey in addon preferences menu
#// addon menu ui
#// add modal selectable toggle
#// add modal apply option
#// add modal ui tooltips
#// add make unique
#// add create collection toggle
bl_info = {
"name" : "R.Array",
"author" : "Syler",
"version": (0, 0, 1, 2),
"description": "Adds Radial Array Operator",
"blender" : (2, 80, 0),
"category" : "Object"
}
#+ handle the keymap
addon_keymaps = []
def add_hotkey():
#* Ctrl Q call R_Array
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
kmi = km.keymap_items.new(R_Array.bl_idname, 'Q', 'PRESS', ctrl=True)
addon_keymaps.append(km)
def remove_hotkey():
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
# clear the list
del addon_keymaps[:]
#--------------------------------------------------------------------------------------#
def RA_Update_Sel_Status(self, context):
if self.RA_Sel_Status == True:
for ob in self.RA_Parent.children:
ob.hide_select = False
if self.RA_Sel_Status == False:
for ob in self.RA_Parent.children:
ob.hide_select = True
def RA_Update_ObjNum(self, context):
if self.RA_Status == True:
if len(self.RA_Parent.children) == self.RA_ObjNum:
pass
#+ Add Objects
if len(self.RA_Parent.children) < self.RA_ObjNum:
object_list = []
object_to_copy = self.RA_Parent.children[0]
# append already existing objects to object list
for c in self.RA_Parent.children:
object_list.append(c)
for i in range (len(self.RA_Parent.children), self.RA_ObjNum):
object_list.append(object_to_copy.copy())
# Add Objects To Collection
for index, ob in enumerate(object_list):
# Reset Matrix
ob.matrix_basis = mathutils.Matrix()
# set object location to RA_Parent + RA_Offset
ob.location[1] = self.RA_Parent.location[1] + self.RA_Parent.RA_Offset
# create angle variable
angle = math.radians(360/self.RA_Parent.RA_ObjNum)
# rotate object
R = mathutils.Matrix.Rotation(angle * (index), 4, 'Z')
T = mathutils.Matrix.Translation([0, 0, 0])
M = T @ R @ T.inverted()
ob.location = M @ ob.location
ob.rotation_euler.rotate(M)
# Parent Object
ob.parent = self.RA_Parent
self.RA_Parent.matrix_parent_inverse = ob.matrix_world.inverted()
ob.RA_Parent = self.RA_Parent
# make objects selectable/unselectable
if self.RA_Sel_Status == True:
ob.hide_select = False
if self.RA_Sel_Status == False:
ob.hide_select = True
# Change Object Name
ob.name = "RA - " + self.RA_Name + " - " + str(index)
# set RA Status
ob.RA_Status = True
# Link object
try:
self.RA_Parent.users_collection[0].objects.link(ob)
#print ("For LINK")
except:
#print ("PASS Linking object to collection failed")
pass
#+ Remove Objects
if len(self.RA_Parent.children) > self.RA_ObjNum:
# deselect all objects
for d in bpy.context.view_layer.objects:
d.select_set(False)
bpy.context.view_layer.objects.active = None
# Make selectable and Select all objects that will be deleted
for i in range (self.RA_ObjNum, len(self.RA_Parent.children)):
self.RA_Parent.children[i].hide_select = False
self.RA_Parent.children[i].select_set(True)
# Delete Objects
bpy.ops.object.delete()
# select control Object
bpy.context.view_layer.objects.active = self.RA_Parent
self.RA_Parent.select_set(True)
for index, ob in enumerate(self.RA_Parent.children):
# Reset Matrix
ob.matrix_basis = mathutils.Matrix()
# set object location to RA_Parent + RA_Offset
ob.location[1] = self.RA_Parent.location[1] + self.RA_Parent.RA_Offset
# create angle variable
angle = math.radians(360/self.RA_Parent.RA_ObjNum)
# rotate object
R = mathutils.Matrix.Rotation(angle * (index), 4, 'Z')
T = mathutils.Matrix.Translation([0, 0, 0])
M = T @ R @ T.inverted()
ob.location = M @ ob.location
ob.rotation_euler.rotate(M)
def RA_Update_Offset(self, context):
if self.RA_Status == True:
for ob in self.RA_Parent.children:
# define variables
loc = mathutils.Vector((0.0, self.RA_Offset, 0.0))
rot = ob.rotation_euler
# rotate location
loc.rotate(rot)
# apply rotation
ob.location = loc
else:
pass
#--------------------------------------------------------------------------------------#
class R_Array(bpy.types.Operator):
bl_idname = 'sop.r_array'
bl_label = 'Radial Array'
bl_description = 'Radial Array S.Operator'
bl_options = {'REGISTER', 'UNDO'}
#?Useless !?
@classmethod
def poll(cls, context):
return True
def execute(self, context):
#Create Bpy.context Variable
C = bpy.context
active_object = C.active_object
# call modal if RA_Status = True
try:
if active_object.RA_Status == True:
bpy.ops.sop.ra_modal('INVOKE_DEFAULT')
return {'FINISHED'}
except:
pass
# Check Selected Cancel if NOT Mesh
if C.selected_objects == [] or C.active_object.type != 'MESH':
self.report({'INFO'}, "No Mesh Selected")
return {'CANCELLED'}
# Create Variables
L_Objects = [] # object list
ob = active_object # active object reference
ob_collections = ob.users_collection # active Object collections
f_name = ob.name # Object Name
point = ob.location.copy() # Middle point
is_col_new = True
# Create New Collection
if bpy.context.preferences.addons[__name__].preferences.col_toggle == True:
for q in bpy.data.collections:
if q.name == "RA -" + f_name:
collection = q
is_col_new = False
try:
for col in ob_collections:
col.objects.unlink(ob)
collection.objects.link(ob)
except:
pass
if is_col_new == True:
# create and link new collection
collection = bpy.data.collections.new(name="RA -" + f_name)
bpy.context.scene.collection.children.link(collection)
print ("NEW")
# Move Object to collection
for col in ob_collections:
col.objects.unlink(ob)
collection.objects.link(ob)
else:
collection = ob_collections[0]
# Create/Location/Name/Status/set RA_Parent/Link Empty and other memery
empty = bpy.data.objects.new( "empty", None )
empty.location = point
empty.name = ".RA - " + ob.name + " - Control Empty"
empty.RA_Status = True
empty.RA_Parent = empty
empty.RA_Name = f_name
empty.RA_Sel_Status = bpy.context.preferences.addons[__name__].preferences.selectable
collection.objects.link(empty)
# Move object
ob.location[1] = ob.location[1] + ob.RA_Offset
# Deselect Active Object and select Control Object
ob.select_set(False)
empty.select_set(True)
# set empty as active object
bpy.context.view_layer.objects.active = empty
# create duplicate objects
for o in range(0, empty.RA_ObjNum):
if o == 0:
L_Objects.append(ob)
if o != 0:
L_Objects.append(ob.copy())
# Add Objects To Collection
for index, ob in enumerate(L_Objects):
# create angle variable
angle = math.radians(360/empty.RA_ObjNum)
# rotate object
R = mathutils.Matrix.Rotation(angle * (index), 4, 'Z')
T = mathutils.Matrix.Translation([0, 0, 0])
M = T @ R @ T.inverted()
ob.location = M @ ob.location
ob.rotation_euler.rotate(M)
# Parent Object
ob.parent = empty
empty.matrix_parent_inverse = ob.matrix_world.inverted()
ob.RA_Parent = empty
# make objects selectable/unselectable
if empty.RA_Sel_Status == True:
ob.hide_select = False
if empty.RA_Sel_Status == False:
ob.hide_select = True
# Change Object Name
ob.name = "RA - " + str(f_name) + " - " + str(index)
# Set RA Status
ob.RA_Status = True
# Link object
try:
collection.objects.link(ob)
#print ("For LINK")
except:
#print ("PASS Linking object to collection failed")
pass
bpy.ops.sop.ra_modal('INVOKE_DEFAULT')
return {'FINISHED'}
#--------------------------------------------------------------------------------------#
class RA_Modal(bpy.types.Operator):
# Change Radial Array
bl_idname = "sop.ra_modal"
bl_label = "Radial Array Modal"
bl_options = {"REGISTER", "UNDO", "BLOCKING", "GRAB_CURSOR", "INTERNAL"} #- add later!?
first_mouse_x: IntProperty()
I_RA_Offset: FloatProperty()
I_RA_ObjNum: IntProperty()
unq_mode: BoolProperty()
def modal(self, context, event):
# context shortcut
C = context
OB = C.object
context.area.tag_redraw() #?
prefs = bpy.context.preferences.addons[__name__].preferences
# -------------------------------------------------------------#
#+ change offset
if event.type == 'MOUSEMOVE' :
delta = self.first_mouse_x - event.mouse_x
if event.shift:
C.object.RA_Offset = round((self.I_RA_Offset + delta * 0.01))
else:
C.object.RA_Offset = self.I_RA_Offset + delta * 0.01
# -------------------------------------------------------------#
#+ add/remove Objects
if event.type == 'WHEELUPMOUSE' and OB.RA_Unq_mode == False:
OB.RA_ObjNum = OB.RA_ObjNum + 1
if event.type == 'WHEELDOWNMOUSE' and OB.RA_Unq_mode == False:
OB.RA_ObjNum = OB.RA_ObjNum - 1
# -------------------------------------------------------------#
#+ call the tarnslation operator
if event.type == 'G' and event.value == "PRESS":
C.tool_settings.use_snap = True
C.tool_settings.snap_elements = {'FACE'}
C.tool_settings.use_snap_align_rotation = True
bpy.ops.transform.translate('INVOKE_DEFAULT')
bpy.types.SpaceView3D.draw_handler_remove(self.ra_draw_b, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'FINISHED'}
# -------------------------------------------------------------#
#+ join objects
if event.type == 'J' and event.value == "PRESS":
objects = OB.RA_Parent.children
location = OB.RA_Parent.location
cursor_location = bpy.context.scene.cursor.location.copy()
# deselect objects and select control object
for o in C.selected_objects:
o.select_set(False)
C.object.RA_Parent.hide_select = False
bpy.context.view_layer.objects.active = C.object.RA_Parent
C.object.RA_Parent.select_set(True)
# Delete control object
bpy.ops.object.delete()
for ob in objects:
ob.hide_select = False
ob.select_set(True)
bpy.context.view_layer.objects.active = objects[0]
bpy.context.scene.cursor.location = location
bpy.ops.view3d.snap_selected_to_cursor(use_offset=True)
bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM')
bpy.ops.object.join()
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
bpy.context.scene.cursor.location = cursor_location
bpy.types.SpaceView3D.draw_handler_remove(self.ra_draw_b, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'FINISHED'}
# -------------------------------------------------------------#
#+ Reset
if event.type == 'R' and event.value == "PRESS":
objects = OB.RA_Parent.children
name = OB.RA_Parent.RA_Name
# deslect all objects
for o in C.selected_objects:
o.select_set(False)
# select objects
for ob in objects:
if ob != objects[0]:
ob.hide_select = False
ob.select_set(True)
# delete objects
bpy.ops.object.delete()
# select object and clear parent and other memery
objects[0].location = objects[0].RA_Parent.location
objects[0].RA_Parent.select_set(True)
bpy.ops.object.delete()
objects[0].hide_select = False
bpy.context.view_layer.objects.active = objects[0]
objects[0].select_set(True)
objects[0].parent = None
objects[0].name = name
try:
del objects[0]["RA_Parent"]
del objects[0]["RA_Status"]
except:
pass
bpy.types.SpaceView3D.draw_handler_remove(self.ra_draw_b, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'FINISHED'}
#+ Apply
if event.type == 'A' and event.value == "PRESS":
objects = OB.RA_Parent.children
# deslect all objects
for o in C.selected_objects:
o.select_set(False)
# select and delete control object
objects[0].RA_Parent.select_set(True)
bpy.ops.object.delete()
# select objects
for ob in objects:
ob.hide_select = False
ob.select_set(True)
ob.RA_Status = False
ob.parent = None
bpy.context.view_layer.objects.active = objects[0]
bpy.types.SpaceView3D.draw_handler_remove(self.ra_draw_b, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'FINISHED'}
#+ Make Unique Mode toggle
if event.type == 'Q' and event.value == "PRESS":
objects = OB.RA_Parent.children
if OB.RA_Unq_mode == True:
for ob in objects:
ob.data = objects[0].data
OB.RA_Unq_mode = False
else:
#* make unique data
for ob in objects:
ob.data = ob.data.copy()
OB.RA_Unq_mode = True
#+ Selectable toggle
if event.type == 'S' and event.value == "PRESS":
if OB.RA_Sel_Status == True:
OB.RA_Sel_Status = False
else:
OB.RA_Sel_Status = True
#+ Help Mode toggle
if event.type == 'H' and event.value == "PRESS":
if prefs.modal_help == True:
prefs.modal_help = False
else:
prefs.modal_help = True
# -------------------------------------------------------------#
#+ Finish/Cancel Modal
elif event.type == 'LEFTMOUSE':
bpy.types.SpaceView3D.draw_handler_remove(self.ra_draw_b, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'FINISHED'}
elif event.type in {'RIGHTMOUSE', 'ESC'}:
C.object.RA_Offset = self.I_RA_Offset
C.object.RA_ObjNum = self.I_RA_ObjNum
bpy.types.SpaceView3D.draw_handler_remove(self.ra_draw_b, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
return {'CANCELLED'}
return {'RUNNING_MODAL'}
def invoke(self, context, event):
# context shortcut
C = context
if C.object.RA_Status == True:
for o in C.selected_objects:
o.select_set(False)
bpy.context.view_layer.objects.active = C.object.RA_Parent
C.object.RA_Parent.select_set(True)
if C.object:
# set initial Variable values
self.first_mouse_x = event.mouse_x
self.I_RA_Offset = C.object.RA_Offset
self.I_RA_ObjNum = C.object.RA_ObjNum
self.unq_mode = C.object.RA_Unq_mode
self.prefs = bpy.context.preferences.addons[__name__].preferences
###-------------------------------------------###
args = (self, context, self.prefs)
self.ra_draw_b = bpy.types.SpaceView3D.draw_handler_add(RA_draw_B, args, 'WINDOW', 'POST_PIXEL')
self._handle = bpy.types.SpaceView3D.draw_handler_add(RA_modal_Draw, args, 'WINDOW', 'POST_PIXEL')
self.mouse_path = []
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
self.report({'WARNING'}, "No active object, could not finish")
return {'CANCELLED'}
#--------------------------------------------------------------------------------------#
class RA_Prefs(bpy.types.AddonPreferences):
bl_idname = __name__
# here you define the addons customizable props
offset: bpy.props.FloatProperty(default=5)
objnum: bpy.props.IntProperty(default=6)
selectable: bpy.props.BoolProperty(default= True, description="False = Only Control Object is selectable")
modal_help: bpy.props.BoolProperty(default= False, description="True = Display Help text in modal")
col_toggle: bpy.props.BoolProperty(default= False, description="True = Create New Collection")
# here you specify how they are drawn
def draw(self, context):
layout = self.layout
box = layout.box()
split = box.split()
col = split.column()
# Layout ---------------------------------------------------------------- #
col.label(text="Default Values:")
col.prop(self, "offset",text="Default Offset")
col.prop(self, "objnum",text="Default Count")
col.prop(self, "selectable",text="Selectable")
col.prop(self, "modal_help",text="Modal Help")
col.label(text ="Options:")
col.prop(self, "col_toggle",text="Create New Collection")
col.label(text="Keymap:")
wm = bpy.context.window_manager
kc = wm.keyconfigs.user
km = kc.keymaps['Object Mode']
#kmi = km.keymap_items[0]
kmi = get_hotkey_entry_item(km, 'sop.r_array', 'sop.r_array')
if addon_keymaps:
km = addon_keymaps[0].active()
col.context_pointer_set("keymap", km)
rna_keymap_ui.draw_kmi([], kc, km, kmi, col, 0)
def get_addon_preferences():
''' quick wrapper for referencing addon preferences '''
addon_preferences = bpy.context.user_preferences.addons[__name__].preferences
return addon_preferences
def get_hotkey_entry_item(km, kmi_name, kmi_value):
'''
returns hotkey of specific type, with specific properties.name (keymap is not a dict, so referencing by keys is not enough
if there are multiple hotkeys!)
'''
for i, km_item in enumerate(km.keymap_items):
if km.keymap_items.keys()[i] == kmi_name:
if km.keymap_items[i].idname == kmi_value:
return km_item
return None
classes = (
RA_Prefs,
R_Array,
RA_Modal,
)
def register():
print ("----------------------------------")
print ("S.Ops Init")
print ("----------------------------------")
#+ add hotkey
add_hotkey()
from bpy.utils import register_class
for cls in classes:
register_class(cls)
# Init Props
bpy.types.Object.RA_Parent = bpy.props.PointerProperty(
name="RA Parent",
description="RA Parent Object Reference",
type=bpy.types.Object
)
bpy.types.Object.RA_ObjNum = bpy.props.IntProperty(
name="RA ObjNum",
description="RA Object Number",
default = bpy.context.preferences.addons[__name__].preferences.objnum,
min = 1,
update = RA_Update_ObjNum
)
bpy.types.Object.RA_Offset = bpy.props.FloatProperty(
name="Offset",
description="Radial Array Offset",
default = bpy.context.preferences.addons[__name__].preferences.offset,
update = RA_Update_Offset
)
bpy.types.Object.RA_Status = bpy.props.BoolProperty(
name="Status",
description="Radial Array Status",
default = False
)
bpy.types.Object.RA_Sel_Status = bpy.props.BoolProperty(
name="Selectable",
description="False = Only Control Object is selectable",
default = bpy.context.preferences.addons[__name__].preferences.selectable,
update = RA_Update_Sel_Status
)
bpy.types.Object.RA_Unq_mode = bpy.props.BoolProperty(
name="Unique Mode",
description="True = all objects have a unique data block(Disables Count in Modal)",
default = False
)
bpy.types.Object.RA_Name = bpy.props.StringProperty(
name="Name",
description="Radial Array Name",
default = "Nameing Error"
)
print ("----------------------------------")
print ("S.Ops Register End")
print ("----------------------------------")
def unregister():
print ("----------------------------------")
print ("S.Ops unRegister Start")
print ("----------------------------------")
#+ remove hotkey
remove_hotkey()
from bpy.utils import unregister_class
for cls in classes:
unregister_class(cls)
print ("----------------------------------")
print ("S.Ops unRegister End")
print ("----------------------------------")
if __name__ == "__main__":
register()