New AutoFindMixin Class

Hi folks,

Another try for a Autofind Mixin class.

wx.ComboBox, wx.Choice and wx.ListCtrl (only single selection) supported.
You can try it, if you change the commented code.

Added four common function, which should work depending
on the type of the control:

def GetSelectedItem(self):
def SetSelectedItem(self, index):
def GetItemString(self, index):
def GetNrEntries(self):

Does it work on Linux?

For suggestions (of the code itself, the code style or another ideas, bugs),
I would be glad to hear.

···

========================================================================================

#!/usr/bin/env python

# Franz Steinhaeusler, 09.05.2006
# AutoFindMixin.py

import wx

class AutoFindMixin:
    """AutoFindMixin: it will search for elements which fits a whole typed in word fragment."""
    def __init__(self, parent, showbuffer=False):
        """Creates the AutoFindMixin Class."""
        # taken from listctrl Mixins class
        self.control = control = self.GetControl()
        if not control:
            raise ValueError, "No Control available"
        else:
            if isinstance(control, wx.Choice) or \
               isinstance(control, wx.ComboBox) or \
               isinstance(control, wx.ListCtrl):
                #print "ok", control
                pass
            else:
                raise ValueError, "Not supported control:", control

        self.keybuffer = ""
        self.showbuffer = showbuffer
        self.lastpos = self.GetSelectedItem()

        if showbuffer:
            # create a static text to show current keybuffer.
            x, y = self.GetPosition()
            w, h = self.GetSize()
            self.StaticText = wx.StaticText(parent, pos=(x+w+5,y+3))
            self.StaticText.SetBackgroundColour(wx.Colour(255, 255, 192))

        # bind the contrrol
        control.Bind(wx.EVT_CHAR, self.OnChar)
        control.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
        control.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)

        self.Bind(wx.EVT_CHOICE, self.OnChoice)
        
    def GetSelectedItem(self):
        """Get index of the currently selected item."""
        if isinstance(self.control, wx.ListCtrl):
            return self.control.GetNextItem(-1, wx.LIST_NEXT_ALL,
                                            wx.LIST_STATE_SELECTED)
        else:
            return self.control.GetSelection()
        pass
        
    def SetSelectedItem(self, index):
        """Set active item to the given index."""
        if isinstance(self.control, wx.ListCtrl):
            self.SetItemState(index, wx.LIST_STATE_SELECTED|wx.LIST_STATE_FOCUSED,
                              wx.LIST_STATE_SELECTED|wx.LIST_STATE_FOCUSED)
            pass
        else:
            self.SetSelection(index)
            pass

    def GetItemString(self, index):
        """Get Currently selected item of the AutoFindMixin control."""
        if isinstance(self.control, wx.ListCtrl):
            return self.control.GetItem(index, 0).GetText()
        else:
            return self.control.GetString(index)
        
    def GetNrEntries(self):
        """Get Number of Entries of the AutoFindMixin control."""
        if isinstance(self.control, wx.ListCtrl):
            return self.control.GetItemCount()
        else:
            return self.control.GetCount()

    def OnKillFocus(self, event):
        """AutoFindMixin control loses the focus. => save the last postion of the selection."""
        self.lastpos = self.GetSelectedItem()
        event.Skip()

    def OnSetFocus(self, event):
        """AutoFindMixin control gets the focus. => Clear the buffer."""
        self.keybuffer = ""
        self.ShowBuffer()
        #print self.lastpos
        #self.SetSelection(self.lastpos)
        event.Skip()
        
    def OnChar(self, event):
        """Process current typed in key."""
        if event.GetKeyCode() > 255 or event.GetKeyCode() in (wx.WXK_RETURN, wx.WXK_TAB):
            # example: cursor keys should work as expected.
            # and return and tab should not fill the keybuffer list.
            event.Skip()
            return
        if event.GetKeyCode() == wx.WXK_BACK:
            # delete last key in buffer
            if len (self.keybuffer) > 0:
                self.keybuffer = self.keybuffer[:-1]
        elif event.GetKeyCode() == wx.WXK_ESCAPE:
            # delete buffer with Escape key.
            self.keybuffer = ""
            self.SetSelectedItem(self.lastpos)
            self.ShowBuffer()
            return
        else:
            # extend buffer with current pressed key.
            self.keybuffer += chr (event.GetKeyCode())
            #print self.lastpos

        self.ShowBuffer()
          
        # try to find in the list
        for i in range(self.GetNrEntries()):
            if self.GetItemString(i).find(self.keybuffer) == 0:
                # save lastpos before first typing a char
                if len(self.keybuffer) == 1 and not event.GetKeyCode() == wx.WXK_BACK:
                    self.lastpos = self.GetSelectedItem()
                self.SetSelectedItem(i)
                #print self.lastpos
                return

    def OnChoice(self, event):
        """This could be skipped."""
        #print '1. EvtChoice: %s\n' % event.GetString(),
        self.lastpos = self.GetSelectedItem()
        #print self.lastpos
        event.Skip()

    def ShowBuffer(self):
        """Display Key Buffer."""
        if self.showbuffer:
            if self.keybuffer == "":
                self.StaticText.SetLabel("")
            else:
                self.StaticText.SetLabel("'" + self.keybuffer + "'")

========================================================================================

#!/usr/bin/env python

# Franz Steinhaeusler, 09.05.2006
# TestAutoFind.py Demo Application

import wx
from AutoFindMixin import AutoFindMixin

class ChoiceAutoFind(wx.Choice, AutoFindMixin):
    """ChoiceAutoFind: Demo Sample to present the AutoFindMixin class with a wx.Choice."""
    def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, choices=[], style=0, showbuffer=False):
        """Create the ChoiceAutoFind Control."""
        wx.Choice.__init__(self, parent, id, pos, size, choices, style)
        AutoFindMixin.__init__(self, parent, showbuffer)

    # this class must be overwritten
    def GetControl(self):
        """returns the assigned control."""
        return self

class ComboBoxAutoFind(wx.ComboBox, AutoFindMixin):
    """ComboBoxAutoFind: Demo Sample to present the AutoFindMixin class with a wx.ComboBox."""
    def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, choices=[], style=0, showbuffer=False):
        """Create the ComboBoxAutoFind Control."""
        wx.ComboBox.__init__(self, parent, id, "", pos, size, choices, style)
        AutoFindMixin.__init__(self, parent, showbuffer)

    # this class must be overwritten
    def GetControl(self):
        """returns the assigned control."""
        return self

class ListCtrlAutoFind(wx.ListCtrl, AutoFindMixin):
    """ListCtrlAutoFind: Demo Sample to present the AutoFindMixin class with a wx.ListCtrl."""
    def __init__(self, parent, id=-1, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, choices=[], style=0, showbuffer=False):
        """Create the ListCtrlAutoFind Control."""
           
        wx.ListCtrl.__init__(self, parent, pos=pos, size=size, style=wx.LC_REPORT|wx.LC_SINGLE_SEL)
        self.InsertColumn(0, "Col1")
        self.InsertColumn(1, "Col2")
        
        listindex = 0
        for c in choices:
            self.InsertStringItem(listindex, c)
            self.SetStringItem(listindex, 1, "line1%d" % listindex)
            listindex += 1
        self.SetSize ((150, 150))
           
        AutoFindMixin.__init__(self, parent, showbuffer)

    # this class must be overwritten
    def GetControl(self):
        """returns the assigned control."""
        return self

class TestAutoFindPanel(wx.Panel):
    """Test Panel for AutoFind."""
    def __init__(self, parent, showbuffer=False):
        """Create the TestAutoFind Panel."""
        wx.Panel.__init__(self, parent, -1)

        wx.StaticText(self, -1, "Select one:", pos=(15, 10), size=(75, -1))

        sampleList = ['zero', 'one', 'two', 'three', 'thirteen', 'twenty']
        wx.StaticText(self, -1, "TextCtrl:", pos=(15, 180), size=(75, -1))
        txt = wx.TextCtrl(self, pos=(100,180))
        
        #self.ch = ChoiceAutoFind(self, pos=(100, 10), choices=sampleList, showbuffer=showbuffer)
        #self.ch = ComboBoxAutoFind(self, pos=(100, 10), choices=sampleList, showbuffer=showbuffer)
        self.ch = ListCtrlAutoFind(self, pos=(100, 10), choices=sampleList, showbuffer=showbuffer)
        
        self.ch.SetFocus()
        
        self.ch.Bind(wx.EVT_CHOICE, self.OnChoice)
        
    def OnChoice(self, event):
        """Display currently selected entry.."""
        #print '2. EvtChoice: %s\n' % event.GetString()
        event.Skip()
        
if __name__ == "__main__":
    app = wx.App(0)
    frame = wx.Frame(None, title="Test Auto Find App", size=(350, 300))
    frame.Center()
    #TestAutoFindPanel(frame)
    TestAutoFindPanel(frame, showbuffer=True)
    frame.Show()
    app.MainLoop()

--

Franz Steinhaeusler

Hi folks,

Another try for a Autofind Mixin class.

wx.ComboBox, wx.Choice and wx.ListCtrl (only single selection) supported.
You can try it, if you change the commented code.

Added four common function, which should work depending
on the type of the control:

def GetSelectedItem(self):
def SetSelectedItem(self, index):
def GetItemString(self, index):
def GetNrEntries(self):

Does it work on Linux?

I did a quick run and it seems to work fine.

Ricardo

thanks, and next try:

Now autofind.py belongs to the mixins directory
(wx\lib\mixins\autofind.py)
and AutoFindDemo.py you can place anywhere, or if you want to
integrate this into the demo, then place it into your
demodirectory.

In main.py you have to extend for example in recent additions:

_treeList = [
    # new stuff
    ('Recent Additions/Updates', [
        ...,
        'AutoFindDemo'
        ]),

New:
  * Now wx.ListBox also is supported.
  * Integrated into Demo
  * Several controls in the demo are on the panel.
  * CheckBox to switch on/off the showbuffer statictext.

Bugfix:
  * You couldn't enter any value into ComboBox.
  * removed superflous GetConrol method.

Changed:
  * changed code from event SetFocus to KillFocus.
  * corrected some comments and simplified some code.

Attached are:
AutoFindDemo.py
autofind.py

or from:
http://mitglied.lycos.de/drpython/AutoFind_10_05_2006.zip (3 k)

···

On Tue, 9 May 2006 18:36:54 +0100 (WEST), "Ricardo Pedroso" <ricardo.pedroso@netvisao.pt> wrote:

Hi folks,

Another try for a Autofind Mixin class.

wx.ComboBox, wx.Choice and wx.ListCtrl (only single selection) supported.
You can try it, if you change the commented code.

Added four common function, which should work depending
on the type of the control:

def GetSelectedItem(self):
def SetSelectedItem(self, index):
def GetItemString(self, index):
def GetNrEntries(self):

Does it work on Linux?

I did a quick run and it seems to work fine.

Ricardo

--

Franz Steinhaeusler

begin 644 autofind.py
M(R$O=7-R+V)I;B]E;G8@<'ET:&]N#0H-"B,@1G)A;GH@4W1E:6YH865U<VQE
M<BP@,3`N,#4N,C`P-@T*(R!A=71O9FEN9"YP>2`H8F5L;VYG<R!T;R!W>"]L
M:6(O;6EX:6YS(&1I<F5C=&]R>2D-"@T*:6UP;W)T("!W>`T*#0IC;&%S<R!!
M=71O1FEN9$UI>&EN.@T*("`@("(B(D%U=&]&:6YD36EX:6XZ(&ET('=I;&P@
M<V5A<F-H(&9O<B!E;&5M96YT<R!W:&EC:"!F:71S(&$@=VAO;&4@='EP960@
M:6X@=V]R9"!F<F%G;65N="XB(B(-"B`@("!D968@7U]I;FET7U\H<V5L9BP@
M<&%R96YT+"!S:&]W8G5F9F5R/49A;'-E*3H-"B`@("`@("`@(B(B0W)E871E
M<R!T:&4@075T;T9I;F1-:7AI;B!#;&%S<RXB(B(-"B`@("`@("`@(R!T86ME
M;B!F<F]M(&QI<W1C=')L($UI>&EN<R!C;&%S<PT*("`@("`@("!S96QF+F-O
M;G1R;VP@/2!C;VYT<F]L(#T@<V5L9@T*("`@("`@("!I9B!N;W0@8V]N=')O
M;#H-"B`@("`@("`@("`@(')A:7-E(%9A;'5E17)R;W(L(").;R!#;VYT<F]L
M(&%V86EL86)L92(-"B`@("`@("`@96QS93H-"B`@("`@("`@("`@(&EF(&ES
M:6YS=&%N8V4H8V]N=')O;"P@=W@N0VAO:6-E*2!O<B!<#0H@("`@("`@("`@
M("`@("!I<VEN<W1A;F-E*&-O;G1R;VPL('=X+D-O;6)O0F]X*2!O<B!<#0H@
M("`@("`@("`@("`@("!I<VEN<W1A;F-E*&-O;G1R;VPL('=X+DQI<W1#=')L
M*2!O<B!<#0H@("`@("`@("`@("`@("!I<VEN<W1A;F-E*&-O;G1R;VPL('=X
M+DQI<W1";W@I.@T*("`@("`@("`@("`@("`@("-P<FEN="`B;VLB+"!C;VYT
M<F]L#0H@("`@("`@("`@("`@("`@<&%S<PT*("`@("`@("`@("`@96QS93H-
M"B`@("`@("`@("`@("`@("!R86ES92!686QU945R<F]R+"`B3F]T('-U<'!O
M<G1E9"!C;VYT<F]L.B(L(&-O;G1R;VP-"@T*("`@("`@("!S96QF+FME>6)U
M9F9E<B`]("(B#0H@("`@("`@('-E;&8N<VAO=V)U9F9E<B`]('-H;W=B=69F
M97(-"B`@("`@("`@<V5L9BYL87-T<&]S(#T@<V5L9BY'971396QE8W1E9$ET
M96TH*0T*#0H@("`@("`@(&EF('-H;W=B=69F97(Z#0H@("`@("`@("`@("`C
M(&-R96%T92!A('-T871I8R!T97AT('1O('-H;W<@8W5R<F5N="!K97EB=69F
M97(N#0H@("`@("`@("`@("!X+"!Y(#T@<V5L9BY'9710;W-I=&EO;B@I#0H@
M("`@("`@("`@("!W+"!H(#T@<V5L9BY'9713:7IE*"D-"B`@("`@("`@("`@
M('-E;&8N4W1A=&EC5&5X="`]('=X+E-T871I8U1E>'0H<&%R96YT+"!P;W,]
M*'@K=RLU+'DK,RDI#0H@("`@("`@("`@("!S96QF+E-T871I8U1E>'0N4V5T
M0F%C:V=R;W5N9$-O;&]U<BAW>"Y#;VQO=7(H,C4U+"`R-34L(#$Y,BDI#0H-
M"B`@("`@("`@(R!B:6YD('1H92!C;VYT<G)O;`T*("`@("`@("!C;VYT<F]L
M+D)I;F0H=W@N15947T-(05(L('-E;&8N3VY#:&%R*0T*("`@("`@("!C;VYT
M<F]L+D)I;F0H=W@N15947TM)3$Q?1D]#55,L('-E;&8N3VY+:6QL1F]C=7,I
M#0H-"B`@("`@("`@<V5L9BY":6YD*'=X+D565%]#2$])0T4L('-E;&8N3VY#
M:&]I8V4I#0H@("`@("`@(`T*("`@(&1E9B!'971396QE8W1E9$ET96TH<V5L
M9BDZ#0H@("`@("`@("(B(D=E="!I;F1E>"!O9B!T:&4@8W5R<F5N=&QY('-E
M;&5C=&5D(&ET96TN(B(B#0H@("`@("`@(&EF(&ES:6YS=&%N8V4H<V5L9BYC
M;VYT<F]L+"!W>"Y,:7-T0W1R;"DZ#0H@("`@("`@("`@("!R971U<FX@<V5L
M9BYC;VYT<F]L+D=E=$YE>'1)=&5M*"TQ+"!W>"Y,25-47TY%6%1?04Q,+"`-
M"B`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@
M=W@N3$E35%]35$%415]314Q%0U1%1"D-"B`@("`@("`@96QS93H-"B`@("`@
M("`@("`@(')E='5R;B!S96QF+F-O;G1R;VPN1V5T4V5L96-T:6]N*"D-"B`@
M("`@("`@<&%S<PT*("`@("`@("`-"B`@("!D968@4V5T4V5L96-T961)=&5M
M*'-E;&8L(&EN9&5X*3H-"B`@("`@("`@(B(B4V5T(&%C=&EV92!I=&5M('1O
M('1H92!G:79E;B!I;F1E>"XB(B(-"B`@("`@("`@:68@:7-I;G-T86YC92AS
M96QF+F-O;G1R;VPL('=X+DQI<W1#=')L*3H-"B`@("`@("`@("`@('-E;&8N
M4V5T271E;5-T871E*&EN9&5X+"!W>"Y,25-47U-4051%7U-%3$5#5$5$?'=X
M+DQ)4U1?4U1!5$5?1D]#55-%1"P@#0H@("`@("`@("`@("`@("`@("`@("`@
M("`@("`@("!W>"Y,25-47U-4051%7U-%3$5#5$5$?'=X+DQ)4U1?4U1!5$5?
M1D]#55-%1"D-"B`@("`@("`@("`@('!A<W,-"B`@("`@("`@96QS93H-"B`@
M("`@("`@("`@('-E;&8N4V5T4V5L96-T:6]N*&EN9&5X*0T*("`@("`@("`@
M("`@<&%S<PT*#0H@("`@9&5F($=E=$ET96U3=')I;F<H<V5L9BP@:6YD97@I
M.@T*("`@("`@("`B(B)'970@0W5R<F5N=&QY('-E;&5C=&5D(&ET96T@;V8@
M=&AE($%U=&]&:6YD36EX:6X@8V]N=')O;"XB(B(-"B`@("`@("`@:68@:7-I
M;G-T86YC92AS96QF+F-O;G1R;VPL('=X+DQI<W1#=')L*3H-"B`@("`@("`@
M("`@(')E='5R;B!S96QF+F-O;G1R;VPN1V5T271E;2AI;F1E>"P@,"DN1V5T
M5&5X="@I#0H@("`@("`@(&5L<V4Z#0H@("`@("`@("`@("!R971U<FX@<V5L
M9BYC;VYT<F]L+D=E=%-T<FEN9RAI;F1E>"D-"B`@("`@("`@#0H@("`@9&5F
M($=E=$YR16YT<FEE<RAS96QF*3H-"B`@("`@("`@(B(B1V5T($YU;6)E<B!O
M9B!%;G1R:65S(&]F('1H92!!=71O1FEN9$UI>&EN(&-O;G1R;VPN(B(B#0H@
M("`@("`@(&EF(&ES:6YS=&%N8V4H<V5L9BYC;VYT<F]L+"!W>"Y,:7-T0W1R
M;"DZ#0H@("`@("`@("`@("!R971U<FX@<V5L9BYC;VYT<F]L+D=E=$ET96U#
M;W5N="@I#0H@("`@("`@(&5L<V4Z#0H@("`@("`@("`@("!R971U<FX@<V5L
M9BYC;VYT<F]L+D=E=$-O=6YT*"D-"@T*("`@(&1E9B!/;DMI;&Q&;V-U<RAS
M96QF+"!E=F5N="DZ#0H@("`@("`@("(B(D%U=&]&:6YD36EX:6X@8V]N=')O
M;"!L;W-E<R!T:&4@9F]C=7,N(#T^('-A=F4@=&AE(&QA<W0@<&]S=&EO;B!O
M9B!T:&4@<V5L96-T:6]N+B(B(@T*("`@("`@("!S96QF+FQA<W1P;W,@/2!S
M96QF+D=E=%-E;&5C=&5D271E;2@I#0H@("`@("`@('-E;&8N:V5Y8G5F9F5R
M(#T@(B(-"B`@("`@("`@<V5L9BY3:&]W0G5F9F5R*"D-"B`@("`@("`@979E
M;G0N4VMI<"@I#0H-"B`@("!D968@3VY#:&%R*'-E;&8L(&5V96YT*3H-"B`@
M("`@("`@(B(B4')O8V5S<R!C=7)R96YT('1Y<&5D(&EN(&ME>2XB(B(-"B`@
M("`@("`@:V5Y8V]D92`](&5V96YT+D=E=$ME>4-O9&4H*0T*("`@("`@("!I
M9B!K97EC;V1E(#X@,C4U(&]R(&ME>6-O9&4@:6X@*'=X+E=82U]215154DXL
M('=X+E=82U]404(I.@T*("`@("`@("`@("`@(R!E>&%M<&QE.B!C=7)S;W(@
M:V5Y<R!S:&]U;&0@=V]R:R!A<R!E>'!E8W1E9"X-"B`@("`@("`@("`@(",@
M86YD(')E='5R;B!A;F0@=&%B('-H;W5L9"!N;W0@9FEL;"!T:&4@:V5Y8G5F
M9F5R(&QI<W0N#0H@("`@("`@("`@("!E=F5N="Y3:VEP*"D-"B`@("`@("`@
M("`@(')E='5R;@T*("`@("`@("!I9B!K97EC;V1E(#T]('=X+E=82U]"04-+
M.@T*("`@("`@("`@("`@(R!D96QE=&4@;&%S="!K97D@:6X@8G5F9F5R#0H@
M("`@("`@("`@("!I9B!L96X@*'-E;&8N:V5Y8G5F9F5R*2`^(#`Z#0H@("`@
M("`@("`@("`@("`@<V5L9BYK97EB=69F97(@/2!S96QF+FME>6)U9F9E<ELZ
M+3%=#0H@("`@("`@(&5L:68@:V5Y8V]D92`]/2!W>"Y76$M?15-#05!%.@T*
M("`@("`@("`@("`@(R!D96QE=&4@8G5F9F5R('=I=&@@17-C87!E(&ME>2X-
M"B`@("`@("`@("`@('-E;&8N:V5Y8G5F9F5R(#T@(B(-"B`@("`@("`@("`@
M('-E;&8N4V5T4V5L96-T961)=&5M*'-E;&8N;&%S='!O<RD-"B`@("`@("`@
M("`@('-E;&8N4VAO=T)U9F9E<B@I#0H@("`@("`@("`@("!R971U<FX-"B`@
M("`@("`@96QS93H-"B`@("`@("`@("`@(",@97AT96YD(&)U9F9E<B!W:71H
M(&-U<G)E;G0@<')E<W-E9"!K97DN#0H@("`@("`@("`@("!S96QF+FME>6)U
M9F9E<B`K/2!C:'(@*&ME>6-O9&4I#0H@("`@("`@("`@("`C<')I;G0@<V5L
M9BYL87-T<&]S#0H-"B`@("`@("`@<V5L9BY3:&]W0G5F9F5R*"D-"B`@("`@
M("`@("`-"B`@("`@("`@(R!T<GD@=&\@9FEN9"!I;B!T:&4@;&ES=`T*("`@
M("`@("!F;W(@:2!I;B!R86YG92AS96QF+D=E=$YR16YT<FEE<R@I*3H-"B`@
M("`@("`@("`@(&EF('-E;&8N1V5T271E;5-T<FEN9RAI*2YF:6YD*'-E;&8N
M:V5Y8G5F9F5R*2`]/2`P.@T*("`@("`@("`@("`@("`@(",@<V%V92!L87-T
M<&]S(&)E9F]R92!F:7)S="!T>7!I;F<@82!C:&%R(`T*("`@("`@("`@("`@
M("`@(&EF(&QE;BAS96QF+FME>6)U9F9E<BD@/3T@,2!A;F0@;F]T(&ME>6-O
M9&4@/3T@=W@N5UA+7T)!0TLZ#0H@("`@("`@("`@("`@("`@("`@('-E;&8N
M;&%S='!O<R`]('-E;&8N1V5T4V5L96-T961)=&5M*"D-"B`@("`@("`@("`@
M("`@("!S96QF+E-E=%-E;&5C=&5D271E;2AI*0T*("`@("`@("`@("`@("`@
M("-P<FEN="!S96QF+FQA<W1P;W,-"B`@("`@("`@("`@("`@("!R971U<FX-
M"B`@("`@("`@(VAA;F1L92!#;VUB;T)O>#H@:68@;F]T:&EN9R!I<R!F;W5N
M9"P@9FEL;"!I;B!T:&4@8W5R<F5N=&QY('1Y<&5D('9A;'5E#0H@("`@("`@
M(&EF(&ES:6YS=&%N8V4H<V5L9BYC;VYT<F]L+"!W>"Y#;VUB;T)O>"DZ#0H@
M("`@("`@("`@("!S96QF+F-O;G1R;VPN4V5T5F%L=64H<V5L9BYK97EB=69F
M97(I#0H@("`@("`@("`@("!S96QF+F-O;G1R;VPN4V5T26YS97)T:6]N4&]I
M;G0H;&5N*'-E;&8N:V5Y8G5F9F5R*2D-"@T*("`@(&1E9B!/;D-H;VEC92AS
M96QF+"!E=F5N="DZ#0H@("`@("`@("(B(E1H:7,@8V]U;&0@8F4@<VMI<'!E
M9"XB(B(-"B`@("`@("`@(W!R:6YT("<Q+B!%=G1#:&]I8V4Z("5S7&XG("4@
M979E;G0N1V5T4W1R:6YG*"DL#0H@("`@("`@('-E;&8N;&%S='!O<R`]('-E
M;&8N1V5T4V5L96-T961)=&5M*"D-"B`@("`@("`@(W!R:6YT('-E;&8N;&%S
M='!O<PT*("`@("`@("!E=F5N="Y3:VEP*"D-"@T*("`@(&1E9B!3:&]W0G5F
M9F5R*'-E;&8I.@T*("`@("`@("`B(B)$:7-P;&%Y($ME>2!"=69F97(N(B(B
M#0H@("`@("`@(&EF('-E;&8N<VAO=V)U9F9E<CH-"B`@("`@("`@("`@(&EF
M('-E;&8N:V5Y8G5F9F5R(#T]("(B.@T*("`@("`@("`@("`@("`@('-E;&8N
M4W1A=&EC5&5X="Y3971,86)E;"@B(BD-"B`@("`@("`@("`@(&5L<V4Z#0H@
M("`@("`@("`@("`@("`@<V5L9BY3=&%T:6-497AT+E-E=$QA8F5L*"(G(B`K
8('-E;&8N:V5Y8G5F9F5R("L@(B<B*0T*
`
end

begin 644 AutoFindDemo.py
M(R$O=7-R+V)I;B]E;G8@<'ET:&]N#0H-"B,@1G)A;GH@4W1E:6YH865U<VQE
M<BP@,3`N,#4N,C`P-@T*(R!497-T075T;T9I;F0N<'D@1&5M;R!!<'!L:6-A
M=&EO;@T*#0II;7!O<G0@=W@-"F9R;VT@=W@N;&EB+FUI>&EN<RYA=71O9FEN
M9"!I;7!O<G0@*@T*#0IC;&%S<R!#:&]I8V5!=71O1FEN9"AW>"Y#:&]I8V4L
M($%U=&]&:6YD36EX:6XI.@T*("`@("(B(D-H;VEC94%U=&]&:6YD.B!$96UO
M($-L87-S('1O('!R97-E;G0@=&AE($%U=&]&:6YD36EX:6X@8VQA<W,@=VET
M:"!A('=X+D-H;VEC92XB(B(-"B`@("!D968@7U]I;FET7U\H<V5L9BP@<&%R
M96YT+"!I9#TM,2P@<&]S/7=X+D1E9F%U;'10;W-I=&EO;BP@#0H@("`@("`@
M("`@("`@("`@('-I>F4]=W@N1&5F875L=%-I>F4L(&-H;VEC97,]6UTL('-T

6QE/3`L('-H;W=B=69F97(]1F%L<V4I.@T*("`@("`@("`B(B)#<F5A=&4@

M=&AE($-H;VEC94%U=&]&:6YD($-O;G1R;VPN(B(B#0H@("`@("`@('=X+D-H
M;VEC92Y?7VEN:71?7RAS96QF+"!P87)E;G0L(&ED+"!P;W,L('-I>F4L(&-H
M;VEC97,L('-T>6QE*0T*("`@("`@("!!=71O1FEN9$UI>&EN+E]?:6YI=%]?
M*'-E;&8L('!A<F5N="P@<VAO=V)U9F9E<BD-"@T*8VQA<W,@0V]M8F]";WA!
M=71O1FEN9"AW>"Y#;VUB;T)O>"P@075T;T9I;F1-:7AI;BDZ#0H@("`@(B(B
M0V]M8F]";WA!=71O1FEN9#H@1&5M;R!#;&%S<R!T;R!P<F5S96YT('1H92!!
M=71O1FEN9$UI>&EN(&-L87-S('=I=&@@82!W>"Y#;VUB;T)O>"XB(B(-"B`@
M("!D968@7U]I;FET7U\H<V5L9BP@<&%R96YT+"!I9#TM,2P@<&]S/7=X+D1E
M9F%U;'10;W-I=&EO;BP@#0H@("`@("`@("`@("`@("`@('-I>F4]=W@N1&5F
M875L=%-I>F4L(&-H;VEC97,]6UTL('-T>6QE/3`L('-H;W=B=69F97(]1F%L
M<V4I.@T*("`@("`@("`B(B)#<F5A=&4@=&AE($-O;6)O0F]X075T;T9I;F0@
M0V]N=')O;"XB(B(-"B`@("`@("`@=W@N0V]M8F]";W@N7U]I;FET7U\H<V5L
M9BP@<&%R96YT+"!I9"P@(B(L('!O<RP@<VEZ92P@8VAO:6-E<RP@<W1Y;&4I
M#0H@("`@("`@($%U=&]&:6YD36EX:6XN7U]I;FET7U\H<V5L9BP@<&%R96YT
M+"!S:&]W8G5F9F5R*0T*#0IC;&%S<R!,:7-T0W1R;$%U=&]&:6YD*'=X+DQI
M<W1#=')L+"!!=71O1FEN9$UI>&EN*3H-"B`@("`B(B),:7-T0W1R;$%U=&]&
M:6YD.B!$96UO(%-A;7!L92!T;R!P<F5S96YT('1H92!!=71O1FEN9$UI>&EN
M(&-L87-S('=I=&@@82!W>"Y,:7-T0W1R;"XB(B(-"B`@("!D968@7U]I;FET
M7U\H<V5L9BP@<&%R96YT+"!I9#TM,2P@<&]S/7=X+D1E9F%U;'10;W-I=&EO
M;BP@#0H@("`@("`@("`@("`@("`@('-I>F4]=W@N1&5F875L=%-I>F4L(&-H
M;VEC97,]6UTL('-T>6QE/3`L('-H;W=B=69F97(]1F%L<V4I.@T*("`@("`@
M("`B(B)#<F5A=&4@=&AE($QI<W1#=')L075T;T9I;F0@0V]N=')O;"XB(B(-
M"B`@("`@("`@("`@#0H@("`@("`@('=X+DQI<W1#=')L+E]?:6YI=%]?*'-E
M;&8L('!A<F5N="P@<&]S/7!O<RP@<VEZ93US:7IE+"!S='EL93UW>"Y,0U]2
M15!/4E1\=W@N3$-?4TE.1TQ%7U-%3"D-"B`@("`@("`@<V5L9BY);G-E<G1#
M;VQU;6XH,"P@(D-O;#$B*0T*("`@("`@("!S96QF+DEN<V5R=$-O;'5M;B@Q
M+"`B0V]L,B(I#0H@("`@("`@(`T*("`@("`@("!L:7-T:6YD97@@/2`P#0H@
M("`@("`@(&9O<B!C(&EN(&-H;VEC97,Z("`@("`@(`T*("`@("`@("`@("`@
M<V5L9BY);G-E<G13=')I;F=)=&5M*&QI<W1I;F1E>"P@8RD-"B`@("`@("`@
M("`@('-E;&8N4V5T4W1R:6YG271E;2AL:7-T:6YD97@L(#$L(")L:6YE,25D
M(B`E(&QI<W1I;F1E>"D-"B`@("`@("`@("`@(&QI<W1I;F1E>"`K/2`Q#0H@
M("`@("`@('-E;&8N4V5T4VEZ92`H*#$U,"P@,34P*2D-"B`@("`@("`@("`@
M#0H@("`@("`@($%U=&]&:6YD36EX:6XN7U]I;FET7U\H<V5L9BP@<&%R96YT
M+"!S:&]W8G5F9F5R*0T*#0IC;&%S<R!,:7-T0F]X075T;T9I;F0H=W@N3&ES
M=$)O>"P@075T;T9I;F1-:7AI;BDZ#0H@("`@(B(B3&ES=$)O>$%U=&]&:6YD
M.B!$96UO($-L87-S('1O('!R97-E;G0@=&AE($%U=&]&:6YD36EX:6X@8VQA
M<W,@=VET:"!A('=X+DQI<W1";WA!=71O1FEN9"XB(B(-"B`@("!D968@7U]I
M;FET7U\H<V5L9BP@<&%R96YT+"!I9#TM,2P@<&]S/7=X+D1E9F%U;'10;W-I
M=&EO;BP@#0H@("`@("`@("`@("`@("`@('-I>F4]=W@N1&5F875L=%-I>F4L
M(&-H;VEC97,]6UTL('-T>6QE/3`L('-H;W=B=69F97(]1F%L<V4I.@T*("`@
M("`@("`B(B)#<F5A=&4@=&AE($QI<W1";WA!=71O1FEN9"!#;VYT<F]L+B(B
M(@T*("`@("`@("!W>"Y,:7-T0F]X+E]?:6YI=%]?*'-E;&8L('!A<F5N="P@
M:60L('!O<RP@<VEZ92P@8VAO:6-E<RP@<W1Y;&4I#0H@("`@("`@($%U=&]&
M:6YD36EX:6XN7U]I;FET7U\H<V5L9BP@<&%R96YT+"!S:&]W8G5F9F5R*0T*
M#0H-"B,M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM#0H-"F-L87-S(%1E<W10
M86YE;"AW>"Y086YE;"DZ#0H@("`@(B(B5&5S="!086YE;"!F;W(@075T;T9I
M;F0N(B(B#0H@("`@9&5F(%]?:6YI=%]?*'-E;&8L('!A<F5N="P@;&]G*3H-
M"B`@("`@("`@(B(B0W)E871E('1H92!497-T075T;T9I;F0@4&%N96PN(B(B
M#0H@("`@("`@('-E;&8N;&]G(#T@;&]G#0H@("`@("`@('=X+E!A;F5L+E]?
M:6YI=%]?*'-E;&8L('!A<F5N="P@+3$I#0H@("`@("`@('-A;7!L94QI<W0@
M/2!;)WIE<F\G+"`G;VYE)RP@)W1W;R<L("=T:')E92<L("=T:&ER=&5E;B<L
M("=T=V5N='DG70T*("`@("`@("`-"B`@("`@("`@<VAO=V)U9F9E<B`](%1R
M=64-"B`@("`@("`@=W@N4W1A=&EC5&5X="AS96QF+"`M,2P@(D-H;VEC93HB
M+"!P;W,]*#$U+"`Q,BDL('-I>F4]*#<U+"`M,2DI#0H@("`@("`@('-E;&8N
M8V@@/2!#:&]I8V5!=71O1FEN9"AS96QF+"!P;W,]*#$P,"P@,3`I+"!C:&]I
M8V5S/7-A;7!L94QI<W0L('-H;W=B=69F97(]<VAO=V)U9F9E<BD-"B`@("`@
M("`@=W@N4W1A=&EC5&5X="AS96QF+"`M,2P@(D-O;6)O0F]X.B(L('!O<STH
M,S$U+"`Q,BDL('-I>F4]*#<U+"`M,2DI#0H@("`@("`@('-E;&8N8V\@/2!#
M;VUB;T)O>$%U=&]&:6YD*'-E;&8L('!O<STH-#`P+"`Q,"DL(&-H;VEC97,]
M<V%M<&QE3&ES="P@<VAO=V)U9F9E<CUS:&]W8G5F9F5R*0T*("`@("`@("!W

"Y3=&%T:6-497AT*'-E;&8L("TQ+"`B3&ES=$-T<FPZ(BP@<&]S/2@Q-2P@

M,34P*2P@<VEZ93TH-S4L("TQ*2D-"B`@("`@("`@<V5L9BYL8R`]($QI<W1#
M=')L075T;T9I;F0H<V5L9BP@<&]S/2@Q,#`L(#$P,"DL(&-H;VEC97,]<V%M
M<&QE3&ES="P@<VAO=V)U9F9E<CUS:&]W8G5F9F5R*0T*#0H@("`@("`@('=X
M+E-T871I8U1E>'0H<V5L9BP@+3$L("),:7-T0F]X.B(L('!O<STH,S$U+"`Q
M-3`I+"!S:7IE/2@W-2P@+3$I*0T*("`@("`@("!S96QF+FQC(#T@3&ES=$)O

$%U=&]&:6YD*'-E;&8L('!O<STH-#`P+"`Q,3`I+"!C:&]I8V5S/7-A;7!L

M94QI<W0L('-H;W=B=69F97(]<VAO=V)U9F9E<BD-"@T*("`@("`@("!S96QF
M+F-H:W-H;W=B=69F97(@/2!W>"Y#:&5C:T)O>"AS96QF+"!L86)E;#TB4VAO
M=R!+97EB=69F97(B+"!P;W,]*"@Q-2P@,S`P*2DI(`T*("`@("`@("!S96QF
M+F-H:W-H;W=B=69F97(N4V5T5F%L=64H<VAO=V)U9F9E<BD-"B`@("`@("`@
M#0H@("`@("`@('-E;&8N8V@N4V5T1F]C=7,H*0T*("`@("`@("`-"B`@("`@
M("`@<V5L9BYC:&MS:&]W8G5F9F5R+D)I;F0H=W@N15947T-(14-+0D]8+"!S
M96QF+D]N0VAE8VLI#0H@("`@("`@(`T*("`@("`@("`-"B`@("!D968@3VY#
M:&5C:RAS96QF+"!E=F5N="DZ#0H@("`@("`@("(B(E-W:71C:"!S:&]W(&ME

6)U9F9E<B!O9F8@86YD(&]N+B(B(@T*("`@("`@("!V86P@/2!S96QF+F-H

M:W-H;W=B=69F97(N27-#:&5C:V5D*"D-"B`@("`@("`@<V5L9BYC:"YS:&]W
M8G5F9F5R(#T@=F%L#0H@("`@("`@('-E;&8N8V\N<VAO=V)U9F9E<B`]('9A
M;`T*("`@("`@("!S96QF+FQC+G-H;W=B=69F97(@/2!V86P-"@T*(RTM+2TM
M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
M+2TM+2TM+2TM+2TM+2TM+2TM+2T-"@T*9&5F(')U;E1E<W0H9G)A;64L(&YB
M+"!L;V<I.@T*("`@('=I;B`](%1E<W1086YE;"AN8BP@;&]G*0T*("`@(')E
M='5R;B!W:6X-"@T*(RTM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM
M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2T-"@T*;W9E
M<G9I97<@/2`B(B)4:&ES(&1E;6\@=7-E<R!T:&4@075T;T9I;F1-:7AI;B!C
M;&%S<R!W:&EC:"!E;F%B;&5S('EO=2!T;PT*9FEN9"!A;B!E;G1R>2!F87-T
M97(L('=H96X@<VEM:6QA<B!E;G1R:65S(&)E9VEN;FEN9R!W:71H('1H92!S
M86UE(&QE='1E<G,-"F%R92!T:&5R92X-"@T*1VEV96XZ#0IT:')E90T*=&AI
M<G1E96X-"G1W96YT>0T*=&5N#0IT=V\-"@T*66]U(&-A;B!F:6YD('1H92!T
M97)M("=T96XG('%U:6-K;'D@869T97(@='EP:6YG(&9I<G-T("=T)R!T:&%N
M("=E)RX-"DYO<FUA;"!B96AA=FEO=7(@=V]U;&0@8F4@:G5M<&EN9R!T;R!T
M:&4@9FER<W0@96YT<GD@=VAI8V@@8F5G:6YS('=I=&@@86X@)V4G+@T*5&AE
M(&ME>2!B=69F97(@:7,@8VQE87)E9"P@=VAE;B!Y;W4@;&5A=F4@=&AE(&-O
M;G1R;VP@;W(@>6]U(&AI="!%4T,@:V5Y+@T*#0I#=7)R96YT;'D@=W@N0VAO
M:6-E+"!W>"Y#;VUB;T)O>"P@=W@N3&ES=$)O>"!A;F0@=W@N3&ES=$-T<FP@
M87)E('-U<'!O<G1E9"X-"@T*/"]B;V1Y/CPO:'1M;#X-"B(B(@T*#0H-"FEF
M(%]?;F%M95]?(#T]("=?7VUA:6Y?7R<Z#0H@("`@(R!C86QL960@87,@<W1A
M;F1A;&]N93H-"B`@("!I;7!O<G0@<WES+&]S#0H@("`@=')Y.@T*("`@("`@
M("`C(&-A;&QE9"!F<F]M(&1E;6\@9&ER96-T;W)Y/PT*("`@("`@("!I;7!O
M<G0@<G5N#0H@("`@("`@(')U;BYM86EN*%LG)RP@;W,N<&%T:"YB87-E;F%M
M92AS>7,N87)G=ELP72E=("L@<WES+F%R9W9;,3I=*0T*("`@(&5X8V5P=#H-
M"B`@("`@("`@(R!I9B!N;W0L('1H96X@8V%L;&5D(&9R;VT@86YY(&]T:&5R
M(&1I<F5C=&]R>3\-"B`@("`@("`@(R!S=&%R="!A<R!U<W5A;"!A<'!L:6-A
M=&EO;@T*("`@("`@("!A<'`@/2!W>"Y!<'`H,"D-"B`@("`@("`@9G)A;64@
M/2!W>"Y&<F%M92A.;VYE+"!T:71L93TB5&5S="!!=71O($9I;F0@07!P(BP@
M<VEZ93TH-C`P+"`T,#`I*0T*("`@("`@("!F<F%M92Y#96YT97(H*0T*("`@
M("`@("`C5&5S=$%U=&]&:6YD4&%N96PH9G)A;64I#0H@("`@("`@(%1E<W10
M86YE;"AF<F%M92P@<WES+G-T9&]U="D-"B`@("`@("`@9G)A;64N4VAO=R@I
<#0H@("`@("`@(&%P<"Y-86EN3&]O<"@I#0H-"B`@
`
end