Xen 
 
Home About Xen.org Xen Xen Summit Wiki Mailing List Bug Tracker Xen Downloads
 
   
 

xen-changelog

[Xen-changelog] merge?

# HG changeset patch
# User cl349@xxxxxxxxxxxxxxxxxxxx
# Node ID 2333f6616d184251753b052b8bf0e05b81cc2d42
# Parent  69beaae8a1fa2748d66f39bb899e14f5b84a8dd1
# Parent  22984cc20ff99c44db9bc925c197cd2bc53b270a
merge?

diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/setup.py
--- a/tools/python/setup.py     Tue Jul 26 17:38:33 2005
+++ b/tools/python/setup.py     Tue Jul 26 18:41:39 2005
@@ -51,6 +51,7 @@
                          'xen.xend.xenstore',
                          'xen.xm',
                          'xen.web',
+                                                'xen.sv'
                          ],
       ext_package = "xen.lowlevel",
       ext_modules = [ xc, xu, xs ]
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/xend/image.py
--- a/tools/python/xen/xend/image.py    Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/xend/image.py    Tue Jul 26 18:41:39 2005
@@ -130,7 +130,13 @@
         # xc.domain_setuuid(dom, uuid)
         xc.domain_setcpuweight(dom, cpu_weight)
         xc.domain_setmaxmem(dom, mem_kb)
-        xc.domain_memory_increase_reservation(dom, mem_kb)
+
+        try:
+            xc.domain_memory_increase_reservation(dom, mem_kb)
+        except:
+            xc.domain_destroy(dom)
+            raise
+
         if cpu != -1:
             xc.domain_pincpu(dom, 0, 1<<int(cpu))
         return dom
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py       Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/xm/main.py       Tue Jul 26 18:41:39 2005
@@ -11,6 +11,13 @@
 
 from xen.xend import PrettyPrint
 from xen.xend import sxp
+# this is a nasty place to stick this in, but required because
+# log file access is set up via a 5 deep import chain.  This
+# ensures the user sees a useful message instead of a stack trace
+if os.getuid() != 0:
+    print "xm requires root access to execute, please try again as root"
+    sys.exit(1)
+
 from xen.xend.XendClient import XendError, server
 from xen.xend.XendClient import main as xend_client_main
 from xen.xm import create, destroy, migrate, shutdown, sysrq
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/CreateDomain.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/CreateDomain.py       Tue Jul 26 18:41:39 2005
@@ -0,0 +1,163 @@
+from xen.sv.Wizard import *
+from xen.sv.util import *
+from xen.sv.GenTabbed import PreTab
+
+from xen.xm.create import make_config, OptVals
+
+from xen.xend.XendClient import server
+
+class CreateDomain( Wizard ):
+    def __init__( self, urlWriter ):
+       
+       sheets = [ CreatePage0,
+                  CreatePage1,
+                  CreatePage2,
+                   CreatePage3,
+                   CreatePage4,
+                   CreateFinish ]
+    
+       Wizard.__init__( self, urlWriter, "Create Domain", sheets )
+       
+class CreatePage0( Sheet ):
+
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "General", 0 )
+        self.addControl( InputControl( 'name', 'VM Name', 'VM Name:', 
"[\\w|\\S]+", "You must enter a name in this field" ) )
+        self.addControl( InputControl( 'memory', '64', 'Memory (Mb):', 
"[\\d]+", "You must enter a number in this field" ) )
+        self.addControl( InputControl( 'cpu', '0', 'CPU:', "[\\d]+", "You must 
enter a number in this feild" ) )
+        self.addControl( InputControl( 'cpu_weight', '1', 'CPU Weight:', 
"[\\d]+", "You must enter a number in this feild" ) )
+                        
+class CreatePage1( Sheet ):
+
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Setup Kernel Image", 1 )
+# For now we don't need to select a builder...
+#        self.addControl( ListControl( 'builder', [('linux', 'Linux'), 
('netbsd', 'NetBSD')], 'Kernel Type:' ) )
+        self.addControl( FileControl( 'kernel', '/boot/vmlinuz-2.6.9-xenU', 
'Kernel Image:' ) )
+        self.addControl( InputControl( 'extra', '', 'Kernel Command Line 
Parameters:' ) )
+
+class CreatePage2( Sheet ):
+
+    def __init__( self, urlWriter ):
+       Sheet.__init__( self, urlWriter, "Setup Virtual Block Device", 2 )
+        self.addControl( InputControl( 'num_vbds', '1', 'Number of VBDs:', 
'[\\d]+', "You must enter a number in this field" ) )
+
+class CreatePage3( Sheet ):
+
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Setup Virtual Block Device", 3 )
+        
+    def write_BODY( self, request, err ):
+        if not self.passback: self.parseForm( request )
+    
+       previous_values = sxp2hash( string2sxp( self.passback ) ) #get the hash 
for quick reference
+        
+        num_vbds = previous_values.get( 'num_vbds' )
+        
+        for i in range( int( num_vbds ) ):
+            self.addControl( InputControl( 'vbd%s_dom0' % i, 'phy:sda%s' % 
str(i + 1), 'Device %s name:' % i  ) )
+            self.addControl( InputControl( 'vbd%s_domU' % i, 'sda%s' % str(i + 
1), 'Virtualized device %s:' % i ) )
+            self.addControl( ListControl( 'vbd%s_mode' % i, [('w', 'Read + 
Write'), ('r', 'Read Only')], 'Device %s mode:' % i ) )
+            
+        self.addControl( InputControl( 'root', '/dev/sda1', 'Root device (in 
VM):' ) )
+        
+        Sheet.write_BODY( self, request, err )
+                
+class CreatePage4( Sheet ):
+
+    def __init__( self, urlWriter ):        
+        Sheet.__init__( self, urlWriter, "Network settings", 4 )
+        self.addControl( ListControl( 'dhcp', [('off', 'No'), ('dhcp', 
'Yes')], 'Use DHCP:' ) )
+        self.addControl( InputControl( 'hostname', 'hostname', 'VM Hostname:' 
) )
+        self.addControl( InputControl( 'ip_addr', '1.2.3.4', 'VM IP Address:' 
) )
+        self.addControl( InputControl( 'ip_subnet', '255.255.255.0', 'VM 
Subnet Mask:' ) ) 
+        self.addControl( InputControl( 'ip_gateway', '1.2.3.4', 'VM Gateway:' 
) )           
+        self.addControl( InputControl( 'ip_nfs', '1.2.3.4', 'NFS Server:' ) )  
+                 
+class CreateFinish( Sheet ):
+
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "All Done", 5 )
+        
+    def write_BODY( self, request, err ):
+    
+        if not self.passback: self.parseForm( request )
+        
+        xend_sxp = self.translate_sxp( string2sxp( self.passback ) )
+        
+        try:
+            dom_sxp = server.xend_domain_create( xend_sxp )
+            success = "Your domain was successfully created.\n"
+        except:
+            success = "There was an error creating your domain.\nThe 
configuration used is as follows:\n"
+            dom_sxp = xend_sxp
+            
+            
+        
+        pt = PreTab( success + sxp2prettystring( dom_sxp ) )
+        pt.write_BODY( request )
+
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
+    
+    def translate_sxp( self, fin_sxp ):
+       fin_hash = ssxp2hash( fin_sxp )
+    
+        def get( key ):
+            ret = fin_hash.get( key )
+            if ret:
+                return ret
+            else:
+                return ""
+        
+       vals = OptVals()
+        
+        vals.name =    get( 'name' )
+        vals.memory =  get( 'memory' )
+        vals.maxmem =   get( 'maxmem' )
+        vals.cpu =     get( 'cpu' )
+        vals.cpu_weight = get( 'cpu_weight' )
+        
+        vals.builder =  get( 'builder' )       
+        vals.kernel =   get( 'kernel' )
+       vals.root =     get( 'root' )
+        vals.extra =   get( 'extra' )
+        
+        #setup vbds
+        
+        vbds = []
+        
+        for i in range( int( get( 'num_vbds' ) ) ):
+            vbds.append( ( get( 'vbd%s_dom0' % i ), get('vbd%s_domU' % i ), 
get( 'vbd%s_mode' % i ) ) )
+        
+        vals.disk = vbds    
+            
+        #misc
+        
+        vals.pci = []
+        
+        vals.blkif = None
+        vals.netif = None
+        vals.restart = None
+        vals.console = None
+        vals.ramdisk = None
+        
+        #setup vifs
+        
+        vals.vif = []
+        vals.nics = 1
+                
+        ip =   get( 'ip_addr' )
+        nfs =  get( 'ip_nfs' )
+        gate = get( 'ip_gateway' )
+        mask = get( 'ip_subnet' )
+        host = get( 'hostname' )
+        dhcp = get( 'dhcp' )
+        
+        vals.cmdline_ip = "%s:%s:%s:%s:%s:eth0:%s" % (ip, nfs, gate, mask, 
host, dhcp)
+        
+        try:
+            return make_config( vals )
+        except:
+            return [["Error creating domain config."]]    
+        
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/Daemon.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/Daemon.py     Tue Jul 26 18:41:39 2005
@@ -0,0 +1,110 @@
+###########################################################
+## XenSV Web Control Interface Daemon
+## Copyright (C) 2004, K A Fraser (University of Cambridge)
+## Copyright (C) 2004, Mike Wray <mike.wray@xxxxxx>
+## Copyright (C) 2004, Tom Wilkie <tw275@xxxxxxxxx>
+###########################################################
+
+import os
+import os.path
+import sys
+import re
+
+from xen.sv.params import *
+
+from twisted.internet import reactor
+from twisted.web import static, server, script
+
+from xen.util.ip import _readline, _readlines
+
+class Daemon:
+    """The xend daemon.
+    """
+    def __init__(self):
+        self.shutdown = 0
+        self.traceon = 0
+
+    def daemon_pids(self):
+        pids = []
+        pidex = '(?P<pid>\d+)'
+        pythonex = '(?P<python>\S*python\S*)'
+        cmdex = '(?P<cmd>.*)'
+        procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex 
+ '$')
+        xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
+        procs = os.popen('ps -e -o pid,args 2>/dev/null')
+        for proc in procs:
+            pm = procre.match(proc)
+            if not pm: continue
+            xm = xendre.match(pm.group('cmd'))
+            if not xm: continue
+            #print 'pid=', pm.group('pid'), 'cmd=', pm.group('cmd')
+            pids.append(int(pm.group('pid')))
+        return pids
+
+    def new_cleanup(self, kill=0):
+        err = 0
+        pids = self.daemon_pids()
+        if kill:
+            for pid in pids:
+                print "Killing daemon pid=%d" % pid
+                os.kill(pid, signal.SIGHUP)
+        elif pids:
+            err = 1
+            print "Daemon already running: ", pids
+        return err
+            
+    def cleanup(self, kill=False):
+        # No cleanup to do if PID_FILE is empty.
+        if not os.path.isfile(PID_FILE) or not os.path.getsize(PID_FILE):
+            return 0
+        # Read the pid of the previous invocation and search active process 
list.
+        pid = open(PID_FILE, 'r').read()
+        lines = _readlines(os.popen('ps ' + pid + ' 2>/dev/null'))
+        for line in lines:
+            if re.search('^ *' + pid + '.+xensv', line):
+                if not kill:
+                    print "Daemon is already running (pid %d)" % int(pid)
+                    return 1
+                # Old daemon is still active: terminate it.
+                os.kill(int(pid), 1)
+        # Delete the stale PID_FILE.
+        os.remove(PID_FILE)
+        return 0
+
+    def start(self, trace=0):
+        if self.cleanup(kill=False):
+            return 1
+   
+        # Fork -- parent writes PID_FILE and exits.
+        pid = os.fork()
+        if pid:
+            # Parent
+            pidfile = open(PID_FILE, 'w')
+            pidfile.write(str(pid))
+            pidfile.close()
+            return 0
+        # Child
+        self.run()
+        return 0
+
+    def stop(self):
+        return self.cleanup(kill=True)
+
+    def run(self):
+       root = static.File( SV_ROOT )
+        root.indexNames = [ 'Main.rpy' ]
+        root.processors = { '.rpy': script.ResourceScript }
+        reactor.listenTCP( SV_PORT, server.Site( root ) )
+        reactor.run()
+
+    def exit(self):
+        reactor.disconnectAll()
+        sys.exit(0)
+
+def instance():
+    global inst
+    try:
+        inst
+    except:
+        inst = Daemon()
+    return inst
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/DomInfo.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/DomInfo.py    Tue Jul 26 18:41:39 2005
@@ -0,0 +1,148 @@
+from xen.xend.XendClient import server
+from xen.xend import PrettyPrint
+
+from xen.sv.HTMLBase import HTMLBase
+from xen.sv.util import *
+from xen.sv.GenTabbed import *
+
+DEBUG=1
+
+class DomInfo( GenTabbed ):
+
+    def __init__( self, urlWriter ):
+        
+        self.dom = 0;
+    
+        def tabUrlWriter( tab ):
+            return urlWriter( "&dom=%s%s" % ( self.dom, tab ) )
+        
+        GenTabbed.__init__( self, "Domain Info", tabUrlWriter, [ 'General', 
'SXP', 'Devices' ], [ DomGeneralTab, DomSXPTab, NullTab ]  )
+
+    def write_BODY( self, request ):
+        dom = request.args.get('dom')
+        
+        if dom is None or len(dom) != 1:
+            request.write( "<p>Please Select a Domain</p>" )
+            return None
+        else:
+            self.dom = dom[0]
+        
+        GenTabbed.write_BODY( self, request )
+        
+    def write_MENU( self, request ):
+        pass
+
+class DomGeneralTab( CompositeTab ):
+    def __init__( self ):
+       CompositeTab.__init__( self, [ DomGenTab, DomActionTab ] )        
+        
+class DomGenTab( GeneralTab ):
+
+    def __init__( self ):
+    
+        titles = {}
+    
+        titles[ 'ID' ] = 'dom'      
+        titles[ 'Name' ] = 'name'
+        titles[ 'CPU' ] = 'cpu'
+        titles[ 'Memory' ] = ( 'mem', memoryFormatter )
+        titles[ 'State' ] = ( 'state', stateFormatter )
+        titles[ 'Total CPU' ] = ( 'cpu_time', smallTimeFormatter )
+        titles[ 'Up Time' ] = ( 'up_time', bigTimeFormatter )
+    
+        GeneralTab.__init__( self, {}, titles )
+        
+    def write_BODY( self, request ):
+    
+        self.dom = getVar('dom', request)
+        
+        if self.dom is None:
+            request.write( "<p>Please Select a Domain</p>" )
+            return None
+            
+        self.dict = getDomInfoHash( self.dom )
+        
+        GeneralTab.write_BODY( self, request )
+            
+class DomSXPTab( PreTab ):
+
+    def __init__( self ):
+        self.dom = 0
+        PreTab.__init__( self, "" )
+
+
+    def write_BODY( self, request ):
+        self.dom = getVar('dom', request)
+        
+        if self.dom is None:
+            request.write( "<p>Please Select a Domain</p>" )
+            return None
+
+        try:
+            domInfo = server.xend_domain( self.dom )
+        except:
+            domInfo = [["Error getting domain details."]]
+            
+        self.source = sxp2prettystring( domInfo )
+        
+        PreTab.write_BODY( self, request )
+        
+class DomActionTab( ActionTab ):
+
+    def __init__( self ):
+       actions = { "shutdown" : "shutdown",
+                   "reboot" : "reboot",
+                    "pause" : "pause",
+                    "unpause" : "unpause",
+                    "destroy" : "destroy" }
+        ActionTab.__init__( self, actions )    
+        
+    def op_shutdown( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+          if DEBUG: print ">DomShutDown %s" % dom
+           try:
+               server.xend_domain_shutdown( int( dom ), "halt" )
+           except:
+               pass
+    
+    def op_reboot( self, request ):
+               dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+           if DEBUG: print ">DomReboot %s" % dom
+            try:
+               server.xend_domain_shutdown( int( dom ), "reboot" )
+            except:
+               pass
+                
+    def op_pause( self, request ):
+               dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+           if DEBUG: print ">DomPause %s" % dom
+            try:
+                server.xend_domain_pause( int( dom ) )
+            except:
+               pass
+               
+    def op_unpause( self, request ):
+               dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+          if DEBUG: print ">DomUnpause %s" % dom
+           try:
+               server.xend_domain_unpause( int( dom ) )
+          except:
+               pass
+               
+    def op_destroy( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != '0':
+          if DEBUG: print ">DomDestroy %s" % dom
+           try:
+               server.xend_domain_destroy( int( dom ), "halt" )
+           except:
+               pass
+        
+    
+    
+        
+
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/DomList.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/DomList.py    Tue Jul 26 18:41:39 2005
@@ -0,0 +1,81 @@
+from xen.xend.XendClient import server
+from xen.xend import sxp
+
+from xen.sv.HTMLBase import HTMLBase
+from xen.sv.util import *
+
+class DomList( HTMLBase ):
+    
+    isLeaf = True
+
+    def __init__( self, urlWriter ):
+        HTMLBase.__init__(self)
+        self.urlWriter = urlWriter
+        
+    def write_MENU( self, request ):
+       return self.write_BODY( request, head=True, long=False ) 
+
+    def write_BODY( self, request, head=True, long=True ):
+        
+       domains = []
+    
+        try:
+            domains = server.xend_domains()
+            domains.sort()
+       except:
+            pass
+                
+        request.write( "\n<table style='border:0px solid white' 
cellspacing='0' cellpadding='0' border='0' width='100%'>\n" )
+        
+        if head:
+            request.write( "<tr class='domainInfoHead'>" )
+            self.write_DOMAIN_HEAD( request, long )
+            request.write( "</tr>" )
+        
+        odd = True
+        
+        if not domains is None:
+            for domain in domains:
+                if odd:
+                    request.write( "<tr class='domainInfoOdd'>\n" )
+                    odd = False
+                else:
+                    request.write( "<tr class='domainInfoEven'>\n" )
+                    odd = True
+                self.write_DOMAIN( request, getDomInfoHash( domain ), long )
+                request.write( "</tr>\n" )
+        else:
+               request.write( "<tr colspan='10'><p class='small'>Error getting 
domain list<br/>Perhaps XenD not running?</p></tr>")
+                
+        request.write( "</table>\n" )
+            
+    def write_DOMAIN( self, request, domInfoHash, long=True ):   
+        request.write( "<td class='domainInfo' align='center'>%(id)s</td>\n" % 
domInfoHash )
+
+        url = self.urlWriter( "&mod=info&dom=%(id)s" % domInfoHash )
+
+        request.write( "<td class='domainInfo' align='center'><a 
href='%s'>%s</a></td>\n" % ( url, domInfoHash['name'] ) )
+        if long: 
+            request.write( "<td class='domainInfo' 
align='center'>%(memory)5s</td>\n" % domInfoHash )
+            request.write( "<td class='domainInfo' 
align='center'>%(cpu)2s</td>\n" % domInfoHash )
+        request.write( "<td class='domainInfo' 
align='center'>%(state)5s</td>\n" % domInfoHash )
+        if domInfoHash[ 'id' ] != "0":
+            request.write( "<td class='domainInfo' align='center'>" )
+            
+            if domInfoHash[ 'state' ][ 2 ] == "-":
+                request.write( "<img src='images/small-pause.png' 
onclick='doOp2( \"pause\", \"%(dom)-4s\" )'>" % domInfoHash )
+            else:
+                request.write( "<img src='images/small-unpause.png' 
onclick='doOp2( \"unpause\", \"%(dom)-4s\" )'>" % domInfoHash )              
+            
+            request.write( "<img src='images/small-destroy.png' 
onclick='doOp2( \"destroy\", \"%(dom)-4s\" )'></td>" % domInfoHash)
+        else:
+            request.write( "<td>&nbsp;</td>" )
+
+    def write_DOMAIN_HEAD( self, request, long=True ):
+        request.write( "<td class='domainInfoHead' 
align='center'>Domain</td>\n" )      
+        request.write( "<td class='domainInfoHead' align='center'>Name</td>\n" 
)      
+        if long:
+            request.write( "<td class='domainInfoHead' align='center'>Memory / 
Mb</td>\n" )      
+            request.write( "<td class='domainInfoHead' 
align='center'>CPU</td>\n" )      
+        request.write( "<td class='domainInfoHead' 
align='center'>State</td>\n" )      
+        request.write( "<td class='domainInfoHead' align='center'></td>\n" )
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/GenTabbed.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/GenTabbed.py  Tue Jul 26 18:41:39 2005
@@ -0,0 +1,135 @@
+import types
+
+from xen.sv.HTMLBase import HTMLBase
+from xen.sv.TabView import TabView
+from xen.sv.util import getVar
+
+class GenTabbed( HTMLBase ):
+
+    def __init__( self, title, urlWriter, tabStrings, tabObjects ):
+        HTMLBase.__init__(self)
+        self.tabStrings = tabStrings
+        self.tabObjects = tabObjects
+        self.urlWriter = urlWriter
+        self.title = title
+
+    def write_BODY( self, request, urlWriter = None ):
+        try:
+            tab = int( getVar( 'tab', request, 0 ) )
+        except:
+            tab = 0
+            
+        request.write( "<table style='' width='100%' border='0' 
cellspacing='0' cellpadding='0'>" )
+        request.write( "<tr><td>" )
+        request.write( "<p align='center'><u>%s</u></p>" % self.title )
+        
+        TabView( tab, self.tabStrings, self.urlWriter ).write_BODY( request )
+        
+        request.write( "</td></tr><tr><td>" )
+
+        try:
+            render_tab = self.tabObjects[ tab ]
+            render_tab().write_BODY( request )
+        except:
+            request.write( "<p>Error Rendering Tab</p>" )
+       
+        request.write( "</td></tr></table>" )
+       
+    def perform( self, request ):
+        try:
+            tab = int( getVar( 'tab', request, 0 ) )
+        except:
+            tab = 0;
+            
+        op_tab = self.tabObjects[ tab ]
+        
+        if op_tab:
+            op_tab().perform( request )
+        
+class PreTab( HTMLBase ):
+
+    def __init__( self, source ):
+        HTMLBase.__init__( self )
+        self.source = source
+    
+    def write_BODY( self, request ):
+        
+        request.write( "<div style='display: block; overflow: auto; border: 
0px solid black; width: 540px; padding: 5px; z-index:0; align: center'><pre>" )
+        
+        request.write( self.source )
+        
+        request.write( "</pre></div>" )
+
+class GeneralTab( HTMLBase ):
+                        
+    def __init__( self, dict, titles ):
+        HTMLBase.__init__( self )
+        self.dict = dict
+        self.titles = titles
+                        
+    def write_BODY( self, request ): 
+        
+        request.write( "<table width='100%' cellspacing='0' cellpadding='0' 
border='0'>" )
+        
+        def writeAttr( niceName, attr, formatter=None ):
+            if type( attr ) is types.TupleType:
+                ( attr, formatter ) = attr
+            
+            if attr in self.dict:
+                if formatter:
+                    temp = formatter( self.dict[ attr ] )
+                else:
+                    temp = str( self.dict[ attr ] )
+                request.write( "<tr><td width='50%%'><p>%s:</p></td><td 
width='50%%'><p>%s</p></td></tr>" % ( niceName, temp ) )
+        
+        for niceName, attr in self.titles.items():
+            writeAttr( niceName, attr )
+                            
+        request.write( "</table>" )
+
+class NullTab( HTMLBase ):
+    
+    def __init__( self ):
+        HTMLBase.__init__( self )
+        self.title = "Null Tab"
+
+    def __init__( self, title ):
+        HTMLBase.__init__( self )
+        self.title = title
+        
+    def write_BODY( self, request ):
+        request.write( "<p>%s</p>" % self.title )
+
+class ActionTab( HTMLBase ):
+
+    def __init__( self, actions ):
+        self.actions = actions
+        HTMLBase.__init__( self )
+        
+    def write_BODY( self, request ):
+        request.write( "<p align='center'><table cellspacing='3' 
cellpadding='2' border='0'><tr>" )
+    
+        for ( command, text ) in self.actions.items():
+            request.write( "<td style='border: 1px solid black; 
background-color: grey' onmouseover='buttonMouseOver( this )' 
onmouseout='buttonMouseOut( this )'>" )
+            request.write( "<p><a href='javascript: doOp( \"%s\" 
);'>%s</a></p></td>" % (command, text) )
+ 
+        request.write("</table></p>")        
+        
+class CompositeTab( HTMLBase ):
+
+    def __init__( self, tabs ):
+       HTMLBase.__init__( self )
+        self.tabs = tabs
+        
+    def write_BODY( self, request ):
+       for tab in self.tabs:
+            request.write( "<br/>" )
+            tab().write_BODY( request )
+            
+    def perform( self, request ):
+       for tab in self.tabs:
+            tab().perform( request )
+    
+    
+       
+        
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/HTMLBase.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/HTMLBase.py   Tue Jul 26 18:41:39 2005
@@ -0,0 +1,62 @@
+from xen.sv.util import *
+
+class HTMLBase:
+
+    isLeaf = True
+ 
+    def __init__( self ):
+        pass
+
+    def render_POST( self, request ):
+        self.perform( request )
+        return self.render_GET( request )
+        
+    def render_GET( self, request ):
+        self.write_TOP( request )
+        self.write_BODY( request )
+        self.write_BOTTOM( request )
+        return ''
+                
+    def write_BODY( self, request ):
+        request.write( "BODY" )
+        
+    def write_TOP( self, request ):
+        request.write( '<html><head><title>Xen</title><link rel="stylesheet" 
type="text/css" href="inc/style.css" />' )
+        request.write( '<script src="inc/script.js"></script>' )
+        request.write( '</head><body>' )
+        request.write('<form method="post" action="%s">' % request.uri)
+
+    def write_BOTTOM( self, request ):
+        request.write('<input type="hidden" name="op" value="">')
+        request.write('<input type="hidden" name="args" value="">')
+        request.write('</form>')
+        request.write( "</body></html>" )
+
+    def get_op_method(self, op):
+        """Get the method for an operation.
+        For operation 'foo' looks for 'op_foo'.
+
+        op     operation name
+        returns method or None
+        """
+        op_method_name = 'op_' + op
+        return getattr(self, op_method_name, None)
+        
+    def perform(self, req):
+        """General operation handler for posted operations.
+        For operation 'foo' looks for a method op_foo and calls
+        it with op_foo(req). Replies with code 500 if op_foo
+        is not found.
+
+        The method must return a list when req.use_sxp is true
+        and an HTML string otherwise (or list).
+        Methods may also return a Deferred (for incomplete processing).
+
+        req    request
+        """
+        op = req.args.get('op')
+        if not op is None and len(op) == 1:
+            op = op[0]
+            op_method = self.get_op_method(op)
+            if op_method:
+                op_method( req )   
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/Main.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/Main.py       Tue Jul 26 18:41:39 2005
@@ -0,0 +1,113 @@
+from xen.sv.HTMLBase import HTMLBase
+from xen.sv.DomList  import DomList
+from xen.sv.NodeInfo import NodeInfo
+from xen.sv.DomInfo  import DomInfo
+from xen.sv.CreateDomain import CreateDomain
+from xen.sv.MigrateDomain import MigrateDomain
+from xen.sv.SaveDomain import SaveDomain
+from xen.sv.RestoreDomain import RestoreDomain
+
+from xen.xend.XendClient import server
+
+from xen.sv.util import getVar
+
+class Main( HTMLBase ):
+    
+    isLeaf = True
+
+    def __init__( self, urlWriter = None ):
+        self.modules = { "node": NodeInfo, 
+                         "list": DomList, 
+                         "info": DomInfo,
+                         "create": CreateDomain,
+                         "migrate" : MigrateDomain,
+                         "save" : SaveDomain,
+                         "restore" : RestoreDomain }
+
+        # ordered list of module menus to display
+        self.module_menus = [ "node", "create", "migrate", "save",
+                              "restore", "list" ]
+        HTMLBase.__init__(self)
+        
+    def render_POST( self, request ):
+    
+       #decide what module post'd the action
+                
+       args = getVar( 'args', request )
+
+        mod = getVar( 'mod', request )
+                
+        if not mod is None and args is None:
+            module = self.modules[ mod ]
+            #check module exists
+            if module:
+               module( self.mainUrlWriter ).perform( request )
+        else:
+            self.perform( request )     
+    
+        return self.render_GET( request )
+
+    def mainUrlWriter( self, module ):
+       def fun( f ):
+            return "Main.rpy?mod=%s%s" % ( module, f )
+        return fun    
+        
+    def write_BODY( self, request ):
+    
+        request.write( "\n<table style='border:0px solid black; background: 
url(images/orb_01.jpg) no-repeat' cellspacing='0' cellpadding='0' border='0' 
width='780px' height='536px'>\n" )
+        request.write( "<tr>\n" )
+        request.write( " <td width='15px'>&nbsp;</td>" )
+        request.write( " <td width='175px' align='center' valign'center'>" )
+        request.write( "  <table cellspacing='0' cellpadding='0' border='0' 
width='100%' height='100%'>" )
+        request.write( "   <tr><td height='140px' align='center' 
valign='bottom'><a href='http://www.cl.cam.ac.uk/Research/SRG/netos/xen/'>" )
+        request.write( "   <img src='images/xen.png' width='150' height='75' 
border='0'/></a><br/></td></tr>" )
+        request.write( "   <tr><td height='60px' align='center'><p 
class='small'>SV Web Interface<br/>(C) <a href='mailto:tw275@xxxxxxxxx'>Tom 
Wilkie</a> 2004</p></td></tr>")
+        request.write( "   <tr><td align='center' valign='top'>" )
+
+        for modName in self.module_menus:
+            self.modules[modName]( self.mainUrlWriter( modName ) ).write_MENU( 
request )
+        
+        request.write( "   </td></tr>" )
+        request.write( "  </table>" )
+        request.write( " &nbsp;" )
+        request.write( " </td>\n" )
+        request.write( " <td width='15px'>&nbsp;</td>" )
+        request.write( " <td width='558px' align='left' valign='top'>" )
+        request.write( "  <table cellspacing='0' cellpadding='0' border='0' 
width='100%' height='100%'>" )
+        request.write( "   <tr><td height='20px'></td></tr>" )
+        request.write( "   <tr><td align='center' valign='top'>" )
+        
+        modName = getVar('mod', request)
+        
+        if modName is None:
+            request.write( '<p>Please select a module</p>' )
+        else:
+            module = self.modules[ modName ]
+            if module:
+               module( self.mainUrlWriter( modName ) ).write_BODY( request )  
+            else:
+               request.write( '<p>Invalid module. Please select another</p>' )
+    
+        request.write( "   </td></tr>" )
+        request.write( "  </table>" )
+        request.write( " </td>\n" )
+        request.write( " <td width='17px'>&nbsp;</td>" )
+        request.write( "</tr>\n" )
+        
+        request.write( "</table>\n" )
+        
+                
+    def op_destroy( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != "0":
+            server.xend_domain_destroy( int( dom ), "halt" ) 
+                 
+    def op_pause( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != "0":
+            server.xend_domain_pause( int( dom ) )      
+    
+    def op_unpause( self, request ):
+       dom = getVar( 'dom', request )
+        if not dom is None and dom != "0":
+            server.xend_domain_unpause( int( dom ) )      
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/MigrateDomain.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/MigrateDomain.py      Tue Jul 26 18:41:39 2005
@@ -0,0 +1,74 @@
+from xen.sv.Wizard import *
+from xen.sv.util import *
+from xen.sv.GenTabbed import PreTab
+
+from xen.xm.create import make_config, OptVals
+
+from xen.xend.XendClient import server
+
+class MigrateDomain( Wizard ):
+    def __init__( self, urlWriter ):
+
+        sheets = [ ChooseMigrateDomain,
+                   DoMigrate ]
+
+        Wizard.__init__( self, urlWriter, "Migrate Domain", sheets )
+
+
+class ChooseMigrateDomain( Sheet ):
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Configure Migration", 0)
+       domains = []
+       domnames = []
+
+        try:
+            domains = server.xend_domains()
+            domains.sort()
+        except:
+            pass
+
+        for i in domains:
+            if i != 'Domain-0': domnames.append((i,i))
+        
+        self.addControl( ListControl('domid',
+                                     domnames,
+                                     'Domain ID:') )
+        self.addControl( TickControl('live',
+                                     'True',
+                                     'Live migrate:') )
+        self.addControl( InputControl('rate',
+                                      '0',
+                                      'Rate limit:') )
+        self.addControl( InputControl( 'dest', 'myhost.mydomain',
+                                       'Name or IP address:',
+                                       ".*") )
+
+class DoMigrate( Sheet ):
+    def __init__(self, urlWriter ):
+        Sheet.__init__(self, urlWriter, "Migration Done", 1)
+
+    def write_BODY( self, request, err ):
+
+        if not self.passback: self.parseForm( request )
+
+#        print string2sxp(self.passback)
+        
+        config = ssxp2hash ( string2sxp( self.passback ) )
+      
+        try:
+            print config
+            print config['domid'], config['dest']
+            dom_sxp = server.xend_domain_migrate( config['domid'],
+                                                  config['dest'],
+                                                  config.get('live') == 'True',
+                                                  config['rate'] )
+            success = "Your domain was successfully Migrated.\n"
+        except Exception, e:
+            success = "There was an error migrating your domain\n"
+            dom_sxp = str(e)
+        
+        pt = PreTab( success + dom_sxp ) # sxp2prettystring( dom_sxp ) )
+        pt.write_BODY( request )
+
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/NodeInfo.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/NodeInfo.py   Tue Jul 26 18:41:39 2005
@@ -0,0 +1,63 @@
+from xen.xend.XendClient import server
+
+from xen.sv.util import *
+from xen.sv.GenTabbed import *
+
+class NodeInfo( GenTabbed ):
+
+    def __init__( self, urlWriter ):  
+        GenTabbed.__init__( self, "Node Details", urlWriter, [ 'General', 
'Dmesg', ], [ NodeGeneralTab, NodeDmesgTab ] )
+    
+    def write_MENU( self, request ):
+        request.write( "<p class='small'><a href='%s'>Node details</a></p>" % 
self.urlWriter( '' ) )
+
+class NodeGeneralTab( CompositeTab ):
+    def __init__( self ):
+       CompositeTab.__init__( self, [ NodeInfoTab, NodeActionTab ] )        
+        
+class NodeInfoTab( GeneralTab ):
+                        
+    def __init__( self ):
+         
+       nodeInfo = {}
+        try:
+            nodeInfo = sxp2hash( server.xend_node() )
+       except:
+            nodeInfo[ 'system' ] = 'Error getting node info'
+             
+        dictTitles = {}
+        dictTitles[ 'System' ] = 'system'
+        dictTitles[ 'Hostname' ] = 'host' 
+        dictTitles[ 'Release' ] = 'release' 
+        dictTitles[ 'Version' ] ='version' 
+        dictTitles[ 'Machine' ] = 'machine' 
+        dictTitles[ 'Cores' ] = 'cores' 
+        dictTitles[ 'Hyperthreading' ] = ( 'hyperthreads_per_core', 
hyperthreadFormatter )
+        dictTitles[ 'CPU Speed' ] = ( 'cpu_mhz', cpuFormatter )
+        dictTitles[ 'Memory' ] = ( 'memory', memoryFormatter )
+        dictTitles[ 'Free Memory' ] = ( 'free_memory', memoryFormatter )
+        
+        GeneralTab.__init__( self, dict=nodeInfo, titles=dictTitles )
+
+class NodeDmesgTab( PreTab ):
+
+    def __init__( self ):
+       try:
+            dmesg = server.xend_node_get_dmesg()
+        except:
+            dmesg = "Error getting node information: XenD not running?"
+        PreTab.__init__( self, dmesg )
+  
+class NodeActionTab( ActionTab ):
+
+    def __init__( self ):
+        ActionTab.__init__( self, { "shutdown" : "shutdown",
+               "reboot" : "reboot" } )    
+        
+    def op_shutdown( self, request ):
+        if debug: print ">NodeShutDown"
+       server.xend_node_shutdown()
+    
+    def op_reboot( self, request ):
+        if debug: print ">NodeReboot"
+        server.xend_node_reboot()
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/RestoreDomain.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/RestoreDomain.py      Tue Jul 26 18:41:39 2005
@@ -0,0 +1,46 @@
+from xen.sv.Wizard import *
+from xen.sv.util import *
+from xen.sv.GenTabbed import PreTab
+
+from xen.xm.create import make_config, OptVals
+
+from xen.xend.XendClient import server
+
+class RestoreDomain( Wizard ):
+    def __init__( self, urlWriter ):
+
+        sheets = [ ChooseRestoreDomain,
+                   DoRestore ]
+
+        Wizard.__init__( self, urlWriter, "Restore Domain", sheets )
+
+
+class ChooseRestoreDomain( Sheet ):
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Configure Restore", 0)
+        
+        self.addControl( InputControl( 'file', '',
+                                       'Suspend file name:',
+                                       ".*") )
+
+class DoRestore( Sheet ):
+    def __init__(self, urlWriter ):
+        Sheet.__init__(self, urlWriter, "Restore Done", 1)
+
+    def write_BODY( self, request, err ):
+
+        if not self.passback: self.parseForm( request )
+        config = ssxp2hash ( string2sxp( self.passback ) )
+      
+        try:
+            dom_sxp = server.xend_domain_restore( config['file'] )
+            success = "Your domain was successfully restored.\n"
+        except Exception, e:
+            success = "There was an error restoring your domain\n"
+            dom_sxp = str(e)
+        
+        pt = PreTab( success + sxp2prettystring( dom_sxp ) )
+        pt.write_BODY( request )
+
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/SaveDomain.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/SaveDomain.py Tue Jul 26 18:41:39 2005
@@ -0,0 +1,62 @@
+from xen.sv.Wizard import *
+from xen.sv.util import *
+from xen.sv.GenTabbed import PreTab
+
+from xen.xm.create import make_config, OptVals
+
+from xen.xend.XendClient import server
+
+class SaveDomain( Wizard ):
+    def __init__( self, urlWriter ):
+
+        sheets = [ ChooseSaveDomain,
+                   DoSave ]
+
+        Wizard.__init__( self, urlWriter, "Save Domain", sheets )
+
+
+class ChooseSaveDomain( Sheet ):
+    def __init__( self, urlWriter ):
+        Sheet.__init__( self, urlWriter, "Configure Save", 0)
+        
+       domains = []
+       domnames = []
+
+       try:
+            domains = server.xend_domains()
+            domains.sort()
+        except:
+            pass
+
+        for i in domains:
+            if i != 'Domain-0': domnames.append((i,i))
+        
+        self.addControl( ListControl('domid',
+                                     domnames,
+                                     'Domain ID:') )
+        self.addControl( InputControl( 'file', '',
+                                       'Suspend file name:',
+                                       ".*") )
+
+class DoSave( Sheet ):
+    def __init__(self, urlWriter ):
+        Sheet.__init__(self, urlWriter, "Save Done", 1)
+
+    def write_BODY( self, request, err ):
+
+        if not self.passback: self.parseForm( request )
+        config = ssxp2hash ( string2sxp( self.passback ) )
+      
+        try:
+            dom_sxp = server.xend_domain_save( config['domid'],
+                                                  config['file'] )
+            success = "Your domain was successfully saved.\n"
+        except Exception, e:
+            success = "There was an error saving your domain\n"
+            dom_sxp = str(e)
+        
+        pt = PreTab( success + dom_sxp ) # sxp2prettystring( dom_sxp ) )
+        pt.write_BODY( request )
+
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/TabView.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/TabView.py    Tue Jul 26 18:41:39 2005
@@ -0,0 +1,26 @@
+from xen.sv.HTMLBase import HTMLBase
+
+class TabView( HTMLBase ):
+
+    # tab - int, id into tabs of selected tab
+    # tabs - list of strings, tab names
+    # urlWriter - 
+    def __init__( self, tab, tabs, urlWriter ):
+        HTMLBase.__init__(self)
+        self.tab = tab
+        self.tabs = tabs
+        self.urlWriter = urlWriter
+
+    def write_BODY( self, request ):
+        request.write( "<table style='' border='0' cellspacing='3' 
cellpadding='2' align='center'>" )
+        request.write( "<tr height='22'>" )                  
+    
+        for i in range( len( self.tabs ) ):
+            if self.tab == i:
+                backgroundColor = "white"
+            else:
+                backgroundColor = "grey"
+        
+            request.write( "<td style='border:1px solid black; 
background-color: %s'><p align='center'><a href='%s'>%s</a></p></td>" % ( 
backgroundColor, self.urlWriter( "&tab=%s" % i ), self.tabs[ i ] ) )
+  
+        request.write( "</tr></table>" )
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/Wizard.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/Wizard.py     Tue Jul 26 18:41:39 2005
@@ -0,0 +1,269 @@
+from xen.sv.util import *
+from xen.sv.HTMLBase import HTMLBase
+from xen.xend import sxp
+
+import re
+
+DEBUG = 0
+
+class Wizard( HTMLBase ):
+
+    def __init__( self, urlWriter, title, sheets ):
+        HTMLBase.__init__( self )
+        self.title = title
+        self.sheets = sheets
+        self.urlWriter = urlWriter
+        
+    def write_MENU( self, request ):
+       request.write( "<p class='small'><a href='%s'>%s</a></p>" % 
(self.urlWriter( '' ), self.title) ) 
+    
+    def write_BODY( self, request ):
+        
+       request.write( "<table width='100%' border='0' cellspacing='0' 
cellpadding='0'><tr><td>" )
+        request.write( "<p align='center'><u>%s</u></p></td></tr><tr><td>" % 
self.title )
+        
+        currSheet = getVar( 'sheet', request )
+    
+        if not currSheet is None:
+            currSheet = int( currSheet )
+        else:
+            currSheet = 0
+            
+        sheet = self.sheets[ currSheet ]( self.urlWriter )
+        
+        err = not sheet.validate( request )
+        
+        if not err:    
+            op = getVar( 'op', request )
+        
+            if op == 'next':
+               currSheet += 1
+            elif op == 'prev':
+               currSheet -= 1
+             
+            sheet = self.sheets[ currSheet ]( self.urlWriter )
+        
+        if getVar( 'visited-sheet%s' % currSheet, request ):
+            sheet.write_BODY( request, err )
+        else:
+            sheet.write_BODY( request, False )
+
+        
+        request.write( "</td></tr><tr><td><table width='100%' border='0' 
cellspacing='0' cellpadding='0'><tr>" )
+        request.write( "<td width='80%'></td><td width='20%' align='center'><p 
align='center'>" )
+       if currSheet > 0:
+                   request.write( "<img src='images/previous.png' 
onclick='doOp( \"prev\" )' onmouseover='update( \"wizText\", \"Previous\" )' 
onmouseout='update( \"wizText\", \"&nbsp;\" )'>&nbsp;" )
+        if currSheet < ( len( self.sheets ) - 2 ):        
+            request.write( "<img src='images/next.png' onclick='doOp( \"next\" 
)' onmouseover='update( \"wizText\", \"Next\" )' onmouseout='update( 
\"wizText\", \"&nbsp;\" )'>" )
+        elif currSheet == ( len( self.sheets ) - 2 ):
+            request.write( "<img src='images/finish.png' onclick='doOp( 
\"next\" )' onmouseover='update( \"wizText\", \"Finish\" )' onmouseout='update( 
\"wizText\", \"&nbsp;\" )'>" )
+        request.write( "</p><p align='center'><span 
id='wizText'></span></p></td></tr></table>" )
+        request.write( "</td></tr></table>" )
+        
+    def op_next( self, request ):
+       pass
+        
+    def op_prev( self, request ):
+       pass
+        
+    def op_finish( self, request ):
+       pass  
+        
+class Sheet( HTMLBase ):
+
+    def __init__( self, urlWriter, title, location ):
+        HTMLBase.__init__( self )
+        self.urlWriter = urlWriter
+        self.feilds = []
+        self.title = title
+        self.location = location
+        self.passback = None
+        
+    def parseForm( self, request ):
+       do_not_parse = [ 'mod', 'op', 'sheet', 'passback' ] 
+    
+       passed_back = request.args
+        
+        temp_passback = passed_back.get( "passback" )
+        
+        if temp_passback is not None and len( temp_passback ) > 0:
+            temp_passback = temp_passback[ len( temp_passback )-1 ]
+        else:
+            temp_passback = "( )"        
+        
+        last_passback = ssxp2hash( string2sxp( temp_passback ) ) #use special 
function - will work with no head on sxp
+        
+        if DEBUG: print last_passback
+        
+        for (key, value) in passed_back.items():
+            if key not in do_not_parse:
+                last_passback[ key ] = value[ len( value ) - 1 ]
+                
+        self.passback = sxp2string( hash2sxp( last_passback ) ) #store the sxp
+        
+        if DEBUG: print self.passback
+        
+    def write_BODY( self, request, err ):
+    
+       if not self.passback: self.parseForm( request )
+        
+       request.write( "<p>%s</p>" % self.title )
+    
+       previous_values = ssxp2hash( string2sxp( self.passback ) ) #get the 
hash for quick reference
+        
+        request.write( "<table width='100%' cellpadding='0' cellspacing='1' 
border='0'>" )
+        
+       for (feild, control) in self.feilds:
+            control.write_Control( request, previous_values.get( feild ) )
+            if err and not control.validate( previous_values.get( feild ) ):
+               control.write_Help( request )
+            
+        request.write( "</table>" )
+            
+        request.write( "<input type='hidden' name='passback' 
value=\"%s\"></p>" % self.passback )
+        request.write( "<input type='hidden' name='sheet' value='%s'></p>" % 
self.location )
+        request.write( "<input type='hidden' name='visited-sheet%s' 
value='True'></p>" % self.location )
+                
+    def addControl( self, control ):
+       self.feilds.append( [ control.getName(), control ] )
+        
+    def validate( self, request ):
+    
+        if not self.passback: self.parseForm( request )
+            
+       check = True
+        
+        previous_values = ssxp2hash( string2sxp( self.passback ) ) #get the 
hash for quick reference
+       if DEBUG: print previous_values
+      
+       for (feild, control) in self.feilds:
+            if not control.validate( previous_values.get( feild ) ):
+                check = False
+                if DEBUG: print "> %s = %s" % (feild, previous_values.get( 
feild ))
+
+        return check
+        
+class SheetControl( HTMLBase ):
+
+    def __init__( self, reg_exp = ".*" ):
+        HTMLBase.__init__( self )
+        self.name = ""
+        self.reg_exp = reg_exp 
+        
+    def write_Control( self, request, persistedValue ):
+        request.write( "<tr colspan='2'><td>%s</td></tr>" % persistedValue )
+        
+    def write_Help( self, request ):
+        request.write( "<tr><td align='right' colspan='2'><p 
class='small'>Text must match pattern:" )
+        request.write( " %s</p></td></tr>" % self.reg_exp )
+        
+    def validate( self, persistedValue ):
+       if persistedValue is None:
+            persistedValue = ""
+            
+        return not re.compile( self.reg_exp ).match( persistedValue ) is None
+
+    def getName( self ):
+       return self.name
+        
+    def setName( self, name ):
+       self.name = name
+        
+class InputControl( SheetControl ):
+
+    def __init__( self, name, defaultValue, humanText,  reg_exp = ".*", 
help_text = "You must enter the appropriate details in this feild." ):
+        SheetControl.__init__( self, reg_exp )
+        self.setName( name )
+        
+        self.defaultValue = defaultValue
+        self.humanText = humanText
+        self.help_text = help_text
+        
+    def write_Control( self, request, persistedValue ):
+       if persistedValue is None:
+            persistedValue = self.defaultValue
+        
+        request.write( "<tr><td width='50%%'><p>%s</p></td><td 
width='50%%'><input size='40'type='text' name='%s' value=\"%s\"></td></tr>" % 
(self.humanText, self.getName(), persistedValue) )
+
+    def write_Help( self, request ):
+        request.write( "<tr><td align='right' colspan='2'><p class='small'>" )
+        request.write( " %s</p></td></tr>" % self.help_text )         
+        
+class TextControl( SheetControl ):
+
+    def __init__( self, text ):
+       SheetControl.__init__( self )
+        self.text = text
+        
+    def write_Control( self, request, persistedValue ):
+       request.write( "<tr><td colspan='2'><p>%s</p></td></tr>" % self.text )
+
+class SmallTextControl( SheetControl ):
+
+    def __init__( self, text ):
+       SheetControl.__init__( self )
+        self.text = text
+        
+    def write_Control( self, request, persistedValue ):
+       request.write( "<tr><td colspan='2'><p class='small'>%s</p></tr></td>" 
% self.text )
+        
+class ListControl( SheetControl ):
+
+    def __init__( self, name, options, humanText ):
+       SheetControl.__init__( self )
+        self.setName( name )
+        self.options = options
+        self.humanText = humanText
+        
+    def write_Control( self, request, persistedValue ):
+        request.write( "<tr><td width='50%%'><p>%s</p></td><td width='50%%'>" 
% self.humanText )
+       request.write( "<select name='%s'>" % self.getName() )
+        for (value, text) in self.options:
+            if value == persistedValue:
+               request.write( "<option value='%s' selected>%s\n" % (value, 
text) )
+            else:
+                request.write( "<option value='%s'>%s\n" % (value, text) )
+        request.write( "</select></td></tr>" )
+
+    def validate( self, persistedValue ):
+        for (value, text) in self.options:
+            if value == persistedValue:
+                return True
+                
+        return False
+        
+class FileControl( InputControl ):
+
+    def __init__( self, name, defaultValue, humanText,  reg_exp = ".*", 
help_text = "You must enter the appropriate details in this feild." ):
+       InputControl.__init__( self, name, defaultValue, humanText )
+        
+    def validate( self, persistedValue ):
+        if persistedValue is None: return False
+        try:
+            open( persistedValue )
+            return True
+        except IOError, TypeError:
+            return False
+    
+    def write_Help( self, request ):
+        request.write( "<tr><td colspan='2' align='right'><p 
class='small'>File does not exist: you must enter a valid, absolute file 
path.</p></td></tr>" )
+
+class TickControl( SheetControl ):
+
+    def __init__( self, name, defaultValue, humanText ):
+        SheetControl.__init__( self )
+        self.setName( name )
+        self.defaultValue = defaultValue
+        self.humanText = humanText
+        
+    def write_Control( self, request, persistedValue ):
+        request.write( "<tr><td width='50%%'><p>%s</p></td><td width='50%%'>" 
% self.humanText )
+        
+        if persistedValue == 'True':
+           request.write( "<input type='checkbox' name='%s' value='True' 
checked>" % self.getName() )
+        else:
+           request.write( "<input type='checkbox' name='%s' value='True'>" % 
self.getName() )
+            
+        request.write( "</select></td></tr>" )
+
+      
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/__init__.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/__init__.py   Tue Jul 26 18:41:39 2005
@@ -0,0 +1,1 @@
+ 
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/params.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/params.py     Tue Jul 26 18:41:39 2005
@@ -0,0 +1,3 @@
+SV_PORT = 8080
+SV_ROOT = "/var/lib/xen/sv/"
+PID_FILE = "/var/run/xen-sv.pid"
diff -r 69beaae8a1fa -r 2333f6616d18 tools/python/xen/sv/util.py
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/python/xen/sv/util.py       Tue Jul 26 18:41:39 2005
@@ -0,0 +1,126 @@
+from xen.xend.XendClient import server
+from xen.xend import sxp
+from xen.xend import PrettyPrint
+
+import types
+
+def getDomInfoHash( domain ):
+    domInfoHash = {}
+    try:
+        domInfoHash = sxp2hash( server.xend_domain( domain ) )
+        domInfoHash['dom'] = domain
+    except:
+       domInfoHash['name'] = "Error getting domain details"
+    return domInfoHash
+
+def sxp2hash( s ):
+    sxphash = {}
+        
+    for child in sxp.children( s ):
+       if isinstance( child, types.ListType ) and len( child ) > 1:
+            if isinstance( child[1], types.ListType ) and len( child ) > 1:
+                sxphash[ child[0] ] = sxp2hash( child[1] )
+            else:
+                sxphash[ child[0] ] = child[1]
+        
+    return sxphash  
+    
+def ssxp2hash( s ):
+    sxphash = {}
+    
+    for i in s:
+       if isinstance( i, types.ListType ) and len( i ) > 1:
+          sxphash[ i[0] ] = i[1]
+    
+    return sxphash 
+    
+def hash2sxp( h ):
+    hashsxp = []
+    
+    for (key, item) in h.items():
+       hashsxp.append( [key, item] )
+        
+    return hashsxp    
+    
+def string2sxp( string ):
+    pin = sxp.Parser()
+    pin.input( string )
+    return pin.get_val()    
+
+def sxp2string( sexp ):
+    return sxp.to_string( sexp )    
+    
+def sxp2prettystring( sxp ):
+    class tmp:
+        def __init__( self ):
+                self.str = ""
+        def write( self, str ):
+                self.str = self.str + str
+    temp = tmp()
+    PrettyPrint.prettyprint( sxp, out=temp )
+    return temp.str
+
+def getVar( var, request, default=None ):
+   
+    arg = request.args.get( var )
+
+    if arg is None:
+        return default
+    else:
+        return arg[ len( arg )-1 ]
+
+def bigTimeFormatter( time ):
+    time = float( time )
+    weeks = time // 604800
+    remainder = time % 604800
+    days = remainder // 86400
+    
+    remainder = remainder % 86400
+
+    hms = smallTimeFormatter( remainder )
+    
+    return "%d weeks, %d days, %s" % ( weeks, days, hms )
+
+def smallTimeFormatter( time ):
+    time = float( time )
+    hours = time // 3600
+    remainder = time % 3600
+    mins = remainder // 60
+    secs = time % 60
+    return "%02d:%02d:%04.1f (hh:mm:ss.s)" % ( hours, mins, secs ) 
+
+def stateFormatter( state ):
+    states = [ 'Running', 'Blocked', 'Paused', 'Shutdown', 'Crashed' ]
+    
+    stateStr = ""
+    
+    for i in range( len( state ) ):
+        if state[i] != "-":
+            stateStr += "%s, " % states[ i ] 
+           
+    return stateStr + " (%s)" % state
+
+def memoryFormatter( mem ):
+    mem = int( mem )
+    if mem >= 1024:
+        mem = float( mem ) / 1024
+        return "%3.2fGb" % mem
+    else:    
+        return "%7dMb" % mem
+
+def cpuFormatter( mhz ):
+    mhz = int( mhz )
+    if mhz > 1000:
+        ghz = float( mhz ) / 1000.0
+        return "%4.2fGHz" % ghz
+    else:
+        return "%4dMHz" % mhz
+        
+def hyperthreadFormatter( threads ):
+    try:
+        if int( threads ) > 1:
+            return "Yes"
+        else:
+            return "No"
+    except:
+        return "No"
diff -r 69beaae8a1fa -r 2333f6616d18 tools/sv/Makefile
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/sv/Makefile Tue Jul 26 18:41:39 2005
@@ -0,0 +1,2 @@
+
+all:
diff -r 69beaae8a1fa -r 2333f6616d18 tools/sv/images/destroy.png
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/sv/images/destroy.png       Tue Jul 26 18:41:39 2005
@@ -0,0 +1,23 @@
+?PNG
+
+
\ No newline at end of file
+IHDR66?EjÝgAMAÖØÔOX2tEXtSoftwareAdobe 
ImageReadyqÉe<úIDATxÚbüÿÿ?µÀÛ·o??ë½zõJóþýû&_¾|?þ÷ï/s@?ýdbbúÂÆÆöJDDä?²²ò)?K@ñs¨å?b¤Ôc?~äR®ïÞ½s¾pá?ïóçÏ¥É1èÑ/ªªªuuu7033ïæççÿH?»?l?=¤?? ³gÏÆÜºuË????¯;???Ö=ø?3?d????=vìXÎãÇ?5hÿ¸ºº
+
+.&ÓO¤è 
?<ô?Ð3@O3Ðcð¡??W???ÄbõÑ&½?M?65~þüY?a??»»{.°°?B?Z?"è1 ??%[ÙÆ?+héh`áÁÀÎÎÎðóçO?_¿~áT'//¿ØÆÆ&?÷Þã3
 ?ðz?ô$>|øP³sçÎló?Æg6H
\ No newline at end of file
+°Øg@`6°èg???b¸sçÃׯ_Áb ü÷ï_½ÜÜÜg||||?ùî.ó?      
?§ÉñÌC?R°Hgæ^^^plqqq1KA`Ar88ö@Ç?7Ù 7â2 ?pzìÇ?eäx?ÀÊÊÊ ¦¦Æ ))É  
 ö?¸¸8X?$ÿþ?Sï·oßLvíÚµ?<@aõ0¦rh?§þüùÃðòåK`aÄ ®®Î ©©      ö???0ÿ?c«°d?
\ No newline at end of file
+¼ÿÞóäÉ?¥Øä#?½yóÆËë¾ÿÎKëÂ?µµµDEEÁy    
Th?8ß?òÙ³gÏÀ?>àáá᪤¤?Rz媧hé)P
?ò°tcÐ××ÇÈ B{@û®_¿J5`Ïã?1رcÇ.hÃ?       
-CÇ?~?f?/(i?ò(Ù0K5?ׯ_3\¹r?ááÃ? |
\ No newline at end of file
+Î[ O=xð?áÉ?'c^À¦J? &¤|¥pøðáZy
+TÂ?ò°?ö(Ö@?wîãG?À±Ì3àØyTp?0±
\ No newline at end of file
+`?×cMÆ ¸Ç?!D«¶ÈS|||`)**?óÓÍ?7Î??ÎGÀ¤?)P,à<F?â?06@1A
þS§N%Ñ*¶899ÁÅ:°9??Û·o??°«Oj ØÊ{?Ü0Õ??6¨Å@Lдï
+?-mZx????ALL?AVVì`P!ìæ?ê!jvraØ'?ÑÄ-
\ No newline at end of file
+?iU?*]999pAqïÞ=??ym? &`28}út 
­ò(¶@-P ?V??6çX?u?@±-1?FâÔ?PCT?ÃÚx zä1Pl??óçÏ?[|Sä`?@,@éQb
+(ïhii?i?Gp?§A?é´ÀBÈ ?@ѦI?fP3ÈÚÚÜÕ 
?ZíÎÎÎàÖÆÑ£G?>}J3?ëBO?bvttì?P¢¤hÔÑѵÏÀu©T1khh?[! 
+?VÉ ?X??")?b ê?###pKØõ E±ÿ ????r«ZOO?*??P?meeE??? ???¥";1?A]
PlQ?JEE?êI ??°?)`vvvDu!È õ?©cÿ?      V,ªªªàâ?VÔ:µú©è±¿¬K?~?\h
\ No newline at end of file
+@£V??ó ?@û?O¨ÕªXi
\ No newline at end of file
+@±ÊÇT?±ÄlÇmÁWÜRË2b¨MI¥?:;@1[×ñ5JAc}ô Ö       
µJE?bâåå½?OÝ<ê?R)Æ?°ázÈø?o?^?vSß`A@L????uÈ\ù
ßµ¨ÏFðØ?ù@LТ¶
+WEýéÓ'ºy4æA?Î-7? °Çv?Æ&°ÐH,½hè???ÚÚÚࢠ?Àv#>*))c??e ?ZPÉ
¦4ÛÛÛ?£ ???z¸ë??ñ+ô¼â?Æi
\ No newline at end of file
+îß¿OQþ
\ No newline at end of file
+99¹u0>@Á=fbbò(Ñ?-??FkiY??ïäÉ??ìÀ
+ûûû??ñeì^FFf1hl½ 
?$Ès´W¯^?^?Þ½{·JAA¥ï@Lh½ÚOêêê®À¼v=I??£©?0hÚèøñã?T¯?­§?^^^(@aLü9;;ïvS&?ä_ôä²sçNªÉ0³ß¾};Þ?KBØÀx???Þ?.@Xg4æÛ?Ýè??ÏÖ¯_¤??Þºuë(ª'?Æ?ììl¬Có?sZSS³???ýú'¨è߸q#Ã¥K?È?MJ¬^½?¢Øºc'°?Â9?@x?CìÛ·OâÆ?ÏA1?m0TÐ????e?é$?ò(¨ô{õêE±ýùóçµ@Oå???â\@°ó?àÝ»wßóÃ?`ëk

?&ÂAÒÒÒ`ÏÂÆ/@¥+hªäÐÜ¥=È­@wl?ÞIx???è%G3gÎ?t¤+?,­uð`ª5Ößó?1ê?¤Eb«V­rS?ùN?Z}'bb
        
?ôö?5++Ë?X}Dò²¾-[¶?VÌ?jêÜÜÜÚ¸ÏÔðÐׯ_oí`6&=??O?"{!æÚµk?-ÿÀ?í°`Ñõ´©?DA¥0ÐC?úìÝÇ'&&>
 Ç?¢xé,°.â®À:¯X'qÛlª Â¶È???UÐÀBá>°/uè?@~~~?èèh?ZÄHÍ   `å-l"C\Ø
\ No newline at end of file
+       ûòåË_ ù þ?0h$ÖÃÆÊK`~
\ No newline at end of file
+?·À?>0??¥é¹¨¨(ª-v0?ù?óÀ~ëIEND®B`?
\ No newline at end of file
diff -r 69beaae8a1fa -r 2333f6616d18 tools/sv/images/finish.png
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/sv/images/finish.png        Tue Jul 26 18:41:39 2005
@@ -0,0 +1,16 @@
+?PNG
+
+
\ No newline at end of file
+IHDR?ÔôUgAMAÖØÔOX2tEXtSoftwareAdobe 
ImageReadyqÉe<7IDATxÚb|óæ
\ No newline at end of file
+
0222üû÷L?0;;;ï_¿?>}êöîÝ;»·oßj}øðAúÿÿÿl@忸¸¸^???_fee=¦¤¤´¨þîß¿>þÌðýûwYYY??þÀÍ
 
Fl?±±±?,Q½wï^Ñ­[·B>~ü(ä3°°°0011ÁÕ-ZüIAAa½??J7Pü*ÈBtËÃ2?Æ/^d?={¶öåË?RÌÌÌ(?Ô`
 G?æååý¨®®^ôñ$ føýû7\
\ No newline at end of file
+@¡X& o:?;V
+s1Ì0K?ÙØ(A@UUu???Y>С?`bÄS
+º;wît9r¤æCl¾Ág?Bä 7n¤Ìjhh?ÄÁÁ? pø?~öìYúñãÇÁ!9d0?îÞ½?
©B?Ã?        ä 7?Ï?9Ó
+_J-B¶döÕ«W;?)Yd!@?-»}ûvéëׯEA®¡&9üçÏ?¬?.]j-@19ò7oÞ
YJ?"¿è0?{~úôI?V???è!`È?0éÛ??9(5, u Ô
+??~?2??M?ïìd£61¾YÄÏÏÏ ¬¬Ì --
\ No newline at end of file
+¶àáÃ?÷ïßOø,éýòå?@±¼ÿ^??J<rrrjjj|||`ÃA>ùæCÁù ?????       eT?e???
<<<`??BäSF.ð?Yö?? "ää²ä`äÃ?(|hÍ_?bÅ3bìüøñc0þúõ+(ÀñõüùsàI?b¾
¬B´        eh?ë_½zö°?òÀ,N 
6ùí-@±prr^²#?qÈÀÅt¼Z!Æ"PÖZ@LÀH_¬auðz??±ê«oÀ?Û@ 8»
\ No newline at end of file
+´pr?JMrвÕÀì² ?@e#(?ö?óOtßë[?½zf6È?bå1 ­×ÅÄÄòAèå%?0?Îæææ>
+Ê?ÄJ]ß¾}c?       tÁ|ôà?YkqëcPðãi0Ó×?Ì%.?#ÈBP«¨¨X,!¶£çX«?     
µA`ÕÌz hÞ?e |
+@L0?½ü     èe ???Að       
9µÁ,ÀeL¨ï;Ï:>?~ÃÌÉz?*ül?õó?PÁ «¾?Â\ÓËD?ã`l?84;üª[Ì·?@Çf??'t?r
Þ§??ú?TÌ?@a ­4PÈæªù
+?ÏÀ<úhÑV`º´|7¾ê
+ À(¹ECeV?IEND®B`?
\ No newline at end of file
diff -r 69beaae8a1fa -r 2333f6616d18 tools/sv/images/internet copy.jpg
--- /dev/null   Tue Jul 26 17:38:33 2005
+++ b/tools/sv/images/internet copy.jpg Tue Jul 26 18:41:39 2005
@@ -0,0 +1,373 @@
+ÿØÿàJFIFddÿìDuckyPÿîAdobedÀÿÛ?
                
+
+                       
\ No newline at end of file
+      
\ No newline at end of file
+ÿÀ
ÿÄÁ     
+!1AQa"q2±ÁBRr??¡Ñb²#3áCÂÒ?³5¢$%ðñ??Scsâ4tu&£DTdE!1AQaq?±"2ð?¡ÁÑáBRb²#ñr$?ÂScÿÚ
?þÒùkÎÚ1éÉ´ÞºÈ?«Dç?Nñ¼q?3lÄÛÔ~´?Þ?þ¢A?1Q)®RFc?±      
2?׿ÿ???½P`ZG|!%ËN¢¤H??éÛ?åK> ??2í?õ¬v8ǨJ¡°ÄF8·Ì^¦µô ??Pô^  
ÍÔ¾Ôfp^hþ©/j'¹.: ÷«?r]z¨^ñ¤8?å§P·rªó?pfs¦?X³ïC?}E¿X=è}5ú?ýbûÑ8Q?¬æ?ú?ýX÷¡Àú?
\ No newline at end of file
+Zï?Àæ?Õ.øp^j¶­p?8Ø>µFØp9¸?:?  
Ö/??ýMµ6'ª/½4S_zIþ¦?÷Ó'$ÿRO{é??©'½ôÄâ¼?ê)ïý0â??ýE=ÿ¦VÏêï}0âZ¨/½%?¯_zK?^¾ÿÓ
+-?®_é?~¹}ï¦YúáïB??\=ï¦Yúáï}0¢Ï×{é?-?®÷Ó
+,ýp÷¾?QgëG½?þ´{Рýh÷¡B?\=瑩÷Ó??\=ï¦Yúáï}0¢Ï×{é?~¸{ßL(³õÃÞúaE?®÷Ó
+,ýp÷¾?Qgë?½ôÂ??\=ï¦ZZ=è?#õ£Þ?ë?½ôÅ¢Ï×{é?~¸{ßL(³õÃÞúaE?®÷Ó
+,ýp÷¾?Qgë?½ôÄ ýp÷¾?P~¸{ßL(Oë~×Ó
+úÁï}0¢ÓúÁïB?Oë½ôÂ?þ°o?~°o?ëøQhý`ß
+Ö¯½
+-¬_zYúÅ÷¡E£õ?Þ?~°{ßL(³õ?ké?ýgÚúaAúÑï}0¡®÷Ó
+,ýp÷¾?´YúÑï}1(?Z=èP~¸{ßLZ,ýp÷¡E¬5£Þ?E¹ 
«l(·6Þ¢r¬JW5qÙ©_?z®?SÐõ§]Ðõ?ôZÍ)ñs+?qføáÇXy±ÏÝõ&~ãi|Éhhµl?^µae{O>[?Åí?½?ß­Ú&Þíµ?{Q¡?kÈÄöÅ?¦T÷¦7F¢i&-«klµ±qoxlgÈk*Æøã1n|²?¦)ÕZÓefù7Â&qI?Ê¥?²A?jméÇW?+?1囹KØl?F)¾7=VÄwS£»­tb§?ââ»ã?]_ÍßÖIÖk??DFq?Ê[TÚ??þ£'ê_j3=MGk?z¹CÞúc?áN±?¬½t`^qbeªõ¢?5»?$âð­a9Þ?ít?c³y?ÝÇÞx?#¦5.YÜlí¨??8úc¯Òrú«ÿPï?¦'Ò>ªç¨
    
'8¨ã¼ÄúKõVþ $9Æ<aô?ª¸×?­Î1â}5ú©ñ#Î0ãé¯Õfz??çñ?Ó>«¬¿Õ?8?ô?ªîz?uèúÍIÏg1K6ê?$ü´?³ÇHz:¿V²õRÞI
Ê?¬Â??ãw¡!SŸ³idCßiâÛg8Qie@ÖdÍW ÍØû
\ No newline at end of file
+¼Ä¢ËÈ?ÍÒè?jìvvÂ?ÛdBIÌõ­?®[;J¬?g£¸vÙÜaE?«âÜ\Í,¨{í<[lç
+-.?Ì?UÈ3f>Ão1(²ò(³tÍè??±ÙÛ
+-©E$?^dìv¸R©i¥KQÜ    ;lî0 T_âÍå?ó´ñm³?(K¢?³&j±nÇØmæ/[Afé
ôF5vÝÛlm¡$Íæw;\gjÚ?©z3?'aí?Æ?Úø·o,?{í<[lçÚ?³"Õr
Ý?°ÛÌõ¥n?½±v;;`56??fõÜì=pZ¶¥*^?àIØ{gq?kâÜY¼²!ï´ñm³?í¨{2/W ÍØû
\ No newline at end of file
+¼À/ZQfé?Ñc³¶SiI&o]ÎÃ×?«jR¥èî??¶w¶¾-Å?Ë"ûOÛ9ÀÚ?³"õr
Ý?°ÛÌõ¥n?½±v;;`56??fõÜì=pZ¶¥*^?àIØ{gq?kâÜY¼²!ï´ñm³?í¨{2/W ÍØû
\ No newline at end of file
+¼À/ZQfé?Ñc³¶SiI&o]ÎÃ×?«jR¥èî??¶w¶¾-Å?Ë"ûOÛ9ÀÚ?³"õr
Ý?°ÛÌõ¥n?½±v;;`56??fõÜì=pZ¶¥*^?àIØ{gq?kâÜY¼²!ï´ñm³?í¨{2/W ÍØû
\ No newline at end of file
+¼À/ZQfé?Ñc³¶SiI&o]ÎÃ×?«jR¥èî??¶w¶¾-Å?Ë"ûOÛ9ÀÚ?³"õr
Ý?°ÛÌõ¥n?½±v;;`56??fõÜì=pZ¶¥*^?àIØ{gq?kâÜY¼²!ï´ñm³?í¨{2/W ÍØû
\ No newline at end of file
+¼À/ZQfé?Ñc³¶SiI&o]ÎÃ×?«jR¥èî??¶w¶¾-Å?Ë"ûOÛ9ÀÚ?³"õr
Ý?°ÛÌõ¥n?½±v;;`56??fõÜì=pZ¶¥*^?àIØ{gq?kâÜY¼²!ï´ñm³?í¨{2/W ÍØû
\ No newline at end of file
+¼À/ZQfé?Ñc³¶SiI&o]ÎÃ×?«jR¥èî??¶w¶¾-Å?Ë"ûOÛ9ÀÚ?³"õrÝ?°ÛÌ^²?
\ No newline at end of file
+Ó72F5v;7×ë´ë§ý??JâlÚ#Q6?X½0!#°ÍË8?ó§Y±oSrö¢Î?íÔÊöØÐý×>??¸x2Î%ùÃÌý#Scªéµ=(·Hêv®x?&áS)8åôomÒ;¸îú_?q?©­ô?µ?ÇVA?.?oËhãÂ,|^¼s??äõe>ÏÓü#q*>½?us
   
L}QxJr?çQe?eÇ?&&??#©?Êj;a·^ªö?ófAó??;a4ã?FNÏMÖÈ!?ê7öõåoní®u-ºÖ]UÔÓÝ?ûí?GÒ?áæú³?¼V¿«ét×??ÚÛ!ý?¡ÖMôÇ?³¢qÝêëò#-?Úë?H
Áùc餵?±pæ?ªwé¾=?¼Ó?8×µÓêÆrè¶±ï§O{©º1¤yòê?zqî?q×Ì
³ü???nfÛÿ\Kµ&k8FN|ça£ó?Ý!õ
\ No newline at end of file
+âYÀ4ðì1¼2?wsÏÏ\w{]/\³®OMsÄZLN ñëÇ?xrì?f¥ÏmuÉZǺgÿ?Åúp}Tþ¾æQC?õCéUªë®d|g5õÆg©~¨5×$Ô8zÄ'®;X¡s:?÷?IëXít:®¥p?kéUõÿ'^½{˺?êµú$Òó?s
\ No newline at end of file
+Ñò<?k²?GØñr¾¸?ãw¤¶×²òº?g?Ô?æ?hG
+w°5ïç2æÈ?Êe)¶ÌÞ¸?ZXÝÍg3©ç2??\?ö?)l¼ox7fèFF?
+w|P¢ÛNôÌ?¬?Sýè?Z??ܼ®£?ç5&¹ÏÚ?ÚTÞñns®l?\¦R?lÍë?isw=?ºs))ÈßhÀ²ñ½àÝ?Ä##NJFÏ?
+Ø?Õ?  *M?óD¡KFéC?Ôs¼æ¤×9ûB%Mßç:fÈ?Êe)¶ÌÞ¸Qicw=?Χ?ÊJEr7Ú?ïÁ»;?,?1???J-±ñ¦dèÀTÿzlíx¹9]G3ÎjMs?´
 ZWÅñns¦l?\¦R?lÍ?/âç³?Ðó?IH®FûP ½ãx7fèFF?FÏ?oÆ$Êâ°'ûPÚrrºw?Ô?ç?hD- 
]ñns®l?\¦R?lÍë?c?¹ìæt<æRR+?¾Ñ???ïìÝÈÓÙñ@jEé?:°'ûPZrrºw?Ô?ç?h@»âÜçLÙ¹L¥6Ù?×qw=?Î??ÊJEr7Ú0Â÷?vn?di??lø 5"ôÌ?Ø
+ý¨­¹9];ÎjMs?´ ]ñns¦l?\¦R?lÍë?8»?ÎgCÎe%"¹íá{Á»7B24ÀB6|P?zfN?l 
þÔV?Ü?®??ç5&¹ÏÚ.ø·9Ó6D®S)M¶fõÀ]Ïg3¡ç2??\?ö?ð½àÝ?¡`!>(
\ No newline at end of file
+H½3'@6?ÿj+BîNWAÎó??\çí|[?é?"W)?¦Û3zà.ç³?Ðó?IH®FûFx^ðnÍÐ??0??¤^?? Bµ?¡w'+ çyÍI®sö?¾-ÎtÍ?+?ÊSm?½psÙÌèy̤¤W#}£¼/x7fèFF?FÏ?R/LÉÐ
\ No newline at end of file
+?¡?Ú?Êл??Ðs¼æ¤×9ûBßç:fÈ?Êe)¶ÌÞ¸?¹ìæt<æRR+?¾Ñ?^¼³t##L#gÅ©¦dèÀP?í@eh]ÉÊè9ÞsRk?ý¡ï?s?3dJå2?Ûfo\ÅÜös:s))ÈßhÀ/Þ
\ No newline at end of file
+Ùº?¦³â?Ô?Ó2t`(Oö 2´.äåtï9©5Î~Ð?wŹÎ?²%r?Jm³7®âî{9?9???äo´`?ïìÝÈÓÙñ@jEé?:°'ûPZrrºw?Ô?ç?h@»âÜçLÙ¹L¥6Ù?×qw=?Î??ÊJEr7Ú0Â÷?vn?di??lø 8]\Ü]¡?®@R?Lûë¶~¨¸î?³¨ÑÝ??JC»ÍÉWäÿ.ù?ºÆ?^è
   
pS.ß?>·Àǹ×ù?¥[êobøåÔY2W?ãÛÓ;»ó·Â¼ëѵ?­?Wû­ëWU´ÝBÙ??4͸ñ??-2Lr?5ÅßùgÏ?5û=Ìî¶µ-%éýL?%ýÊÇczc3?㤽½^Dg©þ¢ä?V
MGö,c.?0ɵ¥ä¹ðØÔúbÝ¥S?rû"æ."f£       
Æf)¨?y~©çÏ/ô?mkuÊ÷ð-s¿Ë,>xïÕ×9¸öçjù?ZýÒêét¯L_Ñèý??&¸Fý G·zµ??|?íÙÒÛó¶»\ÁµZë??f2ù£éte?äa/Q¥ó?]gôºã?Ù[¾Ò?ñô#Î)óç<ºçG[«ê=S 8}>©ÛFõµyLÖ\A???Ç}?þ?/?ÚK¸é¿¹Ïhªu!Ðᨲeó©úãÍS?Ñ?ddú>?ÌZ>¥d^ÒjVòð£´b#¾8<¹eIÔj??3?rè´Çȧ?ÖêY
       
öG?³Æ§·«Ê·DÝqì´?È?±æã0ôò?¡ºy?\ew¤ã¶5:K?W5³æMV?ཤ¼@¤ñ#q?]sx³?xöEdúGýÁÑõ5µbû?6©Y%c2vàk?{º3dzæùÝýYuëèõßÕ
\ No newline at end of file
+y½¦ôõ}?ë5N©ø7y½¤õÄ??a~¸½På~m?±       
éXïqÇU?ëc6.=1?éѨîy½gU¡æ?}?çéOÛ?[\òoHqmØÕI?Y÷WFÖù¯;îËðü¡ú_+éÆ~?½µ»Ì?ݦÎL?Ó?Ò­J{,?Åvð?yeå?-\e
+-/y?Y?¦Y9"ykÈÔ¡?E¢õö6o        Ç#T?¥>(Qm¼v?̧PWûÐ¥¶v¯0ZZf?¹¡Zs?T?Qi[ÍâÜ>Ï*
³YâÕïJZïy?Ú?¦Y95Ë^F¥    
?KeëîlÝ?£T?ÝñB?no¸§?æDÔ¯ÎÑ)mKW?!ü'i»?"´çjT?Qi[ÍâÝ>O"
¼³Å«Þ?J[K^%ìÎÓ¬??2µäjPÂ?MÛÌlÝ?£T?ÝÁ¢QmÍç?eÌ? 
¯÷¡KjZºÁii?læ?iÌiSÖ[Íâ¹ð?ye?Ï®2?KikÌ^Ìí2ÉÉË^F¥
(MëÌlÝ???Y®ï?[cu¦@²æ[fµÿj%*?®0JZv?¹¡Zs?TÀ´­Æñn  
ç?Y¬ñjã(?¸ÅìÎÓ,??<µäjQ¢R?®±³tx.&?RV?ø 67?2Û5þô-;¥¦i»?"´ç4©?X®Þ-Ãá<ò Ë5?-\eؽ?Úu??&V¼?Jçcfèð\M¤­)ñ@j]?#Ás- ­Ú?ÊÓ°JZv?¹2+NsJ?vñn
   ç?Y¬ñjã(»³;N²rDÊ×?©C¼ìlÝ?£T?¥>(
\ No newline at end of file
+K°$x.e´¯ûPZv KNÓw&EiÎiSÞ-Ãá<ò 
Ë5?-\ewbögiÖNH?Zò5(`???£Áq4j?´§Å©v?̶?µÿj+NÁ)iÚnäÈ­9Í*`ÛŸ|'?Df³Å«? ì^Ìí:ÉÉ+^F¥

ó±³tx.&?RV?ø 5.À?à¹?ÐV¿í@eiØ%-;MÜ?§9¥L;x·?óÈ?,Öxµq?Ý?Ù?§Y9"ekÈÔ¡?^v6n?ÄѪJÒ?¥Ø<2Ú
+×ý¨
­;¥§i»?"´ç4©?oáð?ye?Ï®2?;±{3´ë'$L­y?0ÎÆÍÑà¸?5IZSâ?Ô»G?æ[AZÿµ?§`?´í7rdV?æ?0íâÜ>Ï"

³YâÕÆPv/fv?dä??¯#R?yØÙº<F©+J|P?`Hð\Ëh+_ö 2´ì??¦îL?Ó?Ò¦¼[?ÂyäA?k<Z¸ÊîÅìÎÓ¬??2µäjPÀ/;7G?âhÕ%iO?Rì
    
?mkþÔV??RÓ´ÝÉ?Zs?TÀ·?pøO<?2Íg?W@ؽ?Úu??&V¼?Jçcfèð\M¤­)ñ@uÝuÛúf¨xl6ùùeù?Æq¬wL¶t$Ô³C?Âù#-?õÍPÐ\n¥åó'b
\ No newline at end of file
+ý&Ï?ý?o?ìü_Õ¥ú?²ÓXÖj
+ëmȺ¹?ͧîôõ÷¹ÝkA¥ë:[?{üèóÊã{:.¼;mñÿ4yBÿé|,ÃU¥·?ÛF£¡UXG?\t??øÆ?ãôO:Üòç?ÓüêÓ[?OÔ®?xrÁ.?üÆO×a߯ɽ2Ò[u¿ÞO)i­\ýÿê·Þ¶d?-¬ÞÐâzpñ>¦æ~O
        Ñù?ο¿W??·: ý1?ôú9/Ú 
ÇYñ#ª/v1òç²kgÏú/î??ºÝïÓ?kiõNÆ¡,vO?k§,s?g¶2Â-ôý/Y¶Rûºw%ÐAò?£×<tËg?²9~¬7aª/eÞö?æuZ½±?ã=??
   
¼W¯Èç??¡ó`Ìi?Ú#¯?Úãät=×Mó2?:]TµK?L?Yqõp?Ê*_#<g¸u½g@ú4:î?ÇUÓ®w?b?èòwø??¸ìõôy??éËwI ó&§§]]F?Röä{êdG6Ç?¯?Ñ?¿7Ö:/î.?T©g©ÊË?
\ No newline at end of file
+R÷Ä1$zðê½?ó­Þºî¦Þ¢Ò½·[¶ÜMYLÁâ??EÃ1ßO!ÔѤÅj7G?»Ä{ú|Ç?ÕkîéÉæ2óóê?_GèÉÆ·æFJ;Íx?#xeLg?µ¹Õ?è-]Êã¸íôc-cwî?t??¯¡~êkzk[Ðõk?wJ
?öi²ìå;pÀǧ£Èã<sy|?3?]rûGOó5?¡ ¹ªÑë<k,Öäá?(Ô#xGÕ?¸Ê¦>ÉÆâ\?ë7
+ÝüV¢ï;ÄnzúÌ-õ?:?#Åc7ZLï?åÑ£x÷êó?¾¯rGñXü¦/Ñ??çìÚ?j??z=ྶ`°?5?ÆøüwÜñ¯#/Ãò?ìþ×?øØÏÏó?ÐÓSmV·?f,DØT5?>??SoÄvñ?.D³
   No¶Z[Sm??]V??dÂ?#B?$»ª´lÞòQ??2?Øj­? 
Þ@DÁ?×?ggSmTfº¢näM?FsXQbê?ŸÞ*åÊ?6a)Í©
+[^æªÙ¹jWU²¹&L?F¬(²ö®ÑµtÊIC n?E·:»B?ò       ¥µmjmªÝQ7r&ÀLjÄ¢ÖMM¿ëx«?"
Ù?§6¤áKimM¶{2º¦LI?±(´ÝÕY6®?y (ÀÃt)m¹ÔÚRA¼ ?"?Z¶µ6Õ+uDÙÈ?
+?ư¥µ?¢ß?íâ®\?3f?Þ?)mfÔÚf³+ªdä?0 Õ?Kk]ÔÙk7?¼??`aº[ÔZ?y 
°?KjÙÔ[U溢näM??Îk?Jê-x·Å\¹fÌ%9µ «5ûLörÜFÊä?0 ÈÕ?i½¨²lÝêQ¤
\ No newline at end of file
+ѱ¿d
\ No newline at end of file
+ÔP?©jõ¥Nkª&îDØ      
?æ°[JßµâÜo2äA?bS?Rq(K^´Ïg-Õ9X?&@#Vo_²lÝêQ??è?SzÈ$¨¡??«¶?9® 
?¹"£9¬]µâÜo2äA?bS?Rp»i?Î[?dä?A?«½zɳt¨IF 57¬?Aº??X@ejí¥Nk?&îDȨÎkmx·ÄL¹f??æÔ?îÚg³?â9&DPdjÀ/^²lÝêQ??è
\ No newline at end of file
+Më ?n "?Z»iS?â      
»?2*3?ÀÛ^-Æñ.D¦%9µ'{¶?ìå¸?NI?°׬?7@º??`aºSzÈ$¨¡?V®ÚTæ¸?näL??æ°v×?q¼DË?i?NmIÀí¦{9n!??dEF¬õë&ÍÐ.¡%n?ÔÞ²
     ê(Aa?«¶?9® 
?¹"£9¬]µâÜo2äA?bS?Rp»i?Î[?dä?A?«½zɳt¨IF 57¬?Aº??X@ejí¥Nk?&îDȨÎkmx·ÄL¹f??æÔ?îÚg³?â9&DPdjÀ/^²lÝêQ??è
\ No newline at end of file
+Më ?n "?Z»iS?â      
»?2*3?ÀÛ^-Æñ.D¦%9µ'{¶?ìå¸?NI?°׬?7@º??`aºSzÈ$¨¡?V®ÚTæ¸?näL??æ°v×?q¼DË?i?NmIÀí¦{9n!??dEF¬õë&ÍÐ.¡%n?ë:ýËg¥jÐ\Ró¶2?'K?²5?é;<ö?Ù?Ë0ô?Ê?4ü}c¨3\@rTû«õGï2êÑüëê</?:3êo&¿@R۬΢ª?ã??yû|h?XìkÒ|Â?SúÌ??Va??xþ?==]îÏ­º?7¬Øk2Á¼ï.U+9ÐG?·§??öáÛoåÇîÿ?u7zåî?§Õ3èúk½­?<?$Æw.o?Â5Õãý(¿Uçõ4??×u¾±Õ4Þ?]Ý?ËfÛm?Ù;øë?F
 
tÃ)ëßXp<½Ð¼ËÕuMi-ø7=ë¦VÛyàx?å×?xË®s?qï¼ùö?¢^)¨Öj<~ª?-¦'"ÂXÇ»Ýc÷<yyyõi:âû?¤Þ6ÇO:Ò_´%l?ÈãøÊ=?tå?qËI??>Üzç?3q.²åíGO¾tú?Ö?ÙåÚÉÙ½cÏ1=sRôÅvEÇþ,µ
+u??§"Þ¤VKݹÄn1rêç¬n?öðÓ-¿&z>µrÙð®???åéî?Ò\ûüx?cg»é>dk80½¦º%rËUHÛ9Ç×éí?¡ñ{úgpúïJmúÇC%ì?ê´f¬?êãü?ýX:øþgú3þoc«5³?Ûø??*cËÕ?lôöãzKÛôO7kt$6£ðÉçÓ½Pü?;D}>¾9ÃäöÄá/¥è¼ÑÓú²?wÒj?HÚsÊOÙhÞ^;?>C«êÚ,á?iïÞþ?6?.êi{NÌV`?D|~ßq}??&2yÏëWl7x?b#?8Ë®xÆPä[µªB®DÎ*cÙ?È©xòå×7
\ No newline at end of file
+ú_?zÏ?õ_ªéÚ?sO?ÆÓ¸¬ÆV?aô??¬9ôN?ÃÆDVZKô??uzw?,Bæ?IÔ2WJÖíó?ä%FnÌcíxÝ?}ûnø>WGg?¾Ïag­ÜmN?~?â??VÆ$}?õgãÅ<?÷ͼ毭Ý??³¶?
\ No newline at end of file
+¿îÅ??ù~éý?Õ5ïÛ/\9f_^( 
+kµ8Gàþï?yYÇËò?ïþÏ?ø¸OÏó?Ó­Ý9vw?`÷?|ØÅôìO?ø~ZlÞNK=Ó;8~aØ=Æ?Åy®?þ?Ûèq-²Ý38`v
\ No newline at end of file
+Ð?NLì]9v~cìù?ź|k?w`ÞÐâZ×n?Îó°{??ò/Ý>
\ No newline at end of file
+Ü?-¶
\ No newline at end of file
+Ðâroã£NÁÂ'?;7¿
\ No newline at end of file
+°üÇØ=æ?äº]ükÕ??¼Ñ8¯$µÓ?ÅG|ìãB?Ék×??wãl¢Ròr
\ No newline at end of file
+Ú?ÝÐ¥ä¥?¼§ûýã?]nþ3áùi÷?%-¬÷9¬|gî4)m¥ë?±ãz
JX?âäJ[WNç)ÿä¾bL-¬·?çÀ???µÇç±ÿÈ~ãD¥µï·àÞÿãoDJ[m?%-«eùÿ#ýó
+Vük?zZZ\óØøÏÜh?i¾÷ÀÞ?Úq)T²yÆÿ|ÀJ?ǹð'¥¢        
¹ß±ñ?¸ÐRÿä^øÑ¬V{?ã¾`óî|   éhÎý??ýÆ?_ü?ßz 
5?ÊÏpüo÷Ì~}Ï?=-¹ß±ñ?¸Ðÿ?{àoD°Yî?þù?Ϲð'¥ ;ö>3÷ò/|
\ No newline at end of file
+è?Ö+=Ãñ¿ß0ù÷>ô´ç~ÇÆ~ã@/þEï?½Àeg¸~7ûæ?>çÀ???\ïØøÏÜhÿȽð7¢X
¬÷Æÿ|ÀçÜøÒÐ?ûû?¿ù¾ô@k??áøßï?üû?zZs¿cã?q ÿ"÷ÀÞ?¯Ìé¿ðÿÌXÖ;¤ìó}??Ë0ô?Ê?4ü¤êݶ2­O®?¥çÖþS=?96õÊe$_?ýq?ºÝ±ìt]_¤Ú½©¿ÔtH©¬????G\cÉÙÑqnØö>aæ¯4õK]¯?+úv·¥];]3ÌIP)3Æ<8tÏ(vǺbÌÿ4[{½sUâ?³ÜÄÏ
      
öÇnÎ?·««»Gê?ÛoÚ^?Öü·¥Ôêô«{S¨­O¾ô£ÃÙ×0õãßn/?kz¿?-~³§/ê´kQrØ9?ë?á5:ÂÖ·¾M£ó?Íácª+X*Òµ«Ðw£å?18ë;c?e¤îûW@ó??jÒj]oÛ#?ö4í?¡ãy¾?>?àúàô]NÖ?­X.;?aÛÞά{±xº»réÉóæ×èu
\ No newline at end of file
+dÙk??ÂT®Øù9c?NU;>¼e?~7»6èc© ¹â?WðK?L?e§é??a±q»?g?TÔìêZÞ³¦^6î)??]üc}¹uÍK}½8öÅÆÏEÓº½ý+-Û/54eÄ´kÇï??Âò|i?W­t+]RÛõn?­Z

Ú­Ú6?D^ÿ?êÃv|*pýìù?£Ìº.?[õ7Å«öésM:Ï?yº³?ø½]Ýwðëÿ©£?º;?Ó3GÙèí??_Éè?{o/~ðj-?ÓõK&ö???§2£·õOF9Æ?ÕËÕ¼N?æ=Öôë«zÛ
  
0­¸?ÇÏò<7¿Çóiòþ»Ò®Ù,r?k&??äxs?ïxþde?ju´Ï"J?Û3?½÷B-õÂ@KÍ]?ήßIx»zkXq¯ß¸?5Z+Þ¡H`T?
       Oqãg£ýXîå?úsÖTòGïXÒj´?;Í?ùw]Hæ.#¾ó 
O|ãèxþ}þ?Íÿ?h|Ï+íÕúúµ?ãÞ_^n³§ÕYMF?Á¿bèÍjê32?v?>ß?|NU5/è?ìk%ßÚÿ-¹f¹Ô(À§PÔ?z??ýïýæ?ü°þ?ö<¯ÃÃñÿ?_WP?¢s¡`$Ì=£¸ÇÊ?}{_×?Y÷Úx¾ÙÎ??ÁAµÞ«?fì}?ÞbRÚ.?o??}·>¸´[p³wªÑÜl<bQÎÎRz?â?ÃÛ;?(±rø??YP÷Úx¶Ùμ?¹?]·Þ«?fì}?ÞbD?Á«??y
 «¹ÙñE¢Û??Læ«mÆïµ????fy¨ì??´Û?(ä?    
â^ÒÈ?¾Óï6ÙÎ%/$?¡íK5Y??¹öy?Á?¹«??aÛs³?C?ÉÈl??óT?mÇ®'ä­²¥k??àIØ{Gq?KÉq?Äeæ?D=ö?/¶s?KÉvÊ̳UÈ3v>Ão1)c%îä/j!öÜìí?Kä??6®çqë?Kh±??«QÜQØ{gq?0¶ºåñn,ÚYP÷Úx¶Ùζ»jEªä»a·??¶½åAjéæ?7c³¶%-·Ê¤Ì?®çaë?Kh²ªÖêZ?àIØ{M¸Ä¥µ?SŸ³idCßiâÛg8?ZìªÌ?U?3v>Ão0[MÔQfé?Ñc³¶"·È??7®çaë?­¤VZ?£¸vÙÜb*UŸ³idC<í<[lçÖdUk2-W
 ÍØû
\ No newline at end of file
+¼Ä¥Mëh,Ý3y?l]?ÎØ
\ No newline at end of file
+?µ$?½w;\A?«jÉRôwNÃÛ;?ן³ydCßiâÛg8ÛPöd^®A?±öy?^´¢ÍÓ7¢6.Çgl¦Ò?LÞ»??®+VÔ¥KÑÜ
     
;lî0m|[?7?D=ö?-¶s?=µfEêä»a·?ëJ,Ý3z#bìvvÀjm)$Íë¹Øzà2µmJT½À?°öÎãן³ydCßiâÛg8ÛPöd^®A?±öy?^´¢ÍÓ7¢6.Çgl¦Ò?LÞ»??®+VÔ¥KÑÜ
        
;lî0m|[?7?D=ö?-¶s?=µfEêä»a·?ëJ,Ý3z#bìvvÀjm)$Íë¹Øzà2µmJT½À?°öÎãן³ydCßiâÛg8ÛPöd^®A?±öy?^´¢ÍÓ7¢6.Çgl¦Ò?LÞ»??®+VÔ¥KÑÜ
        
;lî0m|[?7?D=ö?-¶s?=µfEêä»a·?ëJ,Ý3z#bìvvÀjm)$Íë¹Øzà2µmJT½À?°öÎãן³ydCßiâÛg8ÛPöd^®A?±öy?^´¢ÍÓ7¢6.ÇglY×í¨éZ¶?Nvé??­ÅÙ9F±Ý'g?éø,nY?¤þTa§ó?K©³ã[?¹<ÛÇÕÕòÃGñ¹Îiȵª²=??ù?ÕËXÎ]²êìçi??ã´}QÆp?|3??ýÁòþ?­ô.§ú
 öµ§L¯B%s*?¦4Æ<ñÕ¬;FWæo?ºYÑëÓPö.ZkªEÌ1ð??TÛ§Wl¿L~×yÇKÓ¼·Ón??Ên
+K?âϯW§É·Ü´~ké{J4$?¾1çV 
ÌÙLúõÑíëíx?7ÓïHó5­F¿Ëî©|£5Í=$L§"#?öq?²?\?'Ûÿ<y{ÌÑú~?íÂ\?Ò<ÊKz¶ÎÈéó?7kêN»gÛ:Fê?9Ðu
 t÷@°àån÷ǧ«³.¹§î¼;"Þñ?§j¬?fÜ?l=à~ÉÝéÏØ©x#
ºfãg?ÖhY/[¢ÙÃÅö;lxóÃ?ÛÝ?q?S?MkV¾¬7×òn7Ñ=â,×f?ºEõë?Ï?õ¾¯Ó<´×U©Pã½eH3<eÂ3ëɼøvâù¾«÷/¨jnÏ¡)Ѫ?·µ/ª>×?Ûo?äxµ»Éõ®?<Ø­Ô,\6ºÊM®Ø?.ï(7ð?½ýÛú£wºzg?ZÃÄi¼M=ãbú?7ÐÉ?í?yz»'ªwz»ºbbãXzý
\ No newline at end of file
+ûmÊÜ­»d}?Èô|/'Æö{^?×µþ_Õ.¯¦êJ/Æ)qw2ÇÒÆ1ÏwÉÏ?>ñk­h:Ö?×ë-?#Þ@É{m?oö~XÏ?ö?ãËb¿?V¼o¹ñʲÒ??Ãù?ËL¹Ý20?#qÚ#ò¾O?0ýG?ç[ä}KE{JÍ0r?¢>N]s?¾¾??¥]uË')i©Ùº;õvÎ.=½1?
\ No newline at end of file
+[YÖÛ??Æb¹ÇØxã,º¥¯Aóß^òeð?!Öô¦oÆÓ9å3Äàr?#å:ôy]?4Ôë?G?×åEÆ??¹?ôÉæ-?ÿdü?Özs5­>·ú?­? 3©^¥ªV?æDGæ~ïÙ?VyGÃþX~?íSÕâá?ú_üÒûÒ?!&­9¬ë?ñóbNe?Äna<?\´?ßdáIif??7?Ë?UÈÜL(´]fðoMÁ
Æ_þ¨T?Ø3fi8M W?ûP¥??Úf 
e`9ÞsY×9â!E¡Y¼K?ã6T®ZJm²p¢×¸ÍâÛÌàóIe\?ÄÄ£?/3øW&à??`,¶|P£??Ìò83He?Ùö¡KÉ?¶o?;Nk:æn"%IÉdfÏ?fÈ?ËIfm??-??=©¸5iIe\?ÄÂ`??¬þɸ#)?Ë-?&MÙ?;Éij
¿ýQ"eKnÙhÀs4æ³®cÄB??áÛ9ç?%rÒY?dýq)yBåÛ5?¸<í),«?ãS??/qßÀ¿7R2?²Ø~ÔI??? 
;?dêÀT?íD¥å?bWQÎó??\çí?ÊGç:æÊ?ËIM¶N%5mÜ\µ?Áç2??\?ÄÄ¥¶??ç?rw?
Ì;¾(Í-¹®N?
\ No newline at end of file
+?©þô)mZç?dê9ÞsRk?¾Ð?Kk#\ñns®l?\¦R?lÍ?Ú»?ÎgSÌe%"¹í?k]k¾ÙÜIdi?¤>(?¶ÞwfdêÉ©þôJ[E£s)Êê9?sRk?ý¡e7<[?:æÈ?Êe)¶ÌÞ¸?«±»?ÎgSÎrÉH®FûP¡7|_ìî!c!?"ÛoÆ??Ä`*½µ-x¹(ê9?sRk?ý¡Jø¾-Á?sdJå2?Ûfh???ÎgCÎe%"¹í?¢ð½àÝ?Ä##L#gÅlEé?:°'ûPZrrºw?Ô?ç?h@»âÜçLÙ¹L¥6Ù?×qw=?Î??ÊJEr7Ú0Â÷?vn?di??lø 5"ôÌ?Ø
+ý¨­¹9];ÎjMs?´ ]ñns¦l?\¦R?lÍë?8»?ÎgCÎe%"¹íá{Á»7B24ÀB6|P?zfN?l 
þÔV?Ü?®??ç5&¹ÏÚ.ø·9Ó6D®S)M¶fõÀ]Ïg3¡ç2??\?ö?ð½àÝ?¡`!>(
\ No newline at end of file
+H½3'@6?ÿj+BîNWAÎó??\çí|[?é?"W)?¦Û3zà.ç³?Ðó?IH®FûFx^ðnÍÐ??0??¤^?? Bµ?¡w'+ çyÍI®sö?¾-ÎtÍ?+?ÊSm?½psÙÌèy̤¤W#}£¼/x7fèFF?FÏ?R/LÉÐ
\ No newline at end of file
+?¡?Ú?Êл??Ðs¼æ¤×9ûBßç:fÈ?Êe)¶ÌÞ¸?¹ìæt<æRR+?¾Ñ?^¼³t##L#gÅÖuñsúV¬?R?·Ë?ÏólýQ¬wIÙçº~?aé??iüÓÒµ±~Ññxlþ1ýw=?Ŧf?Ú¹omÂðÿÌäK´W·â?9ÇgØã0í?»¢Ö?åf$5«`Óz1ç?z0??r<?£êiÔ:}Ôðõ6ó¶?öP
  
?S?èôÏëÅÏã?ó??u:Î?u]S?ÛKÌTË1????3otO«ê]#®¾?WSmȽ§"J)1óÇ?³|s}ÃÉß»¶ºmän¢rªdf$ñwa{½Ý]??Fy:ï?¼énïUM=«?®¹Y?¤#ÉÛ9á0ú=\{4?y×¼?Òú®?í¾?1?/(Ç
 
í?õyó:vlÇo?=«ç?1y[ÐÚíÅS¨Ò/vúclûm?¡?±q¬<ñ?e¦Òø_?|ñÐüµ?5??ºê9PV¿kq?N8ÎLN5¶ï?õ¿Ü®§Ö]ìôÔðôLdQ?ö«G||xÇär¿?¼ÓhïõÍÔ.¶¥Lòê^sIìqº;LDÅNÞìF<fãgU{§]é×?@W-T?Çè"<ÓÕ??GéìÇW7G­"º7?y

ÖGhݾ?*þo?äxucÔ4z_2Y-iBu?By??v[ΣÑÛר߫Ç×?]^???UÝ¡´?éÛ¿lÉ@¥FÃÆ<?]³?\rvíè?ñå?ÎûKÕnU',û²ÛòGÛñü?Ýð¼?ÙöÏ#u[zÝ£A{½¦!­N¼??Ȧ?UöîÎxÌ{?/çtñÊßIÑ_@Òê¿Bæ@??SÚ8p?^Û£¶',wüÿ«^'??TÔíü|w?|?.)»eC+?«
8üW?â?_âù??u?,_°ÎQ
\ No newline at end of file
+       
å?|^Î?Æ_w«º2??½¤¿i?Sl?cÙ1-ç×á]Stº+)Ç·øËIx³é?u?öwþ?íÜÑÓßíêéí²?=X?¥e^¯­&S#|~SîQÇÈʾ??YöÙåããÎ_ª´=X]P?í?¹??a?]â$f±æÃ8?£>¹?jçc?ç?^YâõïJ:9%??jhâW
 
®Zò5(лpø7§mÀÈkËýè£e¸C7á¹£W?qûQ$efáI¦ìi?ß4«@çâ\9yPeå?-^ô¡B÷nÜíºÉÎ9kÈÔ£D?U¿t?W¶ã?ÔåÝÁ¢?Úé
+?
\ No newline at end of file
+ÈÌÒ<µÃíB?«?¶d?fí9e§3R­ZÝÎ{ç#ÏÃA??}ã^ô¡*?vokðØH±®Zò5(Ð??\ºM»??âjjrîø¡*Ýî?î<72c^]ÿH%?]!h?fX?e§1¥Zþ)ÎNG??¼¼³ï={Ò?Z¨×I6gm?NÒ?ZòQ¡E¯réð/?
\ No newline at end of file
+À*jrÒ?íD?X? ^ 
·á¹ùkþÔJ[4÷?Ë$v?±¦Zs?U¢L5²^>%Ãá¼ò ËË<Z½éD¥¶Í|??¦?²rDò×?©F?ÓVÒýòm\Ó?Û59}Þ
\ No newline at end of file
+?Ü?§/        
̶?µ¯?MZlÞ"Ùü7i»?,´æjU¢SVº^>%Óá¼ò'/,ñj÷¢RÛ_?³øn²f5Ë^F¥$ÂÄ­vóWA²àjòîø¢-¹3@´æX?¿;D¥´ZºÁL­;MÜЭ9Í*Ñ)muºÞ-Ãá<ò
 ËË<Z½éD¥µÚë±øN²rDò×?©C?k·XÙº
\ No newline at end of file
+?F©ËJph
\ No newline at end of file
+üV?ḛ3ZüíUµq?RÓ´ÙÉ?Zs?U ,·Ÿ|&?Tf³Å«?¢-¥®1{3´ë'&¥kÈÔ¡?Úo]cfè6\M¤®ï? 
ÛÄ`H\ËlÖ¿íD´ì??¦ÎL?Ó?Ò¦`vñn     §?Y¬ñjã(»³;N²rDÊ×?©C¼ìlÝ?£T?¥>(
\ No newline at end of file
+K°$x.e´¯ûPZv KNÓw&EiÎiSÞ-Ãá<ò 
Ë5?-\ewbögiÖNH?Zò5(`???£Áq4j?´§Å©v?̶?µÿj+NÁ)iÚnäÈ­9Í*`ÛŸ|'?Df³Å«? ì^Ìí:ÉÉ+^F¥

ó±³tx.&?RV?ø 5.À?à¹?ÐV¿í@eiØ%-;MÜ?§9¥L;x·?óÈ?,Öxµq?Ý?Ù?§Y9"ekÈÔ¡?^v6n?ÄѪJÒ?¥Ø<2Ú
+×ý¨
­;¥§i»?"´ç4©?oáð?ye?Ï®2?;±{3´ë'$L­y?0ÎÆÍÑà¸?5IZSâ?Ô»G?æ[AZÿµ?§`?´í7rdV?æ?0íâÜ>Ï"
³YâÕÆPv/fv?dä??¯#R?yØÙº<F©+J|Pg_f=+V¾;|ü²üÅã?¢5?é;<÷OÁcrÌ='ò£
\ No newline at end of file
+?'§ì^?.?µæ-Jåî?µm«ÆL³?Ûýs¾üß?ËþÞë?³?äá?ìUÕ3±æ?;?æ?_H¼}¸ÿ¸=ðþ¿äÌÿÛÞÝ?ÓüØ\ý?ëèìlu­ÐZ`8¸??Ѹûï_®3ýÿà{#l£ú¢ÿío?í0)úNT@<+ò??æ*C»ôO¼~
   
ÿÃwãí?)ÿ|ÛÏÿ¶>okHtGfÓ?ù·vÕÉ©c#ÈäǧÇû?DÍrüÿÁçîûg??¼/ñ~!óÿ?úÏ?ºÍ?µ£ê,èõ7CjÛ!'!9?%Xé?w\åq?61éì?©Æcðm¬ò£ÞÑ?©Ñ.£¨ôùÖFx?aÛ×k
  ?U5/?k®êm-í©N?èÌm?Â?G
+ÇÌî·{ºó~?ý?óF¹:.§KgY-KÔ?q?QÄÄëÂ7Ó×?fé?g­û+ËÞ{³¬ð´zð,ê?@¼Ä?1óü?µ?ãú¾?O?5Rù§ïÿî?Ë]8t®?ÖοZ¤2|tûWV\¦dòøLhþgu?*ëzö®ö»Åczëf{,s+Là#õôÄþ×ÎçÇs¦ùNî??ö?rã`ÿd?GLÄÓ¬ö\küÝ«ØrL?s´Ðö?Ë8ã-F°àx?Ô?é´ºsq?
      
alïÍ»x?uÏHI?º]G?F?ñ»¬¹?ï{ôöè?cC??>^$ã?¬y1?.çE}?¦?Âü¶Q"?ú^?ui/?åx÷¬9=gʺ/4Yɨ_ÓuU_ÀÖ
 
?<°ôdz·ÇÇÈ?õ|î¾ì¼y¿GÅz??_å?Chú­?±m[*êîr©í-)GÏ?sè?9½¹pï?Xnö>@ó?:ö?Ïõ+Y;[¸¬y?×ï£ûO?ò"v??û??Ï
  ?Þ§¬*:?{?æ~¾eùiÁõ/(Z^©¢¿Ó.?×tc=?¾Û?ð?üÏÝú#
ùúOæúÿoì??>°é<Å䵸?UGæûüxÊ4}ÿÉ?f¥ð?¿äæ²ÎËn¢r 
GÃïñøËïty0ù~¿£½?`RRÀð?%ÓÛQ/ë÷ý)³ûä+W.(eþ«0H½WXcàù¹_v_?å»ác]8þ??¿@h ?ÅRYÈ3f5?6ïU¹ZN©ú{?·®?¢??¥Z?ú£xç[±?]ëF?ìj-Ú{7­ºç$É??#cZGnPã1IºöÍ?À]¶IC!?~¸¶Í5mY?»l?w0?"Ùts]¶&ìG:Ôg5Æ?éâ;x¶òåA?:Êsjcái{®?u2ݶdÄ?u ÊÕÆ%?º/½³nàm?P?3®îØYM?í?ݶf?μ8ÁYÛdÌîÛv"n¸fjã¶É?ûx¶òäA?:Êy?ÙÄõS:µ+¨dX?:Ðdjã
   ?¤\{fÛ?vÙ%L?uÝÛ 
??»Ûàݶc0]wöÄ?U?(?Ëbe??¨¦c\a-?ÞlÞ*eÈ¢y?SÌûgÔ¡?Ù?ÛfNÄÉÖ?!ãZ.=³bøm?TÈ]Ç?I???¶zØ"s×ë?ʧOq¡k¶Äî1u¨Îk?I??£§?q¼TË?lë)Í©9ÄÐj÷Q®[ËvÙ??dëA?¸&#x