First commit
diff --git a/miniccnxedit b/miniccnxedit
new file mode 100644
index 0000000..675d0cd
--- /dev/null
+++ b/miniccnxedit
@@ -0,0 +1,722 @@
+#!/usr/bin/python
+
+"""
+MiniCCNxEdit: a simple network editor for MiniCCNx
+
+Based on miniedit by Bob Lantz, April 2010
+
+Carlos Cabral Jan, 2013
+
+
+"""
+import optparse
+
+from Tkinter import Frame, Button, Label, Scrollbar, Canvas
+from Tkinter import Menu, BitmapImage, PhotoImage, Wm, Toplevel
+
+# someday: from ttk import *
+
+from mininet.log import setLogLevel
+from mininet.net import Mininet
+from mininet.util import ipStr
+from mininet.term import makeTerm, cleanUpScreens
+
+
+def parse_args():
+    usage="""Usage: miniccnxedit [template_file]
+	If no template_file is given, generated template will be written
+	to the file miniccnx.conf in the current directory.
+    """
+
+    parser = optparse.OptionParser(usage)
+    
+    _, arg = parser.parse_args()
+
+    if len(arg) != 1:
+        arg = None
+    else:
+        arg = arg[0]
+        
+    return arg
+
+class MiniEdit( Frame ):
+
+    "A simple network editor for Mininet."
+
+    def __init__( self, parent=None, cheight=200, cwidth=500, template_file='miniccnx.conf' ):
+
+        Frame.__init__( self, parent )
+        self.action = None
+        self.appName = 'Mini-CCNx'
+        if template_file == None:
+            self.template_file='miniccnx.conf'
+        else:
+	        self.template_file = template_file
+
+        # Style
+        self.font = ( 'Geneva', 9 )
+        self.smallFont = ( 'Geneva', 7 )
+        self.bg = 'white'
+
+        # Title
+        self.top = self.winfo_toplevel()
+        self.top.title( self.appName )
+
+        # Menu bar
+        self.createMenubar()
+
+        # Editing canvas
+        self.cheight, self.cwidth = cheight, cwidth
+        self.cframe, self.canvas = self.createCanvas()
+
+        # Toolbar
+        self.images = miniEditImages()
+        self.buttons = {}
+        self.active = None
+        self.tools = ( 'Select', 'Host', 'Switch', 'Link' )
+        self.customColors = { 'Switch': 'darkGreen', 'Host': 'blue' }
+        self.toolbar = self.createToolbar()
+
+        # Layout
+        self.toolbar.grid( column=0, row=0, sticky='nsew')
+        self.cframe.grid( column=1, row=0 )
+        self.columnconfigure( 1, weight=1 )
+        self.rowconfigure( 0, weight=1 )
+        self.pack( expand=True, fill='both' )
+
+        # About box
+        self.aboutBox = None
+
+        # Initialize node data
+        self.nodeBindings = self.createNodeBindings()
+        self.nodePrefixes = { 'Switch': 's', 'Host': 'h' }
+        self.widgetToItem = {}
+        self.itemToWidget = {}
+
+        # Initialize link tool
+        self.link = self.linkWidget = None
+
+        # Selection support
+        self.selection = None
+
+        # Keyboard bindings
+        self.bind( '<Control-q>', lambda event: self.quit() )
+        self.bind( '<KeyPress-Delete>', self.deleteSelection )
+        self.bind( '<KeyPress-BackSpace>', self.deleteSelection )
+        self.focus()
+
+        # Event handling initalization
+        self.linkx = self.linky = self.linkItem = None
+        self.lastSelection = None
+
+        # Model initialization
+        self.links = {}
+        self.nodeCount = 0
+        self.net = None
+
+        # Close window gracefully
+        Wm.wm_protocol( self.top, name='WM_DELETE_WINDOW', func=self.quit )
+
+    def quit( self ):
+        "Stop our network, if any, then quit."
+        self.stop()
+        Frame.quit( self )
+
+    def createMenubar( self ):
+        "Create our menu bar."
+
+        font = self.font
+
+        mbar = Menu( self.top, font=font )
+        self.top.configure( menu=mbar )
+
+        # Application menu
+        appMenu = Menu( mbar, tearoff=False )
+        mbar.add_cascade( label=self.appName, font=font, menu=appMenu )
+        appMenu.add_command( label='About Mini-CCNx', command=self.about,
+                             font=font)
+        appMenu.add_separator()
+        appMenu.add_command( label='Quit', command=self.quit, font=font )
+
+        #fileMenu = Menu( mbar, tearoff=False )
+        #mbar.add_cascade( label="File", font=font, menu=fileMenu )
+        #fileMenu.add_command( label="Load...", font=font )
+        #fileMenu.add_separator()
+        #fileMenu.add_command( label="Save", font=font )
+        #fileMenu.add_separator()
+        #fileMenu.add_command( label="Print", font=font )
+
+        editMenu = Menu( mbar, tearoff=False )
+        mbar.add_cascade( label="Edit", font=font, menu=editMenu )
+        editMenu.add_command( label="Cut", font=font,
+                              command=lambda: self.deleteSelection( None ) )
+
+       # runMenu = Menu( mbar, tearoff=False )
+       # mbar.add_cascade( label="Run", font=font, menu=runMenu )
+       # runMenu.add_command( label="Run", font=font, command=self.doRun )
+       # runMenu.add_command( label="Stop", font=font, command=self.doStop )
+       # runMenu.add_separator()
+       # runMenu.add_command( label='Xterm', font=font, command=self.xterm )
+
+    # Canvas
+
+    def createCanvas( self ):
+        "Create and return our scrolling canvas frame."
+        f = Frame( self )
+
+        canvas = Canvas( f, width=self.cwidth, height=self.cheight,
+                         bg=self.bg )
+
+        # Scroll bars
+        xbar = Scrollbar( f, orient='horizontal', command=canvas.xview )
+        ybar = Scrollbar( f, orient='vertical', command=canvas.yview )
+        canvas.configure( xscrollcommand=xbar.set, yscrollcommand=ybar.set )
+
+        # Resize box
+        resize = Label( f, bg='white' )
+
+        # Layout
+        canvas.grid( row=0, column=1, sticky='nsew')
+        ybar.grid( row=0, column=2, sticky='ns')
+        xbar.grid( row=1, column=1, sticky='ew' )
+        resize.grid( row=1, column=2, sticky='nsew' )
+
+        # Resize behavior
+        f.rowconfigure( 0, weight=1 )
+        f.columnconfigure( 1, weight=1 )
+        f.grid( row=0, column=0, sticky='nsew' )
+        f.bind( '<Configure>', lambda event: self.updateScrollRegion() )
+
+        # Mouse bindings
+        canvas.bind( '<ButtonPress-1>', self.clickCanvas )
+        canvas.bind( '<B1-Motion>', self.dragCanvas )
+        canvas.bind( '<ButtonRelease-1>', self.releaseCanvas )
+
+        return f, canvas
+
+    def updateScrollRegion( self ):
+        "Update canvas scroll region to hold everything."
+        bbox = self.canvas.bbox( 'all' )
+        if bbox is not None:
+            self.canvas.configure( scrollregion=( 0, 0, bbox[ 2 ],
+                                   bbox[ 3 ] ) )
+
+    def canvasx( self, x_root ):
+        "Convert root x coordinate to canvas coordinate."
+        c = self.canvas
+        return c.canvasx( x_root ) - c.winfo_rootx()
+
+    def canvasy( self, y_root ):
+        "Convert root y coordinate to canvas coordinate."
+        c = self.canvas
+        return c.canvasy( y_root ) - c.winfo_rooty()
+
+    # Toolbar
+
+    def activate( self, toolName ):
+        "Activate a tool and press its button."
+        # Adjust button appearance
+        if self.active:
+            self.buttons[ self.active ].configure( relief='raised' )
+        self.buttons[ toolName ].configure( relief='sunken' )
+        # Activate dynamic bindings
+        self.active = toolName
+
+    def createToolbar( self ):
+        "Create and return our toolbar frame."
+
+        toolbar = Frame( self )
+
+        # Tools
+        for tool in self.tools:
+            cmd = ( lambda t=tool: self.activate( t ) )
+            b = Button( toolbar, text=tool, font=self.smallFont, command=cmd)
+            if tool in self.images:
+                b.config( height=50, image=self.images[ tool ] )
+                # b.config( compound='top' )
+            b.pack( fill='x' )
+            self.buttons[ tool ] = b
+        self.activate( self.tools[ 0 ] )
+
+        # Spacer
+        Label( toolbar, text='' ).pack()
+
+        # Commands
+        #for cmd, color in [ ( 'Stop', 'darkRed' ), ( 'Run', 'darkGreen' ) ]:
+        #    doCmd = getattr( self, 'do' + cmd )
+        #    b = Button( toolbar, text=cmd, font=self.smallFont,
+        #                fg=color, command=doCmd )
+        #    b.pack( fill='x', side='bottom' )
+
+	for cmd, color in [ ( 'Generate', 'darkGreen' ) ]:
+            doCmd = getattr( self, 'do' + cmd )
+            b = Button( toolbar, text=cmd, font=self.smallFont,
+                        fg=color, command=doCmd )
+            b.pack( fill='x', side='bottom' )
+
+
+        return toolbar
+
+    def doGenerate( self ):
+        "Generate template."
+        self.activate( 'Select' )
+        for tool in self.tools:
+            self.buttons[ tool ].config( state='disabled' )
+
+        self.buildTemplate()
+
+	for tool in self.tools:
+            self.buttons[ tool ].config( state='normal' )
+
+    def doStop( self ):
+        "Stop command."
+        self.stop()
+        for tool in self.tools:
+            self.buttons[ tool ].config( state='normal' )
+
+    def buildTemplate( self ):
+	"Generate template"
+	
+	template = open(self.template_file, 'w')
+
+	# hosts
+	template.write('[hosts]\n')
+	for widget in self.widgetToItem:
+            name = widget[ 'text' ]
+            tags = self.canvas.gettags( self.widgetToItem[ widget ] )
+	    if 'Host' in tags:
+		template.write(name + ':\n')	
+
+	# switches/routers
+	template.write('[routers]\n')
+	for widget in self.widgetToItem:
+            name = widget[ 'text' ]
+            tags = self.canvas.gettags( self.widgetToItem[ widget ] )
+	    if 'Switch' in tags:
+		template.write(name + ':\n')	
+
+        # Make links
+	template.write('[links]\n')
+        for link in self.links.values():
+             ( src, dst ) = link
+             srcName, dstName = src[ 'text' ], dst[ 'text' ]
+             template.write(srcName + ':' + dstName + '\n')
+
+	template.close()   
+
+
+    # Generic canvas handler
+    #
+    # We could have used bindtags, as in nodeIcon, but
+    # the dynamic approach used here
+    # may actually require less code. In any case, it's an
+    # interesting introspection-based alternative to bindtags.
+
+    def canvasHandle( self, eventName, event ):
+        "Generic canvas event handler"
+        if self.active is None:
+            return
+        toolName = self.active
+        handler = getattr( self, eventName + toolName, None )
+        if handler is not None:
+            handler( event )
+
+    def clickCanvas( self, event ):
+        "Canvas click handler."
+        self.canvasHandle( 'click', event )
+
+    def dragCanvas( self, event ):
+        "Canvas drag handler."
+        self.canvasHandle( 'drag', event )
+
+    def releaseCanvas( self, event ):
+        "Canvas mouse up handler."
+        self.canvasHandle( 'release', event )
+
+    # Currently the only items we can select directly are
+    # links. Nodes are handled by bindings in the node icon.
+
+    def findItem( self, x, y ):
+        "Find items at a location in our canvas."
+        items = self.canvas.find_overlapping( x, y, x, y )
+        if len( items ) == 0:
+            return None
+        else:
+            return items[ 0 ]
+
+    # Canvas bindings for Select, Host, Switch and Link tools
+
+    def clickSelect( self, event ):
+        "Select an item."
+        self.selectItem( self.findItem( event.x, event.y ) )
+
+    def deleteItem( self, item ):
+        "Delete an item."
+        # Don't delete while network is running
+        if self.buttons[ 'Select' ][ 'state' ] == 'disabled':
+            return
+        # Delete from model
+        if item in self.links:
+            self.deleteLink( item )
+        if item in self.itemToWidget:
+            self.deleteNode( item )
+        # Delete from view
+        self.canvas.delete( item )
+
+    def deleteSelection( self, _event ):
+        "Delete the selected item."
+        if self.selection is not None:
+            self.deleteItem( self.selection )
+        self.selectItem( None )
+
+    def nodeIcon( self, node, name ):
+        "Create a new node icon."
+        icon = Button( self.canvas, image=self.images[ node ],
+                       text=name, compound='top' )
+        # Unfortunately bindtags wants a tuple
+        bindtags = [ str( self.nodeBindings ) ]
+        bindtags += list( icon.bindtags() )
+        icon.bindtags( tuple( bindtags ) )
+        return icon
+
+    def newNode( self, node, event ):
+        "Add a new node to our canvas."
+        c = self.canvas
+        x, y = c.canvasx( event.x ), c.canvasy( event.y )
+        self.nodeCount += 1
+        name = self.nodePrefixes[ node ] + str( self.nodeCount )
+        icon = self.nodeIcon( node, name )
+        item = self.canvas.create_window( x, y, anchor='c', window=icon,
+                                          tags=node )
+        self.widgetToItem[ icon ] = item
+        self.itemToWidget[ item ] = icon
+        self.selectItem( item )
+        icon.links = {}
+
+    def clickHost( self, event ):
+        "Add a new host to our canvas."
+        self.newNode( 'Host', event )
+
+    def clickSwitch( self, event ):
+        "Add a new switch to our canvas."
+        self.newNode( 'Switch', event )
+
+    def dragLink( self, event ):
+        "Drag a link's endpoint to another node."
+        if self.link is None:
+            return
+        # Since drag starts in widget, we use root coords
+        x = self.canvasx( event.x_root )
+        y = self.canvasy( event.y_root )
+        c = self.canvas
+        c.coords( self.link, self.linkx, self.linky, x, y )
+
+    def releaseLink( self, _event ):
+        "Give up on the current link."
+        if self.link is not None:
+            self.canvas.delete( self.link )
+        self.linkWidget = self.linkItem = self.link = None
+
+    # Generic node handlers
+
+    def createNodeBindings( self ):
+        "Create a set of bindings for nodes."
+        bindings = {
+            '<ButtonPress-1>': self.clickNode,
+            '<B1-Motion>': self.dragNode,
+            '<ButtonRelease-1>': self.releaseNode,
+            '<Enter>': self.enterNode,
+            '<Leave>': self.leaveNode,
+            '<Double-ButtonPress-1>': self.xterm
+        }
+        l = Label()  # lightweight-ish owner for bindings
+        for event, binding in bindings.items():
+            l.bind( event, binding )
+        return l
+
+    def selectItem( self, item ):
+        "Select an item and remember old selection."
+        self.lastSelection = self.selection
+        self.selection = item
+
+    def enterNode( self, event ):
+        "Select node on entry."
+        self.selectNode( event )
+
+    def leaveNode( self, _event ):
+        "Restore old selection on exit."
+        self.selectItem( self.lastSelection )
+
+    def clickNode( self, event ):
+        "Node click handler."
+        if self.active is 'Link':
+            self.startLink( event )
+        else:
+            self.selectNode( event )
+        return 'break'
+
+    def dragNode( self, event ):
+        "Node drag handler."
+        if self.active is 'Link':
+            self.dragLink( event )
+        else:
+            self.dragNodeAround( event )
+
+    def releaseNode( self, event ):
+        "Node release handler."
+        if self.active is 'Link':
+            self.finishLink( event )
+
+    # Specific node handlers
+
+    def selectNode( self, event ):
+        "Select the node that was clicked on."
+        item = self.widgetToItem.get( event.widget, None )
+        self.selectItem( item )
+
+    def dragNodeAround( self, event ):
+        "Drag a node around on the canvas."
+        c = self.canvas
+        # Convert global to local coordinates;
+        # Necessary since x, y are widget-relative
+        x = self.canvasx( event.x_root )
+        y = self.canvasy( event.y_root )
+        w = event.widget
+        # Adjust node position
+        item = self.widgetToItem[ w ]
+        c.coords( item, x, y )
+        # Adjust link positions
+        for dest in w.links:
+            link = w.links[ dest ]
+            item = self.widgetToItem[ dest ]
+            x1, y1 = c.coords( item )
+            c.coords( link, x, y, x1, y1 )
+
+    def startLink( self, event ):
+        "Start a new link."
+        if event.widget not in self.widgetToItem:
+            # Didn't click on a node
+            return
+        w = event.widget
+        item = self.widgetToItem[ w ]
+        x, y = self.canvas.coords( item )
+        self.link = self.canvas.create_line( x, y, x, y, width=4,
+                                             fill='blue', tag='link' )
+        self.linkx, self.linky = x, y
+        self.linkWidget = w
+        self.linkItem = item
+
+        # Link bindings
+        # Selection still needs a bit of work overall
+        # Callbacks ignore event
+
+        def select( _event, link=self.link ):
+            "Select item on mouse entry."
+            self.selectItem( link )
+
+        def highlight( _event, link=self.link ):
+            "Highlight item on mouse entry."
+            # self.selectItem( link )
+            self.canvas.itemconfig( link, fill='green' )
+
+        def unhighlight( _event, link=self.link ):
+            "Unhighlight item on mouse exit."
+            self.canvas.itemconfig( link, fill='blue' )
+            # self.selectItem( None )
+
+        self.canvas.tag_bind( self.link, '<Enter>', highlight )
+        self.canvas.tag_bind( self.link, '<Leave>', unhighlight )
+        self.canvas.tag_bind( self.link, '<ButtonPress-1>', select )
+
+    def finishLink( self, event ):
+        "Finish creating a link"
+        if self.link is None:
+            return
+        source = self.linkWidget
+        c = self.canvas
+        # Since we dragged from the widget, use root coords
+        x, y = self.canvasx( event.x_root ), self.canvasy( event.y_root )
+        target = self.findItem( x, y )
+        dest = self.itemToWidget.get( target, None )
+        if ( source is None or dest is None or source == dest
+                or dest in source.links or source in dest.links ):
+            self.releaseLink( event )
+            return
+        # For now, don't allow hosts to be directly linked
+#        stags = self.canvas.gettags( self.widgetToItem[ source ] )
+#        dtags = self.canvas.gettags( target )
+#        if 'Host' in stags and 'Host' in dtags:
+#            self.releaseLink( event )
+#            return
+        x, y = c.coords( target )
+        c.coords( self.link, self.linkx, self.linky, x, y )
+        self.addLink( source, dest )
+        # We're done
+        self.link = self.linkWidget = None
+
+    # Menu handlers
+
+    def about( self ):
+        "Display about box."
+        about = self.aboutBox
+        if about is None:
+            bg = 'white'
+            about = Toplevel( bg='white' )
+            about.title( 'About' )
+            info = self.appName + ': a simple network editor for Mini-CCNx - based on Miniedit '
+            warning = 'Development version - not entirely functional!'
+	    author = 'Carlos Cabral, Jan 2013'
+            author2 = 'Miniedit by Bob Lantz <rlantz@cs>, April 2010'
+            line1 = Label( about, text=info, font='Helvetica 10 bold', bg=bg )
+            line2 = Label( about, text=warning, font='Helvetica 9', bg=bg )
+            line3 = Label( about, text=author, font='Helvetica 9', bg=bg )
+	    line4 = Label( about, text=author2, font='Helvetica 9', bg=bg )
+            line1.pack( padx=20, pady=10 )
+            line2.pack(pady=10 )
+            line3.pack(pady=10 )
+	    line4.pack(pady=10 )
+            hide = ( lambda about=about: about.withdraw() )
+            self.aboutBox = about
+            # Hide on close rather than destroying window
+            Wm.wm_protocol( about, name='WM_DELETE_WINDOW', func=hide )
+        # Show (existing) window
+        about.deiconify()
+
+    def createToolImages( self ):
+        "Create toolbar (and icon) images."
+
+    # Model interface
+    #
+    # Ultimately we will either want to use a topo or
+    # mininet object here, probably.
+
+    def addLink( self, source, dest ):
+        "Add link to model."
+        source.links[ dest ] = self.link
+        dest.links[ source ] = self.link
+        self.links[ self.link ] = ( source, dest )
+
+    def deleteLink( self, link ):
+        "Delete link from model."
+        pair = self.links.get( link, None )
+        if pair is not None:
+            source, dest = pair
+            del source.links[ dest ]
+            del dest.links[ source ]
+        if link is not None:
+            del self.links[ link ]
+
+    def deleteNode( self, item ):
+        "Delete node (and its links) from model."
+        widget = self.itemToWidget[ item ]
+        for link in widget.links.values():
+            # Delete from view and model
+            self.deleteItem( link )
+        del self.itemToWidget[ item ]
+        del self.widgetToItem[ widget ]
+
+    def build( self ):
+        "Build network based on our topology."
+
+        net = Mininet( topo=None )
+
+        # Make controller
+        net.addController( 'c0' )
+        # Make nodes
+        for widget in self.widgetToItem:
+            name = widget[ 'text' ]
+            tags = self.canvas.gettags( self.widgetToItem[ widget ] )
+            nodeNum = int( name[ 1: ] )
+            if 'Switch' in tags:
+                net.addSwitch( name )
+            elif 'Host' in tags:
+                net.addHost( name, ip=ipStr( nodeNum ) )
+            else:
+                raise Exception( "Cannot create mystery node: " + name )
+        # Make links
+        for link in self.links.values():
+            ( src, dst ) = link
+            srcName, dstName = src[ 'text' ], dst[ 'text' ]
+            src, dst = net.nameToNode[ srcName ], net.nameToNode[ dstName ]
+            src.linkTo( dst )
+
+        # Build network (we have to do this separately at the moment )
+        net.build()
+
+        return net
+
+    def start( self ):
+        "Start network."
+        if self.net is None:
+            self.net = self.build()
+            self.net.start()
+
+    def stop( self ):
+        "Stop network."
+        if self.net is not None:
+            self.net.stop()
+        cleanUpScreens()
+        self.net = None
+
+    def xterm( self, _ignore=None ):
+        "Make an xterm when a button is pressed."
+        if ( self.selection is None or
+             self.net is None or
+             self.selection not in self.itemToWidget ):
+            return
+        name = self.itemToWidget[ self.selection ][ 'text' ]
+        if name not in self.net.nameToNode:
+            return
+        term = makeTerm( self.net.nameToNode[ name ], 'Host' )
+        self.net.terms.append( term )
+
+
+def miniEditImages():
+    "Create and return images for MiniEdit."
+
+    # Image data. Git will be unhappy. However, the alternative
+    # is to keep track of separate binary files, which is also
+    # unappealing.
+
+    return {
+        'Select': BitmapImage(
+            file='/usr/include/X11/bitmaps/left_ptr' ),
+
+	'Switch' : PhotoImage( data=r"""
+	   R0lGODlhOgArAMIEAB8aFwB7tQCb343L8P///////////////yH+GlNvZnR3YXJlOiBNaWNyb3NvZnQgT2ZmaWNlACwAAAAAOgArAAAD/ki63P4wykmrvTjr3YYfQigKH7d5Y6qmnjmBayyHg8vAAqDPaUTbowaA13OIahqcyEgEQEbIi7LIGA1FzsaSQK0QfbnH10sMa83VsqX53HLL7sgUTudR5s367F7PEq4CYDJRcngqfgshiAqAMwF3AYdWTCERjSoBjy+ZVItvMg6XIZmaEgOkSmJwlKOkkKSRlaqraaewr7ABhnqBNLmZuL+6vCzCrpvGsB9EH8m5wc7R0sbQ09bT1dOEBLbXwMjeEN7HpuO6Dt3hFObi7Ovj7d7bEOnYD+4V8PfqF/wN/lKsxZPmop6wBwaFzTsRbVvCWzYQmlMW0UKzZCUqatzICLGjx48gKyYAADs=
+"""),
+	'Host' : PhotoImage( data=r"""
+	    R0lGODlhKQAyAMIHAJyeoK+wsrW2uMHCxM7P0Ozt7fn5+f///yH+EUNyZWF0ZWQgd2l0aCBHSU1QACwAAAAAKQAyAAAD63i63P4wykmrvS4cwLv/IEhxRxGeKGBM3pa+X9QeBmxrT3gMNpyLrt6rgcJgisKXgIFMopaLpjMEVUinn2pQ1ImSrN8uGKCVegHn8bl8CqbV7jFbJ47H650592sX4zl6MX9ocIOBLYNvhkxtiYV8eYx0kJSEi2d7WFmSmZqRmIKeHoddoqOcoaZkqIiqq6CtqqQkrq9jnaKzaLW6Wy8DBMHCp7ClPT+ArMY2t1u9Qs3Et6k+W87KtMfW0r6x1d7P2uDYu+LLtt3nQ9ufxeXM7MkOuCnR7UTe6/jyEOqeWj/SYQEowxXBfgYPJAAAOw==
+"""),
+        'Link': PhotoImage( data=r"""
+            R0lGODlhFgAWAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
+            mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
+            Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
+            M/8AAMz//8z/zMz/mcz/Zsz/M8z/AMzM/8zMzMzMmczMZszMM8zM
+            AMyZ/8yZzMyZmcyZZsyZM8yZAMxm/8xmzMxmmcxmZsxmM8xmAMwz
+            /8wzzMwzmcwzZswzM8wzAMwA/8wAzMwAmcwAZswAM8wAAJn//5n/
+            zJn/mZn/Zpn/M5n/AJnM/5nMzJnMmZnMZpnMM5nMAJmZ/5mZzJmZ
+            mZmZZpmZM5mZAJlm/5lmzJlmmZlmZplmM5lmAJkz/5kzzJkzmZkz
+            ZpkzM5kzAJkA/5kAzJkAmZkAZpkAM5kAAGb//2b/zGb/mWb/Zmb/
+            M2b/AGbM/2bMzGbMmWbMZmbMM2bMAGaZ/2aZzGaZmWaZZmaZM2aZ
+            AGZm/2ZmzGZmmWZmZmZmM2ZmAGYz/2YzzGYzmWYzZmYzM2YzAGYA
+            /2YAzGYAmWYAZmYAM2YAADP//zP/zDP/mTP/ZjP/MzP/ADPM/zPM
+            zDPMmTPMZjPMMzPMADOZ/zOZzDOZmTOZZjOZMzOZADNm/zNmzDNm
+            mTNmZjNmMzNmADMz/zMzzDMzmTMzZjMzMzMzADMA/zMAzDMAmTMA
+            ZjMAMzMAAAD//wD/zAD/mQD/ZgD/MwD/AADM/wDMzADMmQDMZgDM
+            MwDMAACZ/wCZzACZmQCZZgCZMwCZAABm/wBmzABmmQBmZgBmMwBm
+            AAAz/wAzzAAzmQAzZgAzMwAzAAAA/wAAzAAAmQAAZgAAM+4AAN0A
+            ALsAAKoAAIgAAHcAAFUAAEQAACIAABEAAADuAADdAAC7AACqAACI
+            AAB3AABVAABEAAAiAAARAAAA7gAA3QAAuwAAqgAAiAAAdwAAVQAA
+            RAAAIgAAEe7u7t3d3bu7u6qqqoiIiHd3d1VVVURERCIiIhEREQAA
+            ACH5BAEAAAAALAAAAAAWABYAAAhIAAEIHEiwoEGBrhIeXEgwoUKG
+            Cx0+hGhQoiuKBy1irChxY0GNHgeCDAlgZEiTHlFuVImRJUWXEGEy
+            lBmxI8mSNknm1Dnx5sCAADs=
+        """ )
+    }
+
+if __name__ == '__main__':
+    setLogLevel( 'info' )
+    temp_file = parse_args()
+    app = MiniEdit(template_file=temp_file)
+    app.mainloop()