| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666 |
- #################################################################
- # collisionWindow.py
- # Written by Yi-Hong Lin, [email protected], 2004
- #################################################################
- # Import Tkinter, Pmw, and the floater code from this directory tree.
- from direct.tkwidgets.AppShell import *
- from direct.showbase.TkGlobal import *
- from tkSimpleDialog import askfloat
- import string
- import math
- import types
- from direct.task import Task
- FRAMES = 0
- SECONDS = 1
- #####################################################################################
- # BlendAnimPanel(AppShell)
- # This Panel will allow user to blend tow animations
- # that have already been loaded for this actor.
- # user can play and manipulate this blended animation
- # just like in the animation panel. And, they can save this blended animation.
- #####################################################################################
- class BlendAnimPanel(AppShell):
- # Override class variables
- appname = 'Blend Anim Panel'
- frameWidth = 575
- frameHeight = 450
- usecommandarea = 0
- usestatusarea = 0
- index = 0
- dragMode = False
- blendRatio = 0
- rateList= ['1/24.0', '0.1', '0.5', '1.0', '2.0', '5.0' , '10.0']
- enableBlend = False
- currentBlendName = None
-
- def __init__(self, aNode = None, blendDict={}, parent = None, **kw):
- INITOPT = Pmw.INITOPT
- self.id = 'BlendAnimPanel '+ aNode.getName()
- self.appname = self.id
- self.actorNode = aNode
- self.blendDict = blendDict.copy()
- if len(blendDict)>0:
- self.blendList = blendDict.keys()
- else:
- self.blendList = []
- optiondefs = (
- ('title', self.appname, None),
- ('actor', aNode, None),
- ('animList', [], None),
- ('blendAnimList', self.blendList, None),
- )
- self.defineoptions(kw, optiondefs)
- self.id = 'Blend AnimPanel '+ aNode.getName()
- self.nodeName = aNode.getName()
- # Initialize the superclass
- AppShell.__init__(self)
- # Execute option callbacks
- self.initialiseoptions(BlendAnimPanel)
- self.currTime = 0.0
- self.animNameA = None
- self.animNameB = None
- self.parent.resizable(False,False) ## Disable the ability to resize for this Window.
- def createInterface(self):
- # Handle to the toplevels interior
- interior = self.interior()
- self.menuBar.destroy()
- # show the actor's name
- actorFrame = Frame(interior)
- name_label = Label(actorFrame, text= self.nodeName,font=('MSSansSerif', 14),
- relief = SUNKEN, borderwidth=3)
- name_label.pack(side = TOP, expand = False)
- actorFrame.pack(side = TOP, expand = False, fill = X)
- # Create a frame to show is there any ore-blended animation and save, edit, rename button.
- group = Pmw.Group(interior, tag_pyclass=None)
- actorFrame = group.interior()
- group.pack(side = TOP, expand = False, fill = X)
- Label(actorFrame, text= "Blended:", font=('MSSansSerif', 10)).pack(side=LEFT)
- self.blendAnimEntry = self.createcomponent(
- 'Blended Animation', (), None,
- Pmw.ComboBox, (actorFrame,),
- labelpos = W, entry_width = 20, selectioncommand = self.setBlendAnim,
- scrolledlist_items = self['blendAnimList'])
- self.blendAnimEntry.pack(side=LEFT)
- Label(actorFrame, text= " ", font=('MSSansSerif', 10)).pack(side=LEFT)
-
- button = Button(actorFrame, text="Save", font=('MSSansSerif', 10),width = 12,
- command = self.saveButtonPushed).pack(side=LEFT)
- button = Button(actorFrame, text="Remove", font=('MSSansSerif', 10),width = 12,
- command = self.removeButtonPushed).pack(side=LEFT)
- button = Button(actorFrame, text="Rename", font=('MSSansSerif', 10),width = 12,
- command = self.renameButtonPushed).pack(side=LEFT)
- actorFrame.pack(side = TOP, expand = False, fill = X)
- # Create a frame to hold all the animation setting
- group = Pmw.Group(interior, tag_pyclass=None)
- actorFrame = group.interior()
- group.pack(side = TOP, expand = False, fill = X)
- Label(actorFrame, text= "Animation A:", font=('MSSansSerif', 10)).pack(side=LEFT)
- self['animList'] = self['actor'].getAnimNames()
- self.AnimEntryA = self.createcomponent(
- 'AnimationMenuA', (), None,
- Pmw.ComboBox, (actorFrame,),
- labelpos = W, entry_width = 20, entry_state = DISABLED,
- selectioncommand = lambda name, a = 'a' : self.setAnimation(name, AB=a),
- scrolledlist_items = self['animList'])
- self.AnimEntryA.pack(side=LEFT)
- Label(actorFrame, text= " ", font=('MSSansSerif', 10)).pack(side=LEFT,)
- Label(actorFrame, text= "Animation B:", font=('MSSansSerif', 10)).pack(side=LEFT)
- self['animList'] = self['actor'].getAnimNames()
- self.AnimEntryB = self.createcomponent(
- 'AnimationMenuB', (), None,
- Pmw.ComboBox, (actorFrame,),
- labelpos = W, entry_width = 20, entry_state = DISABLED,
- selectioncommand = lambda name, a = 'b' : self.setAnimation(name, AB=a),
- scrolledlist_items = self['animList'])
- self.AnimEntryB.pack(side=LEFT)
- actorFrame.pack(side = TOP, expand = False, fill = X)
-
- ### Blend Enable checkbox
- actorFrame = Frame(interior, relief = SUNKEN, bd = 1)
- Label(actorFrame, text= "Enable Blending:", font=('MSSansSerif', 10)).pack(side=LEFT,)
- self.blendVar = IntVar()
- self.blendVar.set(0)
- self.blendButton = self.createcomponent(
- 'blendButton', (), None,
- Checkbutton, (actorFrame,),
- variable = self.blendVar,
- command = self.toggleBlend)
- self.blendButton.pack(side=LEFT)
- actorFrame.pack(side = TOP, expand = False, fill = X)
- ## Ratio control
- actorFrame = Frame(interior)
- frameFrame = Frame(actorFrame, relief = SUNKEN, bd = 1)
- minRatioLabel = self.createcomponent(
- 'minRatioLabel', (), 'sLabel',
- Label, (frameFrame,),
- text = 0.00)
- minRatioLabel.pack(side = LEFT)
- self.ratioControl = self.createcomponent(
- 'ratio', (), None,
- Scale, (frameFrame,),
- from_ = 0.0, to = 1.0, resolution = 0.01,
- command = self.setRatio, length = 500,
- orient = HORIZONTAL, showvalue = 1)
- self.ratioControl.pack(side = LEFT, expand = 1)
- self.ratioControl.set(1.0)
- self.maxRatioLabel = self.createcomponent(
- 'maxRatioLabel', (), 'sLabel',
- Label, (frameFrame,),
- text = 1.00)
- self.maxRatioLabel.pack(side = LEFT)
- frameFrame.pack(side = LEFT, expand = 1, fill = X)
- actorFrame.pack(side = TOP, expand = True, fill = X)
- ###################################################################################
- ###################################################################################
- actorFrame = Frame(interior)
- Label(actorFrame, text= "Play Rate:", font=('MSSansSerif', 10)).pack(side=LEFT)
- self.playRateEntry = self.createcomponent(
- 'playRateMenu', (), None,
- Pmw.ComboBox, (actorFrame,),
- labelpos = W, entry_width = 20, selectioncommand = self.setPlayRate,
- scrolledlist_items = self.rateList)
- self.playRateEntry.pack(side=LEFT)
- self.playRateEntry.selectitem('1.0')
- ### Loop checkbox
- Label(actorFrame, text= " ", font=('MSSansSerif', 10)).pack(side=LEFT,)
- Label(actorFrame, text= "Loop:", font=('MSSansSerif', 10)).pack(side=LEFT,)
- self.loopVar = IntVar()
- self.loopVar.set(0)
- self.loopButton = self.createcomponent(
- 'loopButton', (), None,
- Checkbutton, (actorFrame,),
- variable = self.loopVar)
- self.loopButton.pack(side=LEFT)
-
- actorFrame.pack(side = TOP, expand = True, fill = X)
-
-
- ### Display Frames/Seconds
- actorFrame = Frame(interior)
-
- Label(actorFrame, text= "Frame/Second:", font=('MSSansSerif', 10)).pack(side=LEFT)
- self.unitsVar = IntVar()
- self.unitsVar.set(FRAMES)
- self.displayButton = self.createcomponent(
- 'displayButton', (), None,
- Checkbutton, (actorFrame,),
- command = self.updateDisplay,
- variable = self.unitsVar)
- self.displayButton.pack(side=LEFT)
- actorFrame.pack(side = TOP, expand = True, fill = X)
-
- ## scale control
- actorFrame = Frame(interior)
- frameFrame = Frame(actorFrame, relief = SUNKEN, bd = 1)
- self.minLabel = self.createcomponent(
- 'minLabel', (), 'sLabel',
- Label, (frameFrame,),
- text = 0)
- self.minLabel.pack(side = LEFT)
- self.frameControl = self.createcomponent(
- 'scale', (), None,
- Scale, (frameFrame,),
- from_ = 0, to = 24, resolution = 1.0,
- command = self.goTo, length = 500,
- orient = HORIZONTAL, showvalue = 1)
- self.frameControl.pack(side = LEFT, expand = 1)
- self.frameControl.bind('<Button-1>', self.onPress)
- self.frameControl.bind('<ButtonRelease-1>', self.onRelease)
- self.maxLabel = self.createcomponent(
- 'maxLabel', (), 'sLabel',
- Label, (frameFrame,),
- text = 24)
- self.maxLabel.pack(side = LEFT)
- frameFrame.pack(side = LEFT, expand = 1, fill = X)
- actorFrame.pack(side = TOP, expand = True, fill = X)
-
- ## button contorl
- actorFrame = Frame(interior)
- ButtomFrame = Frame(actorFrame, relief = SUNKEN, bd = 1,borderwidth=5)
- self.toStartButton = self.createcomponent(
- 'toStart', (), None,
- Button, (ButtomFrame,),
- text = '<<',
- width = 8,
- command = self.resetAllToZero)
- self.toStartButton.pack(side = LEFT, expand = 1, fill = X)
-
- self.playButton = self.createcomponent(
- 'playButton', (), None,
- Button, (ButtomFrame,),
- text = 'Play', width = 8,
- command = self.play)
- self.playButton.pack(side = LEFT, expand = 1, fill = X)
- self.stopButton = self.createcomponent(
- 'stopButton', (), None,
- Button, (ButtomFrame,),
- text = 'Stop', width = 8, state=DISABLED,
- command = self.stop)
- self.stopButton.pack(side = LEFT, expand = 1, fill = X)
- self.toEndButton = self.createcomponent(
- 'toEnd', (), None,
- Button, (ButtomFrame,),
- text = '>>',
- width = 8,
- command = self.resetAllToEnd)
- self.toEndButton.pack(side = LEFT, expand = 1, fill = X)
- ButtomFrame.pack(side = TOP, expand = True, fill = X)
- actorFrame.pack(expand = 1, fill = BOTH)
- def updateList(self):
- #################################################################
- # updateList(self)
- # This will reset the list of all animations that this actor has
- # to the animation entry A and B.
- #################################################################
- self['animList'] = self['actor'].getAnimNames()
- animL = self['actor'].getAnimNames()
- self.AnimEntryA.setlist(animL)
- self.AnimEntryB.setlist(animL)
-
- def play(self):
- #################################################################
- # play(self)
- # It works pretty much like what we have in the Animation Panel.
- # The only different now is that we set two "pose" here.
- # When you do the blending animation by setPose, you don't have
- # to set them simultaneously.
- #################################################################
- self.animNameA = self.AnimEntryA.get()
- self.animNameB = self.AnimEntryB.get()
- if (self.animNameA in self['animList'])and(self.animNameB in self['animList']):
- self.playButton.config(state=DISABLED)
- self.lastT = globalClock.getFrameTime()
- taskMgr.add(self.playTask, self.id + '_UpdateTask')
- self.stopButton.config(state=NORMAL)
- else:
- print '----Illegal Animaion name!!', self.animNameA + ', '+ self.animNameB
- return
- def playTask(self, task):
- #################################################################
- # playTask(self, task)
- # see play(self)
- #################################################################
- fLoop = self.loopVar.get()
- currT = globalClock.getFrameTime()
- deltaT = currT - self.lastT
- self.lastT = currT
- if self.dragMode:
- return Task.cont
- self.currTime = self.currTime + deltaT
- if (self.currTime > self.maxSeconds):
- if fLoop:
- self.currTime = self.currTime%self.duration
- self.gotoT(self.currTime)
- else:
- self.currTime = 0.0
- self.gotoT(0.0)
- self.playButton.config(state=NORMAL)
- self.stopButton.config(state=DISABLED)
- return Task.done
- else:
- self.gotoT(self.currTime)
- return Task.cont
- def stop(self):
- #################################################################
- # stop(self)
- # see play(self)
- #################################################################
- taskMgr.remove(self.id + '_UpdateTask')
- self.playButton.config(state=NORMAL)
- self.stopButton.config(state=DISABLED)
- return
- def setAnimation(self, animation, AB = 'a'):
- #################################################################
- # setAnimation(self, animation, AB = 'a')
- # see play(self)
- #################################################################
- print 'OK!!!'
- if AB == 'a':
- if self.animNameA != None:
- self['actor'].setControlEffect(self.animNameA, 1.0, 'modelRoot','lodRoot')
- self.animNameA = self.AnimEntryA.get()
- else:
- if self.animNameB != None:
- self['actor'].setControlEffect(self.animNameB, 1.0, 'modelRoot','lodRoot')
- self.animNameB = self.AnimEntryB.get()
- self.currTime = 0.0
- self.frameControl.set(0)
- self.updateDisplay()
- self.setRatio(self.blendRatio)
- return
- def setPlayRate(self,rate):
- #################################################################
- # setPlayRate(self,rate)
- # see play(self)
- #################################################################
- self.animNameA = self.AnimEntryA.get()
- if self.animNameA in self['animList']:
- self['actor'].setPlayRate(eval(rate), self.animNameA)
- self.updateDisplay()
- if self.animNameB in self['animList']:
- self['actor'].setPlayRate(eval(rate), self.animNameB)
- self.updateDisplay()
- return
- def updateDisplay(self):
- #################################################################
- # updateDisplay(self)
- # see play(self)
- #################################################################
- if not (self.animNameA in self['animList']):
- return
- self.fps = self['actor'].getFrameRate(self.animNameA)
- self.duration = self['actor'].getDuration(self.animNameA)
- self.maxFrame = self['actor'].getNumFrames(self.animNameA) - 1
- if not (self.animNameB in self['animList']):
- return
- if self.duration > self['actor'].getDuration(self.animNameB):
- self.duration = self['actor'].getDuration(self.animNameB)
- if self.maxFrame > self['actor'].getNumFrames(self.animNameB) - 1:
- self.maxFrame = self['actor'].getNumFrames(self.animNameB) - 1
- self.maxSeconds = self.duration
- if self.unitsVar.get() == FRAMES:
- fromFrame = 0
- toFrame = self.maxFrame
- self.minLabel['text'] = fromFrame
- self.maxLabel['text'] = toFrame
- self.frameControl.configure(from_ = fromFrame,
- to = toFrame,
- resolution = 1.0)
- else:
- self.minLabel['text'] = '0.0'
- self.maxLabel['text'] = "%.2f" % self.duration
- self.frameControl.configure(from_ = 0.0,
- to = self.duration,
- resolution = 0.01)
- def gotoT(self,time):
- #################################################################
- # gotoT(self,time)
- # see play(self)
- #################################################################
- if self.unitsVar.get() == FRAMES:
- self.frameControl.set(time * self.fps)
- else:
- self.frameControl.set(time)
- return
- def goTo(self,frame):
- #################################################################
- # goTo(self,frame)
- # see play(self)
- #################################################################
- if (self.animNameA in self['animList'])and(self.animNameB in self['animList']):
- # Convert scale value to float
- frame = string.atof(frame)
- # Now convert t to seconds for offset calculations
- if self.unitsVar.get() == FRAMES:
- frame = frame / self.fps
- if self.dragMode:
- self.currTime = frame
- self['actor'].pose(self.animNameA,
- min(self.maxFrame, int(frame * self.fps)))
- self['actor'].pose(self.animNameB,
- min(self.maxFrame, int(frame * self.fps)))
- return
- def onRelease(self,frame):
- #################################################################
- # onRelease(self,frame)
- # see play(self)
- #################################################################
- self.dragMode = False
- return
- def onPress(self,frame):
- #################################################################
- # onPress(self,frame)
- # see play(self)
- #################################################################
- self.dragMode = True
- return
-
- def resetAllToZero(self):
- #################################################################
- # resetAllToZero(self)
- # see play(self)
- #################################################################
- self.currTime = 0.0
- self.gotoT(0)
- return
- def resetAllToEnd(self):
- #################################################################
- # resetAllToEnd(self)
- # see play(self)
- #################################################################
- self.currTime = self.maxSeconds
- self.gotoT(self.duration)
- return
- def toggleBlend(self):
- #################################################################
- # toggleBlend(self)
- # This function will enable the blending option for the actor.
- # and call set ratio function to set the blending animation mixing in
- # current ratio.
- #
- # This blending enable will not be keep when you close the window!
- #
- #################################################################
- if self.blendVar.get():
- self.enableBlend = True
- self['actor'].enableBlend()
- self.setRatio(self.blendRatio)
- else:
- self.enableBlend = False
- self['actor'].disableBlend()
- return
- def setRatio(self, ratio):
- #################################################################
- # setRatio(self, ratio)
- # callback funtion
- # This one will be called each time when user drag the blend ratio
- # slider on the panel. This will set the blening ratio to both animation.
- # (Which is "setControlEffect")
- #################################################################
- self.blendRatio = float(ratio)
- if self.enableBlend:
- if self.animNameA in self['animList']:
- self['actor'].setControlEffect(self.animNameA, self.blendRatio, 'modelRoot','lodRoot')
- if self.animNameB in self['animList']:
- self['actor'].setControlEffect(self.animNameB, 1-self.blendRatio, 'modelRoot','lodRoot')
- return
- def setBlendAnim(self, name):
- #################################################################
- # setBlendAnim(self, name)
- # This function will be called each time when user try to select
- # a existing blending animation from the comboBox on the panel
- # This function will re-set every varaibles on the panel to what
- # it should be. For example, when user choose blending anim "R,"
- # which was blended by anim "a" and "b" with ratio "c,"
- # then this function will set Animation A to "a" and animation B
- # to "b" and set the ratio slider to "c" position.
- #################################################################
- if self.blendDict.has_key(name):
- self.currentBlendName = name
- animA = self.blendDict[name][0]
- animB = self.blendDict[name][1]
- ratio = self.blendDict[name][2]
- self.AnimEntryA.selectitem(animA)
- self.AnimEntryB.selectitem(animB)
- self.setAnimation(animA, AB = 'a')
- self.setAnimation(animB, AB = 'b')
- self.ratioControl.set(ratio)
- return
- def setBlendAnimList(self, dict, select=False):
- #################################################################
- # setBlendAnimList(self, dict, select=False)
- # This function will be called when we need to reset the dropdown list
- # of "Blend Anim."
- # About "selec" option, this now is mainly used when we remove
- # a blended animation from the actor. When it has been specified to True,
- # the function will not only reset the list, but will also automatically
- # select one from the top of list, if it is not empty.
- #################################################################
- self.blendDict.clear()
- del self.blendDict
- self.blendDict = dict.copy()
- print self.blendDict
- if len(self.blendDict)>0:
- self.blendList = self.blendDict.keys()
- else:
- self.blendList = []
- self.blendAnimEntry.setlist(self.blendList)
- if select:
- if len(self.blendList)>0:
- self.blendAnimEntry.selectitem(self.blendList[0])
- self.setBlendAnim(self.blendList[0])
- self.currentBlendName = self.blendList[0]
- else:
- self.blendAnimEntry.clear()
- self.currentBlendName = None
- return
-
- def saveButtonPushed(self):
- #################################################################
- # saveButtonPushed(self)
- # This function will be called when user clicked on the "Save" button
- # This functiont will collect all data on the panel and send them with
- # a message to sceneEditor to save the current blending animation
- # into the dataHolder.
- #################################################################
- name = self.blendAnimEntry.get()
- if name=='':
- Pmw.MessageDialog(None, title='Caution!',
- message_text = 'You have to give the blending animation a name first!',
- iconpos='s',
- defaultbutton = 'Close'
- )
- return
- elif (not(self.animNameA in self['animList']))or(not(self.animNameB in self['animList'])):
- Pmw.MessageDialog(None, title='Caution!',
- message_text = 'The Animations you have selected are not exist!',
- iconpos='s',
- defaultbutton = 'Close'
- )
- return
- else:
- messenger.send('BAW_saveBlendAnim', [self['actor'].getName(),
- name,
- self.animNameA,
- self.animNameB,
- self.blendRatio])
- self.currentBlendName = name
- return
- def removeButtonPushed(self):
- #################################################################
- # removeButtonPushed(self)
- # remove the current seleted blended animation from the actor.
- # This will send out a message to sceneEditor to delete the data inside
- # the dataHolder and then reset the list of here.
- #################################################################
- name = self.blendAnimEntry.get()
- messenger.send('BAW_removeBlendAnim', [self['actor'].getName(),name])
- return
- def renameButtonPushed(self):
- #################################################################
- # renameButtonPushed(self)
- # this function will be called when user click on the "Rename" button.
- # This function will collect all data on the panel and send them out
- # with a message to sceneEditor to rename and re-save all setting about
- # current animation.
- #################################################################
- oName = self.currentBlendName
- name = self.blendAnimEntry.get()
- if self.currentBlendName == None:
- Pmw.MessageDialog(None, title='Caution!',
- message_text = "You haven't select any blended animation!!",
- iconpos='s',
- defaultbutton = 'Close'
- )
- return
- elif name=='':
- Pmw.MessageDialog(None, title='Caution!',
- message_text = 'You have to give the blending animation a name first!',
- iconpos='s',
- defaultbutton = 'Close'
- )
- return
- elif (not(self.animNameA in self['animList']))or(not(self.animNameB in self['animList'])):
- Pmw.MessageDialog(None, title='Caution!',
- message_text = 'The Animations you have selected are not exist!',
- iconpos='s',
- defaultbutton = 'Close'
- )
- return
- else:
- messenger.send('BAW_renameBlendAnim', [self['actor'].getName(),
- name,
- oName,
- self.animNameA,
- self.animNameB,
- self.blendRatio]
- )
- self.currentBlendName = name
- return
- def onDestroy(self, event):
- #################################################################
- # onDestroy(self, event)
- # This function will be call when user try to close the window.
- # In here we will stop all tasks we have opend and disable the
- # blend setting of actor.
- # If we didn't disable the blend option, the next time you play
- # the animation via animation panel will cause some error.
- #################################################################
- if taskMgr.hasTaskNamed(self.id + '_UpdateTask'):
- taskMgr.remove(self.id + '_UpdateTask')
- messenger.send('BAW_close',[self.nodeName])
- self.actorNode.setControlEffect(self.animNameA, 1.0, 'modelRoot','lodRoot')
- self.actorNode.setControlEffect(self.animNameB, 1.0, 'modelRoot','lodRoot')
- self.actorNode.disableBlend()
- '''
- If you have open any thing, please rewrite here!
- '''
- pass
|