CD001LINUX CDROM ||.."k  $ MKISOFS ISO 9660/HFS FILESYSTEM BUILDER & CDRECORD CD-R/DVD CREATOR (C) 1993 E.YOUNGDALE (C) 1997 J.PEARSON/J.SCHILLING 2007111009200900$2007111009200900$00000000000000002007111009200900$ CD001IOSUSRBINIOSUSRBINk  $SPRRPX$AATFk  $k  $k  $CEfk  $RRPX$AATFk  $k  $k  $pk :$IOSRRNMiosPX$AATFk :$k $k :$PPk  $SHSCRIPT.TXT;1RRNMshscript.txtPX$TFk  $k  $k  $pk  $!$USRRRNMusrPX$AATFk  $!$k $k ,9$fk  $!$RRPX$AATFk  $!$k  $k ,9$fk  $RRPX$AATFk  $k  $k  $pk  '$BINRRNMbinPX$AATFk  '$k $k ,9$fk  '$RRPX$AATFk  '$k  $k ,9$fk  $!$RRPX$AATFk  $!$k  $k ,9$k  %$ CONFIGOB.PY;1RRNMconfigobj.pyPX$TFk  %$k $k ,9$XXCCk  % $CONFIGOB.PYC;1RRNMconfigobj.pycPX$TFk  % $k $k ,9$CCk  %$CONFIGOB.PYO;1RRNMconfigobj.pyoPX$TFk  %$k $k ,9$~k  %$ CONFIGSP.;1RRNMconfigspecPX$TFk  %$k $k ,9$44k  &$ CONSOLE.PY;1RRNMconsole.pyPX$TFk  &$k $k ,9$´k  &$ CONSOLE.PYC;1RRNMconsole.pycPX$TFk  &$k $k ,9$Ӵk  & $ CONSOLE.PYO;1RRNMconsole.pyoPX$TFk  & $k $k ,9$|k  &$ DYNAGEN.;1RRNM dynagenPX$TFk  &$k $k ,9$k  &$ DYNAGEN.INI;1RRNMdynagen.iniPX$TFk  &$k $k ,9$|ddk  &#$ DYNAMIPS.;1RRNM dynamipsPX$TFk  &#$k $k ,9$))k  &1$ DYNAMIPS.PY;1RRNMdynamips_lib.pyPX$TFk  &1$k $k ,9$؅k  &5$DYNAMIPS.PYC;1RRNMdynamips_lib.pycPX$TFk  &5$k $k ,9$--؅k  &8$DYNAMIPS.PYO;1RRNMdynamips_lib.pyoPX$TFk  &8$k $k ,9$^^k  '$ VALIDATE.PY;1RRNMvalidate.pyPX$TFk  '$k $k ,9$tt~~k  ' $VALIDATE.PYC;1RRNMvalidate.pycPX$TFk  ' $k $k ,9$~~k  '$VALIDATE.PYO;1RRNMvalidate.pyoPX$TFk  '$k $k ,9$fk :$RRPX$AATFk :$k  $k :$fk  $RRPX$AATFk  $k  $k  $HHk :$C2600_DU.BIN;1RRNMc2600-dummyrom.123_4.binPX$TFk :$k $k :$ER TRRIP_1991ATHE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICSPLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR CONTACT INFORMATION.#!/bin/sh ln -s /mnt/.plug-in/dynagen/usr/bin/configobj.py /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/configobj.pyc /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/configobj.pyo /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/configspec /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/console.py /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/console.pyc /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/console.pyo /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/dynagen /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/dynagen.ini /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/dynamips /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/dynamips_lib.py /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/dynamips_lib.pyc /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/dynamips_lib.pyo /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/validate.py /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/validate.pyc /home/cell/bin ln -s /mnt/.plug-in/dynagen/usr/bin/validate.pyo /home/cell/bin ln -s /mnt/.plug-in/dynagen/ios/c2600-dummyrom.123_4.bin /home/cell/ios # configobj.py # A config file reader/writer that supports nested sections in config files. # Copyright (C) 2005-2006 Michael Foord, Nicola Larosa # E-mail: fuzzyman AT voidspace DOT org DOT uk # nico AT tekNico DOT net # ConfigObj 4 # http://www.voidspace.org.uk/python/configobj.html # Released subject to the BSD License # Please see http://www.voidspace.org.uk/python/license.shtml # Scripts maintained at http://www.voidspace.org.uk/python/index.shtml # For information about bugfixes, updates and support, please join the # ConfigObj mailing list: # http://lists.sourceforge.net/lists/listinfo/configobj-develop # Comments, suggestions and bug reports welcome. from __future__ import generators """ >>> z = ConfigObj() >>> z['a'] = 'a' >>> z['sect'] = { ... 'subsect': { ... 'a': 'fish', ... 'b': 'wobble', ... }, ... 'member': 'value', ... } >>> x = ConfigObj(z.write()) >>> z == x 1 """ import sys INTP_VER = sys.version_info[:2] if INTP_VER < (2, 2): raise RuntimeError("Python v.2.2 or later needed") import os, re from types import StringTypes from warnings import warn from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE # A dictionary mapping BOM to # the encoding to decode with, and what to set the # encoding attribute to. BOMS = { BOM_UTF8: ('utf_8', None), BOM_UTF16_BE: ('utf16_be', 'utf_16'), BOM_UTF16_LE: ('utf16_le', 'utf_16'), BOM_UTF16: ('utf_16', 'utf_16'), } # All legal variants of the BOM codecs. # TODO: the list of aliases is not meant to be exhaustive, is there a # better way ? BOM_LIST = { 'utf_16': 'utf_16', 'u16': 'utf_16', 'utf16': 'utf_16', 'utf-16': 'utf_16', 'utf16_be': 'utf16_be', 'utf_16_be': 'utf16_be', 'utf-16be': 'utf16_be', 'utf16_le': 'utf16_le', 'utf_16_le': 'utf16_le', 'utf-16le': 'utf16_le', 'utf_8': 'utf_8', 'u8': 'utf_8', 'utf': 'utf_8', 'utf8': 'utf_8', 'utf-8': 'utf_8', } # Map of encodings to the BOM to write. BOM_SET = { 'utf_8': BOM_UTF8, 'utf_16': BOM_UTF16, 'utf16_be': BOM_UTF16_BE, 'utf16_le': BOM_UTF16_LE, None: BOM_UTF8 } try: from validate import VdtMissingValue except ImportError: VdtMissingValue = None try: enumerate except NameError: def enumerate(obj): """enumerate for Python 2.2.""" i = -1 for item in obj: i += 1 yield i, item try: True, False except NameError: True, False = 1, 0 __version__ = '4.2.0' __revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $' __docformat__ = "restructuredtext en" # NOTE: Does it make sense to have the following in __all__ ? # NOTE: DEFAULT_INDENT_TYPE, NUM_INDENT_SPACES, MAX_INTERPOL_DEPTH # NOTE: If used via ``from configobj import...`` # NOTE: They are effectively read only __all__ = ( '__version__', 'DEFAULT_INDENT_TYPE', 'NUM_INDENT_SPACES', 'MAX_INTERPOL_DEPTH', 'ConfigObjError', 'NestingError', 'ParseError', 'DuplicateError', 'ConfigspecError', 'ConfigObj', 'SimpleVal', 'InterpolationError', 'InterpolationDepthError', 'MissingInterpolationOption', 'RepeatSectionError', '__docformat__', 'flatten_errors', ) DEFAULT_INDENT_TYPE = ' ' NUM_INDENT_SPACES = 4 MAX_INTERPOL_DEPTH = 10 OPTION_DEFAULTS = { 'interpolation': True, 'raise_errors': False, 'list_values': True, 'create_empty': False, 'file_error': False, 'configspec': None, 'stringify': True, # option may be set to one of ('', ' ', '\t') 'indent_type': None, 'encoding': None, 'default_encoding': None, } class ConfigObjError(SyntaxError): """ This is the base class for all errors that ConfigObj raises. It is a subclass of SyntaxError. >>> raise ConfigObjError Traceback (most recent call last): ConfigObjError """ def __init__(self, message='', line_number=None, line=''): self.line = line self.line_number = line_number self.message = message SyntaxError.__init__(self, message) class NestingError(ConfigObjError): """ This error indicates a level of nesting that doesn't match. >>> raise NestingError Traceback (most recent call last): NestingError """ class ParseError(ConfigObjError): """ This error indicates that a line is badly written. It is neither a valid ``key = value`` line, nor a valid section marker line. >>> raise ParseError Traceback (most recent call last): ParseError """ class DuplicateError(ConfigObjError): """ The keyword or section specified already exists. >>> raise DuplicateError Traceback (most recent call last): DuplicateError """ class ConfigspecError(ConfigObjError): """ An error occured whilst parsing a configspec. >>> raise ConfigspecError Traceback (most recent call last): ConfigspecError """ class InterpolationError(ConfigObjError): """Base class for the two interpolation errors.""" class InterpolationDepthError(InterpolationError): """Maximum interpolation depth exceeded in string interpolation.""" def __init__(self, option): """ >>> raise InterpolationDepthError('yoda') Traceback (most recent call last): InterpolationDepthError: max interpolation depth exceeded in value "yoda". """ InterpolationError.__init__( self, 'max interpolation depth exceeded in value "%s".' % option) class RepeatSectionError(ConfigObjError): """ This error indicates additional sections in a section with a ``__many__`` (repeated) section. >>> raise RepeatSectionError Traceback (most recent call last): RepeatSectionError """ class MissingInterpolationOption(InterpolationError): """A value specified for interpolation was missing.""" def __init__(self, option): """ >>> raise MissingInterpolationOption('yoda') Traceback (most recent call last): MissingInterpolationOption: missing option "yoda" in interpolation. """ InterpolationError.__init__( self, 'missing option "%s" in interpolation.' % option) class Section(dict): """ A dictionary-like object that represents a section in a config file. It does string interpolation if the 'interpolate' attribute of the 'main' object is set to True. Interpolation is tried first from the 'DEFAULT' section of this object, next from the 'DEFAULT' section of the parent, lastly the main object. A Section will behave like an ordered dictionary - following the order of the ``scalars`` and ``sections`` attributes. You can use this to change the order of members. Iteration follows the order: scalars, then sections. """ _KEYCRE = re.compile(r"%\(([^)]*)\)s|.") def __init__(self, parent, depth, main, indict=None, name=None): """ * parent is the section above * depth is the depth level of this section * main is the main ConfigObj * indict is a dictionary to initialise the section with """ if indict is None: indict = {} dict.__init__(self) # used for nesting level *and* interpolation self.parent = parent # used for the interpolation attribute self.main = main # level of nesting depth of this Section self.depth = depth # the sequence of scalar values in this Section self.scalars = [] # the sequence of sections in this Section self.sections = [] # purely for information self.name = name # for comments :-) self.comments = {} self.inline_comments = {} # for the configspec self.configspec = {} # for defaults self.defaults = [] # # we do this explicitly so that __setitem__ is used properly # (rather than just passing to ``dict.__init__``) for entry in indict: self[entry] = indict[entry] def _interpolate(self, value): """Nicked from ConfigParser.""" depth = MAX_INTERPOL_DEPTH # loop through this until it's done while depth: depth -= 1 if value.find("%(") != -1: value = self._KEYCRE.sub(self._interpolation_replace, value) else: break else: raise InterpolationDepthError(value) return value def _interpolation_replace(self, match): """ """ s = match.group(1) if s is None: return match.group() else: # switch off interpolation before we try and fetch anything ! self.main.interpolation = False # try the 'DEFAULT' member of *this section* first val = self.get('DEFAULT', {}).get(s) # try the 'DEFAULT' member of the *parent section* next if val is None: val = self.parent.get('DEFAULT', {}).get(s) # last, try the 'DEFAULT' member of the *main section* if val is None: val = self.main.get('DEFAULT', {}).get(s) self.main.interpolation = True if val is None: raise MissingInterpolationOption(s) return val def __getitem__(self, key): """Fetch the item and do string interpolation.""" val = dict.__getitem__(self, key) if self.main.interpolation and isinstance(val, StringTypes): return self._interpolate(val) return val def __setitem__(self, key, value): """ Correctly set a value. Making dictionary values Section instances. (We have to special case 'Section' instances - which are also dicts) Keys must be strings. Values need only be strings (or lists of strings) if ``main.stringify`` is set. """ if not isinstance(key, StringTypes): raise ValueError, 'The key "%s" is not a string.' % key # add the comment if not self.comments.has_key(key): self.comments[key] = [] self.inline_comments[key] = '' # remove the entry from defaults if key in self.defaults: self.defaults.remove(key) # if isinstance(value, Section): if not self.has_key(key): self.sections.append(key) dict.__setitem__(self, key, value) elif isinstance(value, dict): # First create the new depth level, # then create the section if not self.has_key(key): self.sections.append(key) new_depth = self.depth + 1 dict.__setitem__( self, key, Section( self, new_depth, self.main, indict=value, name=key)) else: if not self.has_key(key): self.scalars.append(key) if not self.main.stringify: if isinstance(value, StringTypes): pass elif isinstance(value, (list, tuple)): for entry in value: if not isinstance(entry, StringTypes): raise TypeError, ( 'Value is not a string "%s".' % entry) else: raise TypeError, 'Value is not a string "%s".' % value dict.__setitem__(self, key, value) def __delitem__(self, key): """Remove items from the sequence when deleting.""" dict. __delitem__(self, key) if key in self.scalars: self.scalars.remove(key) else: self.sections.remove(key) del self.comments[key] del self.inline_comments[key] def get(self, key, default=None): """A version of ``get`` that doesn't bypass string interpolation.""" try: return self[key] except KeyError: return default def update(self, indict): """ A version of update that uses our ``__setitem__``. """ for entry in indict: self[entry] = indict[entry] def pop(self, key, *args): """ """ val = dict.pop(self, key, *args) if key in self.scalars: del self.comments[key] del self.inline_comments[key] self.scalars.remove(key) elif key in self.sections: del self.comments[key] del self.inline_comments[key] self.sections.remove(key) if self.main.interpolation and isinstance(val, StringTypes): return self._interpolate(val) return val def popitem(self): """Pops the first (key,val)""" sequence = (self.scalars + self.sections) if not sequence: raise KeyError, ": 'popitem(): dictionary is empty'" key = sequence[0] val = self[key] del self[key] return key, val def clear(self): """ A version of clear that also affects scalars/sections Also clears comments and configspec. Leaves other attributes alone : depth/main/parent are not affected """ dict.clear(self) self.scalars = [] self.sections = [] self.comments = {} self.inline_comments = {} self.configspec = {} def setdefault(self, key, default=None): """A version of setdefault that sets sequence if appropriate.""" try: return self[key] except KeyError: self[key] = default return self[key] def items(self): """ """ return zip((self.scalars + self.sections), self.values()) def keys(self): """ """ return (self.scalars + self.sections) def values(self): """ """ return [self[key] for key in (self.scalars + self.sections)] def iteritems(self): """ """ return iter(self.items()) def iterkeys(self): """ """ return iter((self.scalars + self.sections)) __iter__ = iterkeys def itervalues(self): """ """ return iter(self.values()) def __repr__(self): return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key]))) for key in (self.scalars + self.sections)]) __str__ = __repr__ # Extra methods - not in a normal dictionary def dict(self): """ Return a deepcopy of self as a dictionary. All members that are ``Section`` instances are recursively turned to ordinary dictionaries - by calling their ``dict`` method. >>> n = a.dict() >>> n == a 1 >>> n is a 0 """ newdict = {} for entry in self: this_entry = self[entry] if isinstance(this_entry, Section): this_entry = this_entry.dict() elif isinstance(this_entry, (list, tuple)): # create a copy rather than a reference this_entry = list(this_entry) newdict[entry] = this_entry return newdict def merge(self, indict): """ A recursive update - useful for merging config files. >>> a = '''[section1] ... option1 = True ... [[subsection]] ... more_options = False ... # end of file'''.splitlines() >>> b = '''# File is user.ini ... [section1] ... option1 = False ... # end of file'''.splitlines() >>> c1 = ConfigObj(b) >>> c2 = ConfigObj(a) >>> c2.merge(c1) >>> c2 {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}} """ for key, val in indict.items(): if (key in self and isinstance(self[key], dict) and isinstance(val, dict)): self[key].merge(val) else: self[key] = val def rename(self, oldkey, newkey): """ Change a keyname to another, without changing position in sequence. Implemented so that transformations can be made on keys, as well as on values. (used by encode and decode) Also renames comments. """ if oldkey in self.scalars: the_list = self.scalars elif oldkey in self.sections: the_list = self.sections else: raise KeyError, 'Key "%s" not found.' % oldkey pos = the_list.index(oldkey) # val = self[oldkey] dict.__delitem__(self, oldkey) dict.__setitem__(self, newkey, val) the_list.remove(oldkey) the_list.insert(pos, newkey) comm = self.comments[oldkey] inline_comment = self.inline_comments[oldkey] del self.comments[oldkey] del self.inline_comments[oldkey] self.comments[newkey] = comm self.inline_comments[newkey] = inline_comment def walk(self, function, raise_errors=True, call_on_sections=False, **keywargs): """ Walk every member and call a function on the keyword and value. Return a dictionary of the return values If the function raises an exception, raise the errror unless ``raise_errors=False``, in which case set the return value to ``False``. Any unrecognised keyword arguments you pass to walk, will be pased on to the function you pass in. Note: if ``call_on_sections`` is ``True`` then - on encountering a subsection, *first* the function is called for the *whole* subsection, and then recurses into it's members. This means your function must be able to handle strings, dictionaries and lists. This allows you to change the key of subsections as well as for ordinary members. The return value when called on the whole subsection has to be discarded. See the encode and decode methods for examples, including functions. .. caution:: You can use ``walk`` to transform the names of members of a section but you mustn't add or delete members. >>> config = '''[XXXXsection] ... XXXXkey = XXXXvalue'''.splitlines() >>> cfg = ConfigObj(config) >>> cfg {'XXXXsection': {'XXXXkey': 'XXXXvalue'}} >>> def transform(section, key): ... val = section[key] ... newkey = key.replace('XXXX', 'CLIENT1') ... section.rename(key, newkey) ... if isinstance(val, (tuple, list, dict)): ... pass ... else: ... val = val.replace('XXXX', 'CLIENT1') ... section[newkey] = val >>> cfg.walk(transform, call_on_sections=True) {'CLIENT1section': {'CLIENT1key': None}} >>> cfg {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}} """ out = {} # scalars first for i in range(len(self.scalars)): entry = self.scalars[i] try: val = function(self, entry, **keywargs) # bound again in case name has changed entry = self.scalars[i] out[entry] = val except Exception: if raise_errors: raise else: entry = self.scalars[i] out[entry] = False # then sections for i in range(len(self.sections)): entry = self.sections[i] if call_on_sections: try: function(self, entry, **keywargs) except Exception: if raise_errors: raise else: entry = self.sections[i] out[entry] = False # bound again in case name has changed entry = self.sections[i] # previous result is discarded out[entry] = self[entry].walk( function, raise_errors=raise_errors, call_on_sections=call_on_sections, **keywargs) return out def decode(self, encoding): """ Decode all strings and values to unicode, using the specified encoding. Works with subsections and list values. Uses the ``walk`` method. Testing ``encode`` and ``decode``. >>> m = ConfigObj(a) >>> m.decode('ascii') >>> def testuni(val): ... for entry in val: ... if not isinstance(entry, unicode): ... print >> sys.stderr, type(entry) ... raise AssertionError, 'decode failed.' ... if isinstance(val[entry], dict): ... testuni(val[entry]) ... elif not isinstance(val[entry], unicode): ... raise AssertionError, 'decode failed.' >>> testuni(m) >>> m.encode('ascii') >>> a == m 1 """ def decode(section, key, encoding=encoding): """ """ val = section[key] if isinstance(val, (list, tuple)): newval = [] for entry in val: newval.append(entry.decode(encoding)) elif isinstance(val, dict): newval = val else: newval = val.decode(encoding) newkey = key.decode(encoding) section.rename(key, newkey) section[newkey] = newval # using ``call_on_sections`` allows us to modify section names self.walk(decode, call_on_sections=True) def encode(self, encoding): """ Encode all strings and values from unicode, using the specified encoding. Works with subsections and list values. Uses the ``walk`` method. """ def encode(section, key, encoding=encoding): """ """ val = section[key] if isinstance(val, (list, tuple)): newval = [] for entry in val: newval.append(entry.encode(encoding)) elif isinstance(val, dict): newval = val else: newval = val.encode(encoding) newkey = key.encode(encoding) section.rename(key, newkey) section[newkey] = newval self.walk(encode, call_on_sections=True) def istrue(self, key): """A deprecated version of ``as_bool``.""" warn('use of ``istrue`` is deprecated. Use ``as_bool`` method ' 'instead.', DeprecationWarning) return self.as_bool(key) def as_bool(self, key): """ Accepts a key as input. The corresponding value must be a string or the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to retain compatibility with Python 2.2. If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns ``True``. If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns ``False``. ``as_bool`` is not case sensitive. Any other input will raise a ``ValueError``. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_bool('a') Traceback (most recent call last): ValueError: Value "fish" is neither True nor False >>> a['b'] = 'True' >>> a.as_bool('b') 1 >>> a['b'] = 'off' >>> a.as_bool('b') 0 """ val = self[key] if val == True: return True elif val == False: return False else: try: if not isinstance(val, StringTypes): raise KeyError else: return self.main._bools[val.lower()] except KeyError: raise ValueError('Value "%s" is neither True nor False' % val) def as_int(self, key): """ A convenience method which coerces the specified value to an integer. If the value is an invalid literal for ``int``, a ``ValueError`` will be raised. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_int('a') Traceback (most recent call last): ValueError: invalid literal for int(): fish >>> a['b'] = '1' >>> a.as_int('b') 1 >>> a['b'] = '3.2' >>> a.as_int('b') Traceback (most recent call last): ValueError: invalid literal for int(): 3.2 """ return int(self[key]) def as_float(self, key): """ A convenience method which coerces the specified value to a float. If the value is an invalid literal for ``float``, a ``ValueError`` will be raised. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_float('a') Traceback (most recent call last): ValueError: invalid literal for float(): fish >>> a['b'] = '1' >>> a.as_float('b') 1.0 >>> a['b'] = '3.2' >>> a.as_float('b') 3.2000000000000002 """ return float(self[key]) class ConfigObj(Section): """ An object to read, create, and write config files. Testing with duplicate keys and sections. >>> c = ''' ... [hello] ... member = value ... [hello again] ... member = value ... [ "hello" ] ... member = value ... ''' >>> ConfigObj(c.split('\\n'), raise_errors = True) Traceback (most recent call last): DuplicateError: Duplicate section name at line 5. >>> d = ''' ... [hello] ... member = value ... [hello again] ... member1 = value ... member2 = value ... 'member1' = value ... [ "and again" ] ... member = value ... ''' >>> ConfigObj(d.split('\\n'), raise_errors = True) Traceback (most recent call last): DuplicateError: Duplicate keyword name at line 6. """ _keyword = re.compile(r'''^ # line start (\s*) # indentation ( # keyword (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'"=].*?) # no quotes ) \s*=\s* # divider (.*) # value (including list values and comments) $ # line end ''', re.VERBOSE) _sectionmarker = re.compile(r'''^ (\s*) # 1: indentation ((?:\[\s*)+) # 2: section marker open ( # 3: section name open (?:"\s*\S.*?\s*")| # at least one non-space with double quotes (?:'\s*\S.*?\s*')| # at least one non-space with single quotes (?:[^'"\s].*?) # at least one non-space unquoted ) # section name close ((?:\s*\])+) # 4: section marker close \s*(\#.*)? # 5: optional comment $''', re.VERBOSE) # this regexp pulls list values out as a single string # or single values and comments _valueexp = re.compile(r'''^ (?: (?: ( (?: (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#][^,\#]*?) # unquoted ) \s*,\s* # comma )* # match all list items ending in a comma (if any) ) ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#\s][^,]*?) # unquoted )? # last item in a list - or string value )| (,) # alternatively a single comma - empty list ) \s*(\#.*)? # optional comment $''', re.VERBOSE) # use findall to get the members of a list value _listvalueexp = re.compile(r''' ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#].*?) # unquoted ) \s*,\s* # comma ''', re.VERBOSE) # this regexp is used for the value # when lists are switched off _nolistvalue = re.compile(r'''^ ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'"\#].*?) # unquoted ) \s*(\#.*)? # optional comment $''', re.VERBOSE) # regexes for finding triple quoted values on one line _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$") _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$') _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$") _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$') _triple_quote = { "'''": (_single_line_single, _multi_line_single), '"""': (_single_line_double, _multi_line_double), } # Used by the ``istrue`` Section method _bools = { 'yes': True, 'no': False, 'on': True, 'off': False, '1': True, '0': False, 'true': True, 'false': False, } def __init__(self, infile=None, options=None, **kwargs): """ Parse or create a config file object. ``ConfigObj(infile=None, options=None, **kwargs)`` """ if infile is None: infile = [] if options is None: options = {} # keyword arguments take precedence over an options dictionary options.update(kwargs) # init the superclass Section.__init__(self, self, 0, self) # defaults = OPTION_DEFAULTS.copy() for entry in options.keys(): if entry not in defaults.keys(): raise TypeError, 'Unrecognised option "%s".' % entry # TODO: check the values too. # # Add any explicit options to the defaults defaults.update(options) # # initialise a few variables self.filename = None self._errors = [] self.raise_errors = defaults['raise_errors'] self.interpolation = defaults['interpolation'] self.list_values = defaults['list_values'] self.create_empty = defaults['create_empty'] self.file_error = defaults['file_error'] self.stringify = defaults['stringify'] self.indent_type = defaults['indent_type'] self.encoding = defaults['encoding'] self.default_encoding = defaults['default_encoding'] self.BOM = False self.newlines = None # self.initial_comment = [] self.final_comment = [] # if isinstance(infile, StringTypes): self.filename = infile if os.path.isfile(infile): infile = open(infile).read() or [] elif self.file_error: # raise an error if the file doesn't exist raise IOError, 'Config file not found: "%s".' % self.filename else: # file doesn't already exist if self.create_empty: # this is a good test that the filename specified # isn't impossible - like on a non existent device h = open(infile, 'w') h.write('') h.close() infile = [] elif isinstance(infile, (list, tuple)): infile = list(infile) elif isinstance(infile, dict): # initialise self # the Section class handles creating subsections if isinstance(infile, ConfigObj): # get a copy of our ConfigObj infile = infile.dict() for entry in infile: self[entry] = infile[entry] del self._errors if defaults['configspec'] is not None: self._handle_configspec(defaults['configspec']) else: self.configspec = None return elif hasattr(infile, 'read'): # This supports file like objects infile = infile.read() or [] # needs splitting into lines - but needs doing *after* decoding # in case it's not an 8 bit encoding else: raise TypeError, ('infile must be a filename,' ' file like object, or list of lines.') # if infile: # don't do it for the empty ConfigObj infile = self._handle_bom(infile) # infile is now *always* a list # # Set the newlines attribute (first line ending it finds) # and strip trailing '\n' or '\r' from lines for line in infile: if (not line) or (line[-1] not in '\r\n'): continue for end in ('\r\n', '\n', '\r'): if line.endswith(end): self.newlines = end break break infile = [line.rstrip('\r\n') for line in infile] # self._parse(infile) # if we had any errors, now is the time to raise them if self._errors: error = ConfigObjError("Parsing failed.") # set the errors attribute; it's a list of tuples: # (error_type, message, line_number) error.errors = self._errors # set the config attribute error.config = self raise error # delete private attributes del self._errors # if defaults['configspec'] is None: self.configspec = None else: self._handle_configspec(defaults['configspec']) def _handle_bom(self, infile): """ Handle any BOM, and decode if necessary. If an encoding is specified, that *must* be used - but the BOM should still be removed (and the BOM attribute set). (If the encoding is wrongly specified, then a BOM for an alternative encoding won't be discovered or removed.) If an encoding is not specified, UTF8 or UTF16 BOM will be detected and removed. The BOM attribute will be set. UTF16 will be decoded to unicode. NOTE: This method must not be called with an empty ``infile``. Specifying the *wrong* encoding is likely to cause a ``UnicodeDecodeError``. ``infile`` must always be returned as a list of lines, but may be passed in as a single string. """ if ((self.encoding is not None) and (self.encoding.lower() not in BOM_LIST)): # No need to check for a BOM # encoding specified doesn't have one # just decode return self._decode(infile, self.encoding) # if isinstance(infile, (list, tuple)): line = infile[0] else: line = infile if self.encoding is not None: # encoding explicitly supplied # And it could have an associated BOM # TODO: if encoding is just UTF16 - we ought to check for both # TODO: big endian and little endian versions. enc = BOM_LIST[self.encoding.lower()] if enc == 'utf_16': # For UTF16 we try big endian and little endian for BOM, (encoding, final_encoding) in BOMS.items(): if not final_encoding: # skip UTF8 continue if infile.startswith(BOM): ### BOM discovered ##self.BOM = True # Don't need to remove BOM return self._decode(infile, encoding) # # If we get this far, will *probably* raise a DecodeError # As it doesn't appear to start with a BOM return self._decode(infile, self.encoding) # # Must be UTF8 BOM = BOM_SET[enc] if not line.startswith(BOM): return self._decode(infile, self.encoding) # newline = line[len(BOM):] # # BOM removed if isinstance(infile, (list, tuple)): infile[0] = newline else: infile = newline self.BOM = True return self._decode(infile, self.encoding) # # No encoding specified - so we need to check for UTF8/UTF16 for BOM, (encoding, final_encoding) in BOMS.items(): if not line.startswith(BOM): continue else: # BOM discovered self.encoding = final_encoding if not final_encoding: self.BOM = True # UTF8 # remove BOM newline = line[len(BOM):] if isinstance(infile, (list, tuple)): infile[0] = newline else: infile = newline # UTF8 - don't decode if isinstance(infile, StringTypes): return infile.splitlines(True) else: return infile # UTF16 - have to decode return self._decode(infile, encoding) # # No BOM discovered and no encoding specified, just return if isinstance(infile, StringTypes): # infile read from a file will be a single string return infile.splitlines(True) else: return infile def _a_to_u(self, string): """Decode ascii strings to unicode if a self.encoding is specified.""" if not self.encoding: return string else: return string.decode('ascii') def _decode(self, infile, encoding): """ Decode infile to unicode. Using the specified encoding. if is a string, it also needs converting to a list. """ if isinstance(infile, StringTypes): # can't be unicode # NOTE: Could raise a ``UnicodeDecodeError`` return infile.decode(encoding).splitlines(True) for i, line in enumerate(infile): if not isinstance(line, unicode): # NOTE: The isinstance test here handles mixed lists of unicode/string # NOTE: But the decode will break on any non-string values # NOTE: Or could raise a ``UnicodeDecodeError`` infile[i] = line.decode(encoding) return infile def _decode_element(self, line): """Decode element to unicode if necessary.""" if not self.encoding: return line if isinstance(line, str) and self.default_encoding: return line.decode(self.default_encoding) return line def _str(self, value): """ Used by ``stringify`` within validate, to turn non-string values into strings. """ if not isinstance(value, StringTypes): return str(value) else: return value def _parse(self, infile): """ Actually parse the config file Testing Interpolation >>> c = ConfigObj() >>> c['DEFAULT'] = { ... 'b': 'goodbye', ... 'userdir': 'c:\\\\home', ... 'c': '%(d)s', ... 'd': '%(c)s' ... } >>> c['section'] = { ... 'a': '%(datadir)s\\\\some path\\\\file.py', ... 'b': '%(userdir)s\\\\some path\\\\file.py', ... 'c': 'Yo %(a)s', ... 'd': '%(not_here)s', ... 'e': '%(c)s', ... } >>> c['section']['DEFAULT'] = { ... 'datadir': 'c:\\\\silly_test', ... 'a': 'hello - %(b)s', ... } >>> c['section']['a'] == 'c:\\\\silly_test\\\\some path\\\\file.py' 1 >>> c['section']['b'] == 'c:\\\\home\\\\some path\\\\file.py' 1 >>> c['section']['c'] == 'Yo hello - goodbye' 1 Switching Interpolation Off >>> c.interpolation = False >>> c['section']['a'] == '%(datadir)s\\\\some path\\\\file.py' 1 >>> c['section']['b'] == '%(userdir)s\\\\some path\\\\file.py' 1 >>> c['section']['c'] == 'Yo %(a)s' 1 Testing the interpolation errors. >>> c.interpolation = True >>> c['section']['d'] Traceback (most recent call last): MissingInterpolationOption: missing option "not_here" in interpolation. >>> c['section']['e'] Traceback (most recent call last): InterpolationDepthError: max interpolation depth exceeded in value "%(c)s". Testing our quoting. >>> i._quote('\"""\'\'\'') Traceback (most recent call last): SyntaxError: EOF while scanning triple-quoted string >>> try: ... i._quote('\\n', multiline=False) ... except ConfigObjError, e: ... e.msg 'Value "\\n" cannot be safely quoted.' >>> k._quote(' "\' ', multiline=False) Traceback (most recent call last): SyntaxError: EOL while scanning single-quoted string Testing with "stringify" off. >>> c.stringify = False >>> c['test'] = 1 Traceback (most recent call last): TypeError: Value is not a string "1". """ comment_list = [] done_start = False this_section = self maxline = len(infile) - 1 cur_index = -1 reset_comment = False while cur_index < maxline: if reset_comment: comment_list = [] cur_index += 1 line = infile[cur_index] sline = line.strip() # do we have anything on the line ? if not sline or sline.startswith('#'): reset_comment = False comment_list.append(line) continue if not done_start: # preserve initial comment self.initial_comment = comment_list comment_list = [] done_start = True reset_comment = True # first we check if it's a section marker mat = self._sectionmarker.match(line) ## print >> sys.stderr, sline, mat if mat is not None: # is a section line (indent, sect_open, sect_name, sect_close, comment) = ( mat.groups()) if indent and (self.indent_type is None): self.indent_type = indent[0] cur_depth = sect_open.count('[') if cur_depth != sect_close.count(']'): self._handle_error( "Cannot compute the section depth at line %s.", NestingError, infile, cur_index) continue if cur_depth < this_section.depth: # the new section is dropping back to a previous level try: parent = self._match_depth( this_section, cur_depth).parent except SyntaxError: self._handle_error( "Cannot compute nesting level at line %s.", NestingError, infile, cur_index) continue elif cur_depth == this_section.depth: # the new section is a sibling of the current section parent = this_section.parent elif cur_depth == this_section.depth + 1: # the new section is a child the current section parent = this_section else: self._handle_error( "Section too nested at line %s.", NestingError, infile, cur_index) # sect_name = self._unquote(sect_name) if parent.has_key(sect_name): ## print >> sys.stderr, sect_name self._handle_error( 'Duplicate section name at line %s.', DuplicateError, infile, cur_index) continue # create the new section this_section = Section( parent, cur_depth, self, name=sect_name) parent[sect_name] = this_section parent.inline_comments[sect_name] = comment parent.comments[sect_name] = comment_list ## print >> sys.stderr, parent[sect_name] is this_section continue # # it's not a section marker, # so it should be a valid ``key = value`` line mat = self._keyword.match(line) ## print >> sys.stderr, sline, mat if mat is not None: # is a keyword value # value will include any inline comment (indent, key, value) = mat.groups() if indent and (self.indent_type is None): self.indent_type = indent[0] # check for a multiline value if value[:3] in ['"""', "'''"]: try: (value, comment, cur_index) = self._multiline( value, infile, cur_index, maxline) except SyntaxError: self._handle_error( 'Parse error in value at line %s.', ParseError, infile, cur_index) continue else: # extract comment and lists try: (value, comment) = self._handle_value(value) except SyntaxError: self._handle_error( 'Parse error in value at line %s.', ParseError, infile, cur_index) continue # ## print >> sys.stderr, sline key = self._unquote(key) if this_section.has_key(key): self._handle_error( 'Duplicate keyword name at line %s.', DuplicateError, infile, cur_index) continue # add the key ## print >> sys.stderr, this_section.name this_section[key] = value this_section.inline_comments[key] = comment this_section.comments[key] = comment_list ## print >> sys.stderr, key, this_section[key] ## if this_section.name is not None: ## print >> sys.stderr, this_section ## print >> sys.stderr, this_section.parent ## print >> sys.stderr, this_section.parent[this_section.name] continue # # it neither matched as a keyword # or a section marker self._handle_error( 'Invalid line at line "%s".', ParseError, infile, cur_index) if self.indent_type is None: # no indentation used, set the type accordingly self.indent_type = '' # preserve the final comment if not self and not self.initial_comment: self.initial_comment = comment_list else: self.final_comment = comment_list def _match_depth(self, sect, depth): """ Given a section and a depth level, walk back through the sections parents to see if the depth level matches a previous section. Return a reference to the right section, or raise a SyntaxError. """ while depth < sect.depth: if sect is sect.parent: # we've reached the top level already raise SyntaxError sect = sect.parent if sect.depth == depth: return sect # shouldn't get here raise SyntaxError def _handle_error(self, text, ErrorClass, infile, cur_index): """ Handle an error according to the error settings. Either raise the error or store it. The error will have occured at ``cur_index`` """ line = infile[cur_index] message = text % cur_index error = ErrorClass(message, cur_index, line) if self.raise_errors: # raise the error - parsing stops here raise error # store the error # reraise when parsing has finished self._errors.append(error) def _unquote(self, value): """Return an unquoted version of a value""" if (value[0] == value[-1]) and (value[0] in ('"', "'")): value = value[1:-1] return value def _quote(self, value, multiline=True): """ Return a safely quoted version of a value. Raise a ConfigObjError if the value cannot be safely quoted. If multiline is ``True`` (default) then use triple quotes if necessary. Don't quote values that don't need it. Recursively quote members of a list and return a comma joined list. Multiline is ``False`` for lists. Obey list syntax for empty and single member lists. If ``list_values=False`` then the value is only quoted if it contains a ``\n`` (is multiline). """ if isinstance(value, (list, tuple)): if not value: return ',' elif len(value) == 1: return self._quote(value[0], multiline=False) + ',' return ', '.join([self._quote(val, multiline=False) for val in value]) if not isinstance(value, StringTypes): if self.stringify: value = str(value) else: raise TypeError, 'Value "%s" is not a string.' % value squot = "'%s'" dquot = '"%s"' noquot = "%s" wspace_plus = ' \r\t\n\v\t\'"' tsquot = '"""%s"""' tdquot = "'''%s'''" if not value: return '""' if (not self.list_values and '\n' not in value) or not (multiline and ((("'" in value) and ('"' in value)) or ('\n' in value))): if not self.list_values: # we don't quote if ``list_values=False`` quot = noquot # for normal values either single or double quotes will do elif '\n' in value: # will only happen if multiline is off - e.g. '\n' in key raise ConfigObjError, ('Value "%s" cannot be safely quoted.' % value) elif ((value[0] not in wspace_plus) and (value[-1] not in wspace_plus) and (',' not in value)): quot = noquot else: if ("'" in value) and ('"' in value): raise ConfigObjError, ( 'Value "%s" cannot be safely quoted.' % value) elif '"' in value: quot = squot else: quot = dquot else: # if value has '\n' or "'" *and* '"', it will need triple quotes if (value.find('"""') != -1) and (value.find("'''") != -1): raise ConfigObjError, ( 'Value "%s" cannot be safely quoted.' % value) if value.find('"""') == -1: quot = tdquot else: quot = tsquot return quot % value def _handle_value(self, value): """ Given a value string, unquote, remove comment, handle lists. (including empty and single member lists) Testing list values. >>> testconfig3 = ''' ... a = , ... b = test, ... c = test1, test2 , test3 ... d = test1, test2, test3, ... ''' >>> d = ConfigObj(testconfig3.split('\\n'), raise_errors=True) >>> d['a'] == [] 1 >>> d['b'] == ['test'] 1 >>> d['c'] == ['test1', 'test2', 'test3'] 1 >>> d['d'] == ['test1', 'test2', 'test3'] 1 Testing with list values off. >>> e = ConfigObj( ... testconfig3.split('\\n'), ... raise_errors=True, ... list_values=False) >>> e['a'] == ',' 1 >>> e['b'] == 'test,' 1 >>> e['c'] == 'test1, test2 , test3' 1 >>> e['d'] == 'test1, test2, test3,' 1 Testing creating from a dictionary. >>> f = { ... 'key1': 'val1', ... 'key2': 'val2', ... 'section 1': { ... 'key1': 'val1', ... 'key2': 'val2', ... 'section 1b': { ... 'key1': 'val1', ... 'key2': 'val2', ... }, ... }, ... 'section 2': { ... 'key1': 'val1', ... 'key2': 'val2', ... 'section 2b': { ... 'key1': 'val1', ... 'key2': 'val2', ... }, ... }, ... 'key3': 'val3', ... } >>> g = ConfigObj(f) >>> f == g 1 Testing we correctly detect badly built list values (4 of them). >>> testconfig4 = ''' ... config = 3,4,, ... test = 3,,4 ... fish = ,, ... dummy = ,,hello, goodbye ... ''' >>> try: ... ConfigObj(testconfig4.split('\\n')) ... except ConfigObjError, e: ... len(e.errors) 4 Testing we correctly detect badly quoted values (4 of them). >>> testconfig5 = ''' ... config = "hello # comment ... test = 'goodbye ... fish = 'goodbye # comment ... dummy = "hello again ... ''' >>> try: ... ConfigObj(testconfig5.split('\\n')) ... except ConfigObjError, e: ... len(e.errors) 4 """ # do we look for lists in values ? if not self.list_values: mat = self._nolistvalue.match(value) if mat is None: raise SyntaxError (value, comment) = mat.groups() # NOTE: we don't unquote here return (value, comment) mat = self._valueexp.match(value) if mat is None: # the value is badly constructed, probably badly quoted, # or an invalid list raise SyntaxError (list_values, single, empty_list, comment) = mat.groups() if (list_values == '') and (single is None): # change this if you want to accept empty values raise SyntaxError # NOTE: note there is no error handling from here if the regex # is wrong: then incorrect values will slip through if empty_list is not None: # the single comma - meaning an empty list return ([], comment) if single is not None: single = self._unquote(single) if list_values == '': # not a list value return (single, comment) the_list = self._listvalueexp.findall(list_values) the_list = [self._unquote(val) for val in the_list] if single is not None: the_list += [single] return (the_list, comment) def _multiline(self, value, infile, cur_index, maxline): """ Extract the value, where we are in a multiline situation Testing multiline values. >>> i == { ... 'name4': ' another single line value ', ... 'multi section': { ... 'name4': '\\n Well, this is a\\n multiline ' ... 'value\\n ', ... 'name2': '\\n Well, this is a\\n multiline ' ... 'value\\n ', ... 'name3': '\\n Well, this is a\\n multiline ' ... 'value\\n ', ... 'name1': '\\n Well, this is a\\n multiline ' ... 'value\\n ', ... }, ... 'name2': ' another single line value ', ... 'name3': ' a single line value ', ... 'name1': ' a single line value ', ... } 1 """ quot = value[:3] newvalue = value[3:] single_line = self._triple_quote[quot][0] multi_line = self._triple_quote[quot][1] mat = single_line.match(value) if mat is not None: retval = list(mat.groups()) retval.append(cur_index) return retval elif newvalue.find(quot) != -1: # somehow the triple quote is missing raise SyntaxError # while cur_index < maxline: cur_index += 1 newvalue += '\n' line = infile[cur_index] if line.find(quot) == -1: newvalue += line else: # end of multiline, process it break else: # we've got to the end of the config, oops... raise SyntaxError mat = multi_line.match(line) if mat is None: # a badly formed line raise SyntaxError (value, comment) = mat.groups() return (newvalue + value, comment, cur_index) def _handle_configspec(self, configspec): """Parse the configspec.""" try: configspec = ConfigObj( configspec, raise_errors=True, file_error=True, list_values=False) except ConfigObjError, e: # FIXME: Should these errors have a reference # to the already parsed ConfigObj ? raise ConfigspecError('Parsing configspec failed: %s' % e) except IOError, e: raise IOError('Reading configspec failed: %s' % e) self._set_configspec_value(configspec, self) def _set_configspec_value(self, configspec, section): """Used to recursively set configspec values.""" if '__many__' in configspec.sections: section.configspec['__many__'] = configspec['__many__'] if len(configspec.sections) > 1: # FIXME: can we supply any useful information here ? raise RepeatSectionError for entry in configspec.scalars: section.configspec[entry] = configspec[entry] for entry in configspec.sections: if entry == '__many__': continue if not section.has_key(entry): section[entry] = {} self._set_configspec_value(configspec[entry], section[entry]) def _handle_repeat(self, section, configspec): """Dynamically assign configspec for repeated section.""" try: section_keys = configspec.sections scalar_keys = configspec.scalars except AttributeError: section_keys = [entry for entry in configspec if isinstance(configspec[entry], dict)] scalar_keys = [entry for entry in configspec if not isinstance(configspec[entry], dict)] if '__many__' in section_keys and len(section_keys) > 1: # FIXME: can we supply any useful information here ? raise RepeatSectionError scalars = {} sections = {} for entry in scalar_keys: val = configspec[entry] scalars[entry] = val for entry in section_keys: val = configspec[entry] if entry == '__many__': scalars[entry] = val continue sections[entry] = val # section.configspec = scalars for entry in sections: if not section.has_key(entry): section[entry] = {} self._handle_repeat(section[entry], sections[entry]) def _write_line(self, indent_string, entry, this_entry, comment): """Write an individual line, for the write method""" # NOTE: the calls to self._quote here handles non-StringType values. return '%s%s%s%s%s' % ( indent_string, self._decode_element(self._quote(entry, multiline=False)), self._a_to_u(' = '), self._decode_element(self._quote(this_entry)), self._decode_element(comment)) def _write_marker(self, indent_string, depth, entry, comment): """Write a section marker line""" return '%s%s%s%s%s' % ( indent_string, self._a_to_u('[' * depth), self._quote(self._decode_element(entry), multiline=False), self._a_to_u(']' * depth), self._decode_element(comment)) def _handle_comment(self, comment): """ Deal with a comment. >>> filename = a.filename >>> a.filename = None >>> values = a.write() >>> index = 0 >>> while index < 23: ... index += 1 ... line = values[index-1] ... assert line.endswith('# comment ' + str(index)) >>> a.filename = filename >>> start_comment = ['# Initial Comment', '', '#'] >>> end_comment = ['', '#', '# Final Comment'] >>> newconfig = start_comment + testconfig1.split('\\n') + end_comment >>> nc = ConfigObj(newconfig) >>> nc.initial_comment ['# Initial Comment', '', '#'] >>> nc.final_comment ['', '#', '# Final Comment'] >>> nc.initial_comment == start_comment 1 >>> nc.final_comment == end_comment 1 """ if not comment: return '' if self.indent_type == '\t': start = self._a_to_u('\t') else: start = self._a_to_u(' ' * NUM_INDENT_SPACES) if not comment.startswith('#'): start += _a_to_u('# ') return (start + comment) def _compute_indent_string(self, depth): """ Compute the indent string, according to current indent_type and depth """ if self.indent_type == '': # no indentation at all return '' if self.indent_type == '\t': return '\t' * depth if self.indent_type == ' ': return ' ' * NUM_INDENT_SPACES * depth raise SyntaxError # Public methods def write(self, outfile=None, section=None): """ Write the current ConfigObj as a file tekNico: FIXME: use StringIO instead of real files >>> filename = a.filename >>> a.filename = 'test.ini' >>> a.write() >>> a.filename = filename >>> a == ConfigObj('test.ini', raise_errors=True) 1 >>> os.remove('test.ini') >>> b.filename = 'test.ini' >>> b.write() >>> b == ConfigObj('test.ini', raise_errors=True) 1 >>> os.remove('test.ini') >>> i.filename = 'test.ini' >>> i.write() >>> i == ConfigObj('test.ini', raise_errors=True) 1 >>> os.remove('test.ini') >>> a = ConfigObj() >>> a['DEFAULT'] = {'a' : 'fish'} >>> a['a'] = '%(a)s' >>> a.write() ['a = %(a)s', '[DEFAULT]', 'a = fish'] """ if self.indent_type is None: # this can be true if initialised from a dictionary self.indent_type = DEFAULT_INDENT_TYPE # out = [] cs = self._a_to_u('#') csp = self._a_to_u('# ') if section is None: int_val = self.interpolation self.interpolation = False section = self for line in self.initial_comment: line = self._decode_element(line) stripped_line = line.strip() if stripped_line and not stripped_line.startswith(cs): line = csp + line out.append(line) # indent_string = self._a_to_u( self._compute_indent_string(section.depth)) for entry in (section.scalars + section.sections): if entry in section.defaults: # don't write out default values continue for comment_line in section.comments[entry]: comment_line = self._decode_element(comment_line.lstrip()) if comment_line and not comment_line.startswith(cs): comment_line = csp + comment_line out.append(indent_string + comment_line) this_entry = section[entry] comment = self._handle_comment(section.inline_comments[entry]) # if isinstance(this_entry, dict): # a section out.append(self._write_marker( indent_string, this_entry.depth, entry, comment)) out.extend(self.write(section=this_entry)) else: out.append(self._write_line( indent_string, entry, this_entry, comment)) # if section is self: for line in self.final_comment: line = self._decode_element(line) stripped_line = line.strip() if stripped_line and not stripped_line.startswith(cs): line = csp + line out.append(line) self.interpolation = int_val # if section is not self: return out # if (self.filename is None) and (outfile is None): # output a list of lines # might need to encode # NOTE: This will *screw* UTF16, each line will start with the BOM if self.encoding: out = [l.encode(self.encoding) for l in out] if (self.BOM and ((self.encoding is None) or (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))): # Add the UTF8 BOM if not out: out.append('') out[0] = BOM_UTF8 + out[0] return out # # Turn the list to a string, joined with correct newlines output = (self._a_to_u(self.newlines or os.linesep) ).join(out) if self.encoding: output = output.encode(self.encoding) if (self.BOM and ((self.encoding is None) or (BOM_LIST.get(self.encoding.lower()) == 'utf_8'))): # Add the UTF8 BOM output = BOM_UTF8 + output if outfile is not None: outfile.write(output) else: h = open(self.filename, 'w') h.write(output) h.close() def validate(self, validator, preserve_errors=False, section=None): """ Test the ConfigObj against a configspec. It uses the ``validator`` object from *validate.py*. To run ``validate`` on the current ConfigObj, call: :: test = config.validate(validator) (Normally having previously passed in the configspec when the ConfigObj was created - you can dynamically assign a dictionary of checks to the ``configspec`` attribute of a section though). It returns ``True`` if everything passes, or a dictionary of pass/fails (True/False). If every member of a subsection passes, it will just have the value ``True``. (It also returns ``False`` if all members fail). In addition, it converts the values from strings to their native types if their checks pass (and ``stringify`` is set). If ``preserve_errors`` is ``True`` (``False`` is default) then instead of a marking a fail with a ``False``, it will preserve the actual exception object. This can contain info about the reason for failure. For example the ``VdtValueTooSmallError`` indeicates that the value supplied was too small. If a value (or section) is missing it will still be marked as ``False``. You must have the validate module to use ``preserve_errors=True``. You can then use the ``flatten_errors`` function to turn your nested results dictionary into a flattened list of failures - useful for displaying meaningful error messages. >>> try: ... from validate import Validator ... except ImportError: ... print >> sys.stderr, 'Cannot import the Validator object, skipping the related tests' ... else: ... config = ''' ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [section] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [[sub section]] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... '''.split('\\n') ... configspec = ''' ... test1= integer(30,50) ... test2= string ... test3=integer ... test4=float(6.0) ... [section ] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... [[sub section]] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... '''.split('\\n') ... val = Validator() ... c1 = ConfigObj(config, configspec=configspec) ... test = c1.validate(val) ... test == { ... 'test1': True, ... 'test2': True, ... 'test3': True, ... 'test4': False, ... 'section': { ... 'test1': True, ... 'test2': True, ... 'test3': True, ... 'test4': False, ... 'sub section': { ... 'test1': True, ... 'test2': True, ... 'test3': True, ... 'test4': False, ... }, ... }, ... } 1 >>> val.check(c1.configspec['test4'], c1['test4']) Traceback (most recent call last): VdtValueTooSmallError: the value "5.0" is too small. >>> val_test_config = ''' ... key = 0 ... key2 = 1.1 ... [section] ... key = some text ... key2 = 1.1, 3.0, 17, 6.8 ... [[sub-section]] ... key = option1 ... key2 = True'''.split('\\n') >>> val_test_configspec = ''' ... key = integer ... key2 = float ... [section] ... key = string ... key2 = float_list(4) ... [[sub-section]] ... key = option(option1, option2) ... key2 = boolean'''.split('\\n') >>> val_test = ConfigObj(val_test_config, configspec=val_test_configspec) >>> val_test.validate(val) 1 >>> val_test['key'] = 'text not a digit' >>> val_res = val_test.validate(val) >>> val_res == {'key2': True, 'section': True, 'key': False} 1 >>> configspec = ''' ... test1=integer(30,50, default=40) ... test2=string(default="hello") ... test3=integer(default=3) ... test4=float(6.0, default=6.0) ... [section ] ... test1=integer(30,50, default=40) ... test2=string(default="hello") ... test3=integer(default=3) ... test4=float(6.0, default=6.0) ... [[sub section]] ... test1=integer(30,50, default=40) ... test2=string(default="hello") ... test3=integer(default=3) ... test4=float(6.0, default=6.0) ... '''.split('\\n') >>> default_test = ConfigObj(['test1=30'], configspec=configspec) >>> default_test {'test1': '30', 'section': {'sub section': {}}} >>> default_test.validate(val) 1 >>> default_test == { ... 'test1': 30, ... 'test2': 'hello', ... 'test3': 3, ... 'test4': 6.0, ... 'section': { ... 'test1': 40, ... 'test2': 'hello', ... 'test3': 3, ... 'test4': 6.0, ... 'sub section': { ... 'test1': 40, ... 'test3': 3, ... 'test2': 'hello', ... 'test4': 6.0, ... }, ... }, ... } 1 Now testing with repeated sections : BIG TEST >>> repeated_1 = ''' ... [dogs] ... [[__many__]] # spec for a dog ... fleas = boolean(default=True) ... tail = option(long, short, default=long) ... name = string(default=rover) ... [[[__many__]]] # spec for a puppy ... name = string(default="son of rover") ... age = float(default=0.0) ... [cats] ... [[__many__]] # spec for a cat ... fleas = boolean(default=True) ... tail = option(long, short, default=short) ... name = string(default=pussy) ... [[[__many__]]] # spec for a kitten ... name = string(default="son of pussy") ... age = float(default=0.0) ... '''.split('\\n') >>> repeated_2 = ''' ... [dogs] ... ... # blank dogs with puppies ... # should be filled in by the configspec ... [[dog1]] ... [[[puppy1]]] ... [[[puppy2]]] ... [[[puppy3]]] ... [[dog2]] ... [[[puppy1]]] ... [[[puppy2]]] ... [[[puppy3]]] ... [[dog3]] ... [[[puppy1]]] ... [[[puppy2]]] ... [[[puppy3]]] ... [cats] ... ... # blank cats with kittens ... # should be filled in by the configspec ... [[cat1]] ... [[[kitten1]]] ... [[[kitten2]]] ... [[[kitten3]]] ... [[cat2]] ... [[[kitten1]]] ... [[[kitten2]]] ... [[[kitten3]]] ... [[cat3]] ... [[[kitten1]]] ... [[[kitten2]]] ... [[[kitten3]]] ... '''.split('\\n') >>> repeated_3 = ''' ... [dogs] ... ... [[dog1]] ... [[dog2]] ... [[dog3]] ... [cats] ... ... [[cat1]] ... [[cat2]] ... [[cat3]] ... '''.split('\\n') >>> repeated_4 = ''' ... [__many__] ... ... name = string(default=Michael) ... age = float(default=0.0) ... sex = option(m, f, default=m) ... '''.split('\\n') >>> repeated_5 = ''' ... [cats] ... [[__many__]] ... fleas = boolean(default=True) ... tail = option(long, short, default=short) ... name = string(default=pussy) ... [[[description]]] ... height = float(default=3.3) ... weight = float(default=6) ... [[[[coat]]]] ... fur = option(black, grey, brown, "tortoise shell", default=black) ... condition = integer(0,10, default=5) ... '''.split('\\n') >>> from validate import Validator >>> val= Validator() >>> repeater = ConfigObj(repeated_2, configspec=repeated_1) >>> repeater.validate(val) 1 >>> repeater == { ... 'dogs': { ... 'dog1': { ... 'fleas': True, ... 'tail': 'long', ... 'name': 'rover', ... 'puppy1': {'name': 'son of rover', 'age': 0.0}, ... 'puppy2': {'name': 'son of rover', 'age': 0.0}, ... 'puppy3': {'name': 'son of rover', 'age': 0.0}, ... }, ... 'dog2': { ... 'fleas': True, ... 'tail': 'long', ... 'name': 'rover', ... 'puppy1': {'name': 'son of rover', 'age': 0.0}, ... 'puppy2': {'name': 'son of rover', 'age': 0.0}, ... 'puppy3': {'name': 'son of rover', 'age': 0.0}, ... }, ... 'dog3': { ... 'fleas': True, ... 'tail': 'long', ... 'name': 'rover', ... 'puppy1': {'name': 'son of rover', 'age': 0.0}, ... 'puppy2': {'name': 'son of rover', 'age': 0.0}, ... 'puppy3': {'name': 'son of rover', 'age': 0.0}, ... }, ... }, ... 'cats': { ... 'cat1': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'kitten1': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten2': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten3': {'name': 'son of pussy', 'age': 0.0}, ... }, ... 'cat2': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'kitten1': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten2': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten3': {'name': 'son of pussy', 'age': 0.0}, ... }, ... 'cat3': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'kitten1': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten2': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten3': {'name': 'son of pussy', 'age': 0.0}, ... }, ... }, ... } 1 >>> repeater = ConfigObj(repeated_3, configspec=repeated_1) >>> repeater.validate(val) 1 >>> repeater == { ... 'cats': { ... 'cat1': {'fleas': True, 'tail': 'short', 'name': 'pussy'}, ... 'cat2': {'fleas': True, 'tail': 'short', 'name': 'pussy'}, ... 'cat3': {'fleas': True, 'tail': 'short', 'name': 'pussy'}, ... }, ... 'dogs': { ... 'dog1': {'fleas': True, 'tail': 'long', 'name': 'rover'}, ... 'dog2': {'fleas': True, 'tail': 'long', 'name': 'rover'}, ... 'dog3': {'fleas': True, 'tail': 'long', 'name': 'rover'}, ... }, ... } 1 >>> repeater = ConfigObj(configspec=repeated_4) >>> repeater['Michael'] = {} >>> repeater.validate(val) 1 >>> repeater == { ... 'Michael': {'age': 0.0, 'name': 'Michael', 'sex': 'm'}, ... } 1 >>> repeater = ConfigObj(repeated_3, configspec=repeated_5) >>> repeater == { ... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}}, ... 'cats': {'cat1': {}, 'cat2': {}, 'cat3': {}}, ... } 1 >>> repeater.validate(val) 1 >>> repeater == { ... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}}, ... 'cats': { ... 'cat1': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'description': { ... 'weight': 6.0, ... 'height': 3.2999999999999998, ... 'coat': {'fur': 'black', 'condition': 5}, ... }, ... }, ... 'cat2': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'description': { ... 'weight': 6.0, ... 'height': 3.2999999999999998, ... 'coat': {'fur': 'black', 'condition': 5}, ... }, ... }, ... 'cat3': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'description': { ... 'weight': 6.0, ... 'height': 3.2999999999999998, ... 'coat': {'fur': 'black', 'condition': 5}, ... }, ... }, ... }, ... } 1 Test that interpolation is preserved for validated string values. Also check that interpolation works in configspecs. >>> t = ConfigObj() >>> t['DEFAULT'] = {} >>> t['DEFAULT']['test'] = 'a' >>> t['test'] = '%(test)s' >>> t['test'] 'a' >>> v = Validator() >>> t.configspec = {'test': 'string'} >>> t.validate(v) 1 >>> t.interpolation = False >>> t {'test': '%(test)s', 'DEFAULT': {'test': 'a'}} >>> specs = [ ... 'interpolated string = string(default="fuzzy-%(man)s")', ... '[DEFAULT]', ... 'man = wuzzy', ... ] >>> c = ConfigObj(configspec=specs) >>> c.validate(v) 1 >>> c['interpolated string'] 'fuzzy-wuzzy' FIXME: Above tests will fail if we couldn't import Validator (the ones that don't raise errors will produce different output and still fail as tests) """ if section is None: if self.configspec is None: raise ValueError, 'No configspec supplied.' if preserve_errors: if VdtMissingValue is None: raise ImportError('Missing validate module.') section = self # spec_section = section.configspec if '__many__' in section.configspec: many = spec_section['__many__'] # dynamically assign the configspecs # for the sections below for entry in section.sections: self._handle_repeat(section[entry], many) # out = {} ret_true = True ret_false = True for entry in spec_section: if entry == '__many__': continue if (not entry in section.scalars) or (entry in section.defaults): # missing entries # or entries from defaults missing = True val = None else: missing = False val = section[entry] try: check = validator.check(spec_section[entry], val, missing=missing ) except validator.baseErrorClass, e: if not preserve_errors or isinstance(e, VdtMissingValue): out[entry] = False else: # preserve the error out[entry] = e ret_false = False ret_true = False else: ret_false = False out[entry] = True if self.stringify or missing: # if we are doing type conversion # or the value is a supplied default if not self.stringify: if isinstance(check, (list, tuple)): # preserve lists check = [self._str(item) for item in check] elif missing and check is None: # convert the None from a default to a '' check = '' else: check = self._str(check) if (check != val) or missing: section[entry] = check if missing and entry not in section.defaults: section.defaults.append(entry) # # FIXME: Will this miss missing sections ? for entry in section.sections: if section is self and entry == 'DEFAULT': continue check = self.validate(validator, preserve_errors=preserve_errors, section=section[entry]) out[entry] = check if check == False: ret_true = False elif check == True: ret_false = False else: ret_true = False ret_false = False # if ret_true: return True elif ret_false: return False else: return out class SimpleVal(object): """ A simple validator. Can be used to check that all members expected are present. To use it, provide a configspec with all your members in (the value given will be ignored). Pass an instance of ``SimpleVal`` to the ``validate`` method of your ``ConfigObj``. ``validate`` will return ``True`` if all members are present, or a dictionary with True/False meaning present/missing. (Whole missing sections will be replaced with ``False``) >>> val = SimpleVal() >>> config = ''' ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [section] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [[sub section]] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... '''.split('\\n') >>> configspec = ''' ... test1='' ... test2='' ... test3='' ... test4='' ... [section] ... test1='' ... test2='' ... test3='' ... test4='' ... [[sub section]] ... test1='' ... test2='' ... test3='' ... test4='' ... '''.split('\\n') >>> o = ConfigObj(config, configspec=configspec) >>> o.validate(val) 1 >>> o = ConfigObj(configspec=configspec) >>> o.validate(val) 0 """ def __init__(self): self.baseErrorClass = ConfigObjError def check(self, check, member, missing=False): """A dummy check method, always returns the value unchanged.""" if missing: raise self.baseErrorClass return member # Check / processing functions for options def flatten_errors(cfg, res, levels=None, results=None): """ An example function that will turn a nested dictionary of results (as returned by ``ConfigObj.validate``) into a flat list. ``cfg`` is the ConfigObj instance being checked, ``res`` is the results dictionary returned by ``validate``. (This is a recursive function, so you shouldn't use the ``levels`` or ``results`` arguments - they are used by the function. Returns a list of keys that failed. Each member of the list is a tuple : :: ([list of sections...], key, result) If ``validate`` was called with ``preserve_errors=False`` (the default) then ``result`` will always be ``False``. *list of sections* is a flattened list of sections that the key was found in. If the section was missing then key will be ``None``. If the value (or section) was missing then ``result`` will be ``False``. If ``validate`` was called with ``preserve_errors=True`` and a value was present, but failed the check, then ``result`` will be the exception object returned. You can use this as a string that describes the failure. For example *The value "3" is of the wrong type*. # FIXME: is the ordering of the output arbitrary ? >>> import validate >>> vtor = validate.Validator() >>> my_ini = ''' ... option1 = True ... [section1] ... option1 = True ... [section2] ... another_option = Probably ... [section3] ... another_option = True ... [[section3b]] ... value = 3 ... value2 = a ... value3 = 11 ... ''' >>> my_cfg = ''' ... option1 = boolean() ... option2 = boolean() ... option3 = boolean(default=Bad_value) ... [section1] ... option1 = boolean() ... option2 = boolean() ... option3 = boolean(default=Bad_value) ... [section2] ... another_option = boolean() ... [section3] ... another_option = boolean() ... [[section3b]] ... value = integer ... value2 = integer ... value3 = integer(0, 10) ... [[[section3b-sub]]] ... value = string ... [section4] ... another_option = boolean() ... ''' >>> cs = my_cfg.split('\\n') >>> ini = my_ini.split('\\n') >>> cfg = ConfigObj(ini, configspec=cs) >>> res = cfg.validate(vtor, preserve_errors=True) >>> errors = [] >>> for entry in flatten_errors(cfg, res): ... section_list, key, error = entry ... section_list.insert(0, '[root]') ... if key is not None: ... section_list.append(key) ... else: ... section_list.append('[missing]') ... section_string = ', '.join(section_list) ... errors.append((section_string, ' = ', error)) >>> errors.sort() >>> for entry in errors: ... print entry[0], entry[1], (entry[2] or 0) [root], option2 = 0 [root], option3 = the value "Bad_value" is of the wrong type. [root], section1, option2 = 0 [root], section1, option3 = the value "Bad_value" is of the wrong type. [root], section2, another_option = the value "Probably" is of the wrong type. [root], section3, section3b, section3b-sub, [missing] = 0 [root], section3, section3b, value2 = the value "a" is of the wrong type. [root], section3, section3b, value3 = the value "11" is too big. [root], section4, [missing] = 0 """ if levels is None: # first time called levels = [] results = [] if res is True: return results if res is False: results.append((levels[:], None, False)) if levels: levels.pop() return results for (key, val) in res.items(): if val == True: continue if isinstance(cfg.get(key), dict): # Go down one level levels.append(key) flatten_errors(cfg[key], val, levels, results) continue results.append((levels[:], key, val)) # # Go up one level if levels: levels.pop() # return results # FIXME: test error code for badly built multiline values # FIXME: test handling of StringIO # FIXME: test interpolation with writing def _doctest(): """ Dummy function to hold some of the doctests. >>> a.depth 0 >>> a == { ... 'key2': 'val', ... 'key1': 'val', ... 'lev1c': { ... 'lev2c': { ... 'lev3c': { ... 'key1': 'val', ... }, ... }, ... }, ... 'lev1b': { ... 'key2': 'val', ... 'key1': 'val', ... 'lev2ba': { ... 'key1': 'val', ... }, ... 'lev2bb': { ... 'key1': 'val', ... }, ... }, ... 'lev1a': { ... 'key2': 'val', ... 'key1': 'val', ... }, ... } 1 >>> b.depth 0 >>> b == { ... 'key3': 'val3', ... 'key2': 'val2', ... 'key1': 'val1', ... 'section 1': { ... 'keys11': 'val1', ... 'keys13': 'val3', ... 'keys12': 'val2', ... }, ... 'section 2': { ... 'section 2 sub 1': { ... 'fish': '3', ... }, ... 'keys21': 'val1', ... 'keys22': 'val2', ... 'keys23': 'val3', ... }, ... } 1 >>> t = ''' ... 'a' = b # !"$%^&*(),::;'@~#= 33 ... "b" = b #= 6, 33 ... ''' .split('\\n') >>> t2 = ConfigObj(t) >>> assert t2 == {'a': 'b', 'b': 'b'} >>> t2.inline_comments['b'] = '' >>> del t2['a'] >>> assert t2.write() == ['','b = b', ''] # Test ``list_values=False`` stuff >>> c = ''' ... key1 = no quotes ... key2 = 'single quotes' ... key3 = "double quotes" ... key4 = "list", 'with', several, "quotes" ... ''' >>> cfg = ConfigObj(c.splitlines(), list_values=False) >>> cfg == {'key1': 'no quotes', 'key2': "'single quotes'", ... 'key3': '"double quotes"', ... 'key4': '"list", \\'with\\', several, "quotes"' ... } 1 >>> cfg = ConfigObj(list_values=False) >>> cfg['key1'] = 'Multiline\\nValue' >>> cfg['key2'] = '''"Value" with 'quotes' !''' >>> cfg.write() ["key1 = '''Multiline\\nValue'''", 'key2 = "Value" with \\'quotes\\' !'] >>> cfg.list_values = True >>> cfg.write() == ["key1 = '''Multiline\\nValue'''", ... 'key2 = \\'\\'\\'"Value" with \\'quotes\\' !\\'\\'\\''] 1 Test flatten_errors: >>> from validate import Validator, VdtValueTooSmallError >>> config = ''' ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [section] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [[sub section]] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... '''.split('\\n') >>> configspec = ''' ... test1= integer(30,50) ... test2= string ... test3=integer ... test4=float(6.0) ... [section ] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... [[sub section]] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... '''.split('\\n') >>> val = Validator() >>> c1 = ConfigObj(config, configspec=configspec) >>> res = c1.validate(val) >>> flatten_errors(c1, res) == [([], 'test4', False), (['section', ... 'sub section'], 'test4', False), (['section'], 'test4', False)] True >>> res = c1.validate(val, preserve_errors=True) >>> check = flatten_errors(c1, res) >>> check[0][:2] ([], 'test4') >>> check[1][:2] (['section', 'sub section'], 'test4') >>> check[2][:2] (['section'], 'test4') >>> for entry in check: ... isinstance(entry[2], VdtValueTooSmallError) ... print str(entry[2]) True the value "5.0" is too small. True the value "5.0" is too small. True the value "5.0" is too small. Test unicode handling, BOM, write witha file like object and line endings : >>> u_base = ''' ... # initial comment ... # inital comment 2 ... ... test1 = some value ... # comment ... test2 = another value # inline comment ... # section comment ... [section] # inline comment ... test = test # another inline comment ... test2 = test2 ... ... # final comment ... # final comment2 ... ''' >>> u = u_base.encode('utf_8').splitlines(True) >>> u[0] = BOM_UTF8 + u[0] >>> uc = ConfigObj(u) >>> uc.encoding = None >>> uc.BOM == True 1 >>> uc == {'test1': 'some value', 'test2': 'another value', ... 'section': {'test': 'test', 'test2': 'test2'}} 1 >>> uc = ConfigObj(u, encoding='utf_8', default_encoding='latin-1') >>> uc.BOM 1 >>> isinstance(uc['test1'], unicode) 1 >>> uc.encoding 'utf_8' >>> uc.newlines '\\n' >>> uc['latin1'] = "This costs lot's of " >>> a_list = uc.write() >>> len(a_list) 15 >>> isinstance(a_list[0], str) 1 >>> a_list[0].startswith(BOM_UTF8) 1 >>> u = u_base.replace('\\n', '\\r\\n').encode('utf_8').splitlines(True) >>> uc = ConfigObj(u) >>> uc.newlines '\\r\\n' >>> uc.newlines = '\\r' >>> from cStringIO import StringIO >>> file_like = StringIO() >>> uc.write(file_like) >>> file_like.seek(0) >>> uc2 = ConfigObj(file_like) >>> uc2 == uc 1 >>> uc2.filename == None 1 >>> uc2.newlines == '\\r' 1 """ if __name__ == '__main__': # run the code tests in doctest format # testconfig1 = """\ key1= val # comment 1 key2= val # comment 2 # comment 3 [lev1a] # comment 4 key1= val # comment 5 key2= val # comment 6 # comment 7 [lev1b] # comment 8 key1= val # comment 9 key2= val # comment 10 # comment 11 [[lev2ba]] # comment 12 key1= val # comment 13 # comment 14 [[lev2bb]] # comment 15 key1= val # comment 16 # comment 17 [lev1c] # comment 18 # comment 19 [[lev2c]] # comment 20 # comment 21 [[[lev3c]]] # comment 22 key1 = val # comment 23""" # testconfig2 = """\ key1 = 'val1' key2 = "val2" key3 = val3 ["section 1"] # comment keys11 = val1 keys12 = val2 keys13 = val3 [section 2] keys21 = val1 keys22 = val2 keys23 = val3 [['section 2 sub 1']] fish = 3 """ # testconfig6 = ''' name1 = """ a single line value """ # comment name2 = \''' another single line value \''' # comment name3 = """ a single line value """ name4 = \''' another single line value \''' [ "multi section" ] name1 = """ Well, this is a multiline value """ name2 = \''' Well, this is a multiline value \''' name3 = """ Well, this is a multiline value """ # a comment name4 = \''' Well, this is a multiline value \''' # I guess this is a comment too ''' # import doctest m = sys.modules.get('__main__') globs = m.__dict__.copy() a = ConfigObj(testconfig1.split('\n'), raise_errors=True) b = ConfigObj(testconfig2.split('\n'), raise_errors=True) i = ConfigObj(testconfig6.split('\n'), raise_errors=True) globs.update({ 'INTP_VER': INTP_VER, 'a': a, 'b': b, 'i': i, }) doctest.testmod(m, globs=globs) """ BUGS ==== None known. TODO ==== Better support for configuration from multiple files, including tracking *where* the original file came from and writing changes to the correct file. Make ``newline`` an option (as well as an attribute) ? ``UTF16`` encoded files, when returned as a list of lines, will have the BOM at the start of every line. Should this be removed from all but the first line ? Option to set warning type for unicode decode ? (Defaults to strict). A method to optionally remove uniform indentation from multiline values. (do as an example of using ``walk`` - along with string-escape) Should the results dictionary from validate be an ordered dictionary if `odict `_ is available ? Implement a better ``__repr__`` ? (``ConfigObj({})``) Implement some of the sequence methods (which include slicing) from the newer ``odict`` ? INCOMPATIBLE CHANGES ==================== (I have removed a lot of needless complications - this list is probably not conclusive, many option/attribute/method names have changed) Case sensitive The only valid divider is '=' We've removed line continuations with '\' No recursive lists in values No empty section No distinction between flatfiles and non flatfiles Change in list syntax - use commas to indicate list, not parentheses (square brackets and parentheses are no longer recognised as lists) ';' is no longer valid for comments and no multiline comments No attribute access We don't allow empty values - have to use '' or "" In ConfigObj 3 - setting a non-flatfile member to ``None`` would initialise it as an empty section. The escape entities '&mjf-lf;' and '&mjf-quot;' have gone replaced by triple quote, multiple line values. The ``newline``, ``force_return``, and ``default`` options have gone The ``encoding`` and ``backup_encoding`` methods have gone - replaced with the ``encode`` and ``decode`` methods. ``fileerror`` and ``createempty`` options have become ``file_error`` and ``create_empty`` Partial configspecs (for specifying the order members should be written out and which should be present) have gone. The configspec is no longer used to specify order for the ``write`` method. Exceeding the maximum depth of recursion in string interpolation now raises an error ``InterpolationDepthError``. Specifying a value for interpolation which doesn't exist now raises an error ``MissingInterpolationOption`` (instead of merely being ignored). The ``writein`` method has been removed. The comments attribute is now a list (``inline_comments`` equates to the old comments attribute) ISSUES ====== ``validate`` doesn't report *extra* values or sections. You can't have a keyword with the same name as a section (in the same section). They are both dictionary keys - so they would overlap. ConfigObj doesn't quote and unquote values if ``list_values=False``. This means that leading or trailing whitespace in values will be lost when writing. (Unless you manually quote). Interpolation checks first the 'DEFAULT' subsection of the current section, next it checks the 'DEFAULT' section of the parent section, last it checks the 'DEFAULT' section of the main section. Logically a 'DEFAULT' section should apply to all subsections of the *same parent* - this means that checking the 'DEFAULT' subsection in the *current section* is not necessarily logical ? In order to simplify unicode support (which is possibly of limited value in a config file) I have removed automatic support and added the ``encode`` and ``decode methods, which can be used to transform keys and entries. Because the regex looks for specific values on inital parsing (i.e. the quotes and the equals signs) it can only read ascii compatible encodings. For unicode use ``UTF8``, which is ASCII compatible. Does it matter that we don't support the ':' divider, which is supported by ``ConfigParser`` ? The regular expression correctly removes the value - ``"'hello', 'goodbye'"`` and then unquote just removes the front and back quotes (called from ``_handle_value``). What should we do ?? (*ought* to raise exception because it's an invalid value if lists are off *sigh*. This is not what you want if you want to do your own list processing - would be *better* in this case not to unquote.) String interpolation and validation don't play well together. When validation changes type it sets the value. This will correctly fetch the value using interpolation - but then overwrite the interpolation reference. If the value is unchanged by validation (it's a string) - but other types will be. List Value Syntax ================= List values allow you to specify multiple values for a keyword. This maps to a list as the resulting Python object when parsed. The syntax for lists is easy. A list is a comma separated set of values. If these values contain quotes, the hash mark, or commas, then the values can be surrounded by quotes. e.g. : :: keyword = value1, 'value 2', "value 3" If a value needs to be a list, but only has one member, then you indicate this with a trailing comma. e.g. : :: keyword = "single value", If a value needs to be a list, but it has no members, then you indicate this with a single comma. e.g. : :: keyword = , # an empty list Using triple quotes it will be possible for single values to contain newlines and *both* single quotes and double quotes. Triple quotes aren't allowed in list values. This means that the members of list values can't contain carriage returns (or line feeds :-) or both quote values. CHANGELOG ========= 2006/02/04 ---------- Removed ``BOM_UTF8`` from ``__all__``. The ``BOM`` attribute has become a boolean. (Defaults to ``False``.) It can be ``True`` for the ``UTF16/UTF8`` encodings. File like objects no longer need a ``seek`` attribute. ConfigObj no longer keeps a reference to file like objects. Instead the ``write`` method takes a file like object as an optional argument. (Which will be used in preference of the ``filename`` attribute if htat exists as well.) Full unicode support added. New options/attributes ``encoding``, ``default_encoding``. utf16 files decoded to unicode. If ``BOM`` is ``True``, but no encoding specified, then the utf8 BOM is written out at the start of the file. (It will normally only be ``True`` if the utf8 BOM was found when the file was read.) File paths are *not* converted to absolute paths, relative paths will remain relative as the ``filename`` attribute. Fixed bug where ``final_comment`` wasn't returned if ``write`` is returning a list of lines. 2006/01/31 ---------- Added ``True``, ``False``, and ``enumerate`` if they are not defined. (``True`` and ``False`` are needed for *early* versions of Python 2.2, ``enumerate`` is needed for all versions ofPython 2.2) Deprecated ``istrue``, replaced it with ``as_bool``. Added ``as_int`` and ``as_float``. utf8 and utf16 BOM handled in an endian agnostic way. 2005/12/14 ---------- Validation no longer done on the 'DEFAULT' section (only in the root level). This allows interpolation in configspecs. Change in validation syntax implemented in validate 0.2.1 4.1.0 2005/12/10 ---------- Added ``merge``, a recursive update. Added ``preserve_errors`` to ``validate`` and the ``flatten_errors`` example function. Thanks to Matthew Brett for suggestions and helping me iron out bugs. Fixed bug where a config file is *all* comment, the comment will now be ``initial_comment`` rather than ``final_comment``. 2005/12/02 ---------- Fixed bug in ``create_empty``. Thanks to Paul Jimenez for the report. 2005/11/04 ---------- Fixed bug in ``Section.walk`` when transforming names as well as values. Added the ``istrue`` method. (Fetches the boolean equivalent of a string value). Fixed ``list_values=False`` - they are now only quoted/unquoted if they are multiline values. List values are written as ``item, item`` rather than ``item,item``. 4.0.1 2005/10/09 ---------- Fixed typo in ``write`` method. (Testing for the wrong value when resetting ``interpolation``). 4.0.0 Final 2005/09/16 ---------- Fixed bug in ``setdefault`` - creating a new section *wouldn't* return a reference to the new section. 2005/09/09 ---------- Removed ``PositionError``. Allowed quotes around keys as documented. Fixed bug with commas in comments. (matched as a list value) Beta 5 2005/09/07 ---------- Fixed bug in initialising ConfigObj from a ConfigObj. Changed the mailing list address. Beta 4 2005/09/03 ---------- Fixed bug in ``Section.__delitem__`` oops. 2005/08/28 ---------- Interpolation is switched off before writing out files. Fixed bug in handling ``StringIO`` instances. (Thanks to report from "Gustavo Niemeyer" ) Moved the doctests from the ``__init__`` method to a separate function. (For the sake of IDE calltips). Beta 3 2005/08/26 ---------- String values unchanged by validation *aren't* reset. This preserves interpolation in string values. 2005/08/18 ---------- None from a default is turned to '' if stringify is off - because setting a value to None raises an error. Version 4.0.0-beta2 2005/08/16 ---------- By Nicola Larosa Actually added the RepeatSectionError class ;-) 2005/08/15 ---------- If ``stringify`` is off - list values are preserved by the ``validate`` method. (Bugfix) 2005/08/14 ---------- By Michael Foord Fixed ``simpleVal``. Added ``RepeatSectionError`` error if you have additional sections in a section with a ``__many__`` (repeated) section. By Nicola Larosa Reworked the ConfigObj._parse, _handle_error and _multiline methods: mutated the self._infile, self._index and self._maxline attributes into local variables and method parameters Reshaped the ConfigObj._multiline method to better reflect its semantics Changed the "default_test" test in ConfigObj.validate to check the fix for the bug in validate.Validator.check 2005/08/13 ---------- By Nicola Larosa Updated comments at top 2005/08/11 ---------- By Michael Foord Implemented repeated sections. By Nicola Larosa Added test for interpreter version: raises RuntimeError if earlier than 2.2 2005/08/10 ---------- By Michael Foord Implemented default values in configspecs. By Nicola Larosa Fixed naked except: clause in validate that was silencing the fact that Python2.2 does not have dict.pop 2005/08/08 ---------- By Michael Foord Bug fix causing error if file didn't exist. 2005/08/07 ---------- By Nicola Larosa Adjusted doctests for Python 2.2.3 compatibility 2005/08/04 ---------- By Michael Foord Added the inline_comments attribute We now preserve and rewrite all comments in the config file configspec is now a section attribute The validate method changes values in place Added InterpolationError The errors now have line number, line, and message attributes. This simplifies error handling Added __docformat__ 2005/08/03 ---------- By Michael Foord Fixed bug in Section.pop (now doesn't raise KeyError if a default value is specified) Replaced ``basestring`` with ``types.StringTypes`` Removed the ``writein`` method Added __version__ 2005/07/29 ---------- By Nicola Larosa Indentation in config file is not significant anymore, subsections are designated by repeating square brackets Adapted all tests and docs to the new format 2005/07/28 ---------- By Nicola Larosa Added more tests 2005/07/23 ---------- By Nicola Larosa Reformatted final docstring in ReST format, indented it for easier folding Code tests converted to doctest format, and scattered them around in various docstrings Walk method rewritten using scalars and sections attributes 2005/07/22 ---------- By Nicola Larosa Changed Validator and SimpleVal "test" methods to "check" More code cleanup 2005/07/21 ---------- Changed Section.sequence to Section.scalars and Section.sections Added Section.configspec Sections in the root section now have no extra indentation Comments now better supported in Section and preserved by ConfigObj Comments also written out Implemented initial_comment and final_comment A scalar value after a section will now raise an error 2005/07/20 ---------- Fixed a couple of bugs Can now pass a tuple instead of a list Simplified dict and walk methods Added __str__ to Section 2005/07/10 ---------- By Nicola Larosa More code cleanup 2005/07/08 ---------- The stringify option implemented. On by default. 2005/07/07 ---------- Renamed private attributes with a single underscore prefix. Changes to interpolation - exceeding recursion depth, or specifying a missing value, now raise errors. Changes for Python 2.2 compatibility. (changed boolean tests - removed ``is True`` and ``is False``) Added test for duplicate section and member (and fixed bug) 2005/07/06 ---------- By Nicola Larosa Code cleanup 2005/07/02 ---------- Version 0.1.0 Now properly handles values including comments and lists. Better error handling. String interpolation. Some options implemented. You can pass a Section a dictionary to initialise it. Setting a Section member to a dictionary will create a Section instance. 2005/06/26 ---------- Version 0.0.1 Experimental reader. A reasonably elegant implementation - a basic reader in 160 lines of code. *A programming language is a medium of expression.* - Paul Graham """ m fFc@sdklZdkZeid ZeddfjoedndkZdkZdkl Z dk l Z dk l Z lZlZlZhe def<edd f<ed d f<ed d fYZ(d%e%fd?YZ)d(e%fd@YZ*d)e*fdAYZ+d+e%fdBYZ,d*e*fdCYZ-dDe.fdEYZ/d&e/fdFYZ0d'e1fdGYZ2eedHZ3dIZ4e5dJjodKZ6dLZ7dMZ8dk9Z9ei:i;dJZ<e<i=i>Z?e0e6i@dNd2eZAe0e7i@dNd2eZBe0e8i@dNd2eZCe?iDhdOe<dPeA<dQeB<dReC<e9iEe<dSe?ndS(T(s generatorsNisPython v.2.2 or later needed(s StringTypes(swarn(sBOM_UTF8s BOM_UTF16s BOM_UTF16_BEs BOM_UTF16_LEtutf_8tutf16_betutf_16tutf16_letu16tutf16sutf-16t utf_16_besutf-16bet utf_16_lesutf-16letu8tutftutf8sutf-8(sVdtMissingValueccs/d}x"|D]}|d7}||fVq WdS(senumerate for Python 2.2.iiN(titobjtitem(R R R ((t/usr/bin/configobj.pyt enumerate]s  iis4.2.0s5$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $srestructuredtext ent __version__tDEFAULT_INDENT_TYPEtNUM_INDENT_SPACEStMAX_INTERPOL_DEPTHtConfigObjErrort NestingErrort ParseErrortDuplicateErrortConfigspecErrort ConfigObjt SimpleValtInterpolationErrortInterpolationDepthErrortMissingInterpolationOptiontRepeatSectionErrort __docformat__tflatten_errorst ii t interpolationt raise_errorst list_valuest create_emptyt file_errort configspect stringifyt indent_typetencodingtdefault_encodingcBs tZdZdeddZRS(s This is the base class for all errors that ConfigObj raises. It is a subclass of SyntaxError. >>> raise ConfigObjError Traceback (most recent call last): ConfigObjError tcCs/||_||_||_ti||dS(N(tlinetselft line_numbertmessaget SyntaxErrort__init__(R.R0R/R-((RR2s   (t__name__t __module__t__doc__tNoneR2(((RRs cBstZdZRS(s This error indicates a level of nesting that doesn't match. >>> raise NestingError Traceback (most recent call last): NestingError (R3R4R5(((RRs cBstZdZRS(s This error indicates that a line is badly written. It is neither a valid ``key = value`` line, nor a valid section marker line. >>> raise ParseError Traceback (most recent call last): ParseError (R3R4R5(((RRs cBstZdZRS(s The keyword or section specified already exists. >>> raise DuplicateError Traceback (most recent call last): DuplicateError (R3R4R5(((RRs cBstZdZRS(s An error occured whilst parsing a configspec. >>> raise ConfigspecError Traceback (most recent call last): ConfigspecError (R3R4R5(((RRs cBstZdZRS(s,Base class for the two interpolation errors.(R3R4R5(((RRs cBstZdZdZRS(s=Maximum interpolation depth exceeded in string interpolation.cCsti|d|dS(s >>> raise InterpolationDepthError('yoda') Traceback (most recent call last): InterpolationDepthError: max interpolation depth exceeded in value "yoda". s/max interpolation depth exceeded in value "%s".N(RR2R.toption(R.R7((RR2s (R3R4R5R2(((RRs cBstZdZRS(s This error indicates additional sections in a section with a ``__many__`` (repeated) section. >>> raise RepeatSectionError Traceback (most recent call last): RepeatSectionError (R3R4R5(((RRs cBstZdZdZRS(s0A value specified for interpolation was missing.cCsti|d|dS(s >>> raise MissingInterpolationOption('yoda') Traceback (most recent call last): MissingInterpolationOption: missing option "yoda" in interpolation. s%missing option "%s" in interpolation.N(RR2R.R7(R.R7((RR2s (R3R4R5R2(((RRs tSectioncBs@tZdZeidZeedZdZdZ dZ dZ dZ edZ d Zd Zd Zd Zed ZdZdZdZdZdZeZdZdZeZdZdZdZee dZ!dZ"dZ#dZ$dZ%dZ&dZ'RS(sO A dictionary-like object that represents a section in a config file. It does string interpolation if the 'interpolate' attribute of the 'main' object is set to True. Interpolation is tried first from the 'DEFAULT' section of this object, next from the 'DEFAULT' section of the parent, lastly the main object. A Section will behave like an ordered dictionary - following the order of the ``scalars`` and ``sections`` attributes. You can use this to change the order of members. Iteration follows the order: scalars, then sections. s%\(([^)]*)\)s|.cCs|djo h}nti|||_||_||_g|_g|_ ||_ h|_ h|_ h|_ g|_x|D]}||||R(tlistttupleRDt TypeError(R.RTRER\RD((RR[VsF     cCs\ti||||ijo|ii|n|ii||i|=|i|=dS(s-Remove items from the sequence when deleting.N( R:t __delitem__R.RTR>RYR?RARB(R.RT((RR`s cCs*y ||SWntj o |SnXdS(s>A version of ``get`` that doesn't bypass string interpolation.N(R.RTtKeyErrortdefault(R.RTRb((RRPs  cCs#x|D]}||||RARBRYR?R<R"RURVRJ(R.RTReRQ((RRds    cCsI|i|i}|p tdn|d}||}||=||fS(sPops the first (key,val)s": 'popitem(): dictionary is empty'iN(R.R>R?tsequenceRaRTRQ(R.RQRTRf((Rtpopitems   cCs>ti|g|_g|_h|_h|_h|_dS(s A version of clear that also affects scalars/sections Also clears comments and configspec. Leaves other attributes alone : depth/main/parent are not affected N(R:tclearR.R>R?RARBR'(R.((RRhs     cCs8y ||SWn%tj o|||<||SnXdS(s:A version of setdefault that sets sequence if appropriate.N(R.RTRaRb(R.RTRb((Rt setdefaults   cCst|i|i|iS(R!N(tzipR.R>R?tvalues(R.((RtitemsscCs|i|iS(R!N(R.R>R?(R.((RtkeysscCs-g}|i|iD]}|||q~S(R!N(t_[1]R.R>R?RT(R.RnRT((RRkscCst|iS(R!N(titerR.Rl(R.((Rt iteritemsscCst|i|iS(R!N(RoR.R>R?(R.((RtiterkeysscCst|iS(R!N(RoR.Rk(R.((Rt itervaluessc CsPddig}|i|iD]'}|dt|t||fq~S(Ns{%s}s, s%s: %s(tjoinRnR.R>R?RTtrepr(R.RnRT((Rt__repr__scCsuh}xh|D]`}||}t|to|i}n't|ttfot|}n|||>> n = a.dict() >>> n == a 1 >>> n is a 0 N( tnewdictR.RDt this_entryRUR8R:R]R^(R.RvRwRD((RR:s  cCsqxj|iD]\\}}||jo9t||to%t|to||i|q |||>> a = '''[section1] ... option1 = True ... [[subsection]] ... more_options = False ... # end of file'''.splitlines() >>> b = '''# File is user.ini ... [section1] ... option1 = False ... # end of file'''.splitlines() >>> c1 = ConfigObj(b) >>> c2 = ConfigObj(a) >>> c2.merge(c1) >>> c2 {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}} N(R9RlRTRQR.RUR:tmerge(R.R9RQRT((RRxs  1cCs||ijo |i}n+||ijo |i}ntd||i|}||}t i ||t i ||||i ||i|||i|}|i|}|i|=|i|=||i|<||i|tthe_listR?RatindextposRQR:R`R[tnewkeyRYtinsertRAtcommRBtinline_comment(R.RyR}RRQRR|Rz((Rtrename*s$          c KsYh}xtt|iD]{}|i|}y-||||}|i|}|||>> config = '''[XXXXsection] ... XXXXkey = XXXXvalue'''.splitlines() >>> cfg = ConfigObj(config) >>> cfg {'XXXXsection': {'XXXXkey': 'XXXXvalue'}} >>> def transform(section, key): ... val = section[key] ... newkey = key.replace('XXXX', 'CLIENT1') ... section.rename(key, newkey) ... if isinstance(val, (tuple, list, dict)): ... pass ... else: ... val = val.replace('XXXX', 'CLIENT1') ... section[newkey] = val >>> cfg.walk(transform, call_on_sections=True) {'CLIENT1section': {'CLIENT1key': None}} >>> cfg {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}} R#tcall_on_sectionsN(touttrangetlenR.R>R RDtfunctiontkeywargsRQt ExceptionR#ROR?Rtwalk( R.RR#RRRQR RDR((RRGs<.      cCs#|d}|i|dtdS(sK Decode all strings and values to unicode, using the specified encoding. Works with subsections and list values. Uses the ``walk`` method. Testing ``encode`` and ``decode``. >>> m = ConfigObj(a) >>> m.decode('ascii') >>> def testuni(val): ... for entry in val: ... if not isinstance(entry, unicode): ... print >> sys.stderr, type(entry) ... raise AssertionError, 'decode failed.' ... if isinstance(val[entry], dict): ... testuni(val[entry]) ... elif not isinstance(val[entry], unicode): ... raise AssertionError, 'decode failed.' >>> testuni(m) >>> m.encode('ascii') >>> a == m 1 cCs||}t|ttfo1g}xQ|D]}|i|i |q-Wn*t|t o |}n|i |}|i |}|i |||||>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_bool('a') Traceback (most recent call last): ValueError: Value "fish" is neither True nor False >>> a['b'] = 'True' >>> a.as_bool('b') 1 >>> a['b'] = 'off' >>> a.as_bool('b') 0 s$Value "%s" is neither True nor FalseN( R.RTRQRRRORURVRaR<t_boolstlowerRW(R.RTRQ((RRs    cCst||S(sK A convenience method which coerces the specified value to an integer. If the value is an invalid literal for ``int``, a ``ValueError`` will be raised. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_int('a') Traceback (most recent call last): ValueError: invalid literal for int(): fish >>> a['b'] = '1' >>> a.as_int('b') 1 >>> a['b'] = '3.2' >>> a.as_int('b') Traceback (most recent call last): ValueError: invalid literal for int(): 3.2 N(tintR.RT(R.RT((Rtas_int scCst||S(s A convenience method which coerces the specified value to a float. If the value is an invalid literal for ``float``, a ``ValueError`` will be raised. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_float('a') Traceback (most recent call last): ValueError: invalid literal for float(): fish >>> a['b'] = '1' >>> a.as_float('b') 1.0 >>> a['b'] = '3.2' >>> a.as_float('b') 3.2000000000000002 N(tfloatR.RT(R.RT((Rtas_float#s((R3R4R5tretcompileRGR6R2RJRIRSR[R`RPRcRdRgRhRiRlRmRkRpRqt__iter__RrRut__str__R:RxRRRRORRRRRRR(((RR8sB #    7               T *   * cBstZdZeideiZeideiZeideiZeideiZ eideiZ eidZ eidZ eidZ eid Zhd e e f<d e ef>> c = ''' ... [hello] ... member = value ... [hello again] ... member = value ... [ "hello" ] ... member = value ... ''' >>> ConfigObj(c.split('\n'), raise_errors = True) Traceback (most recent call last): DuplicateError: Duplicate section name at line 5. >>> d = ''' ... [hello] ... member = value ... [hello again] ... member1 = value ... member2 = value ... 'member1' = value ... [ "and again" ] ... member = value ... ''' >>> ConfigObj(d.split('\n'), raise_errors = True) Traceback (most recent call last): DuplicateError: Duplicate keyword name at line 6. s^ # line start (\s*) # indentation ( # keyword (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'"=].*?) # no quotes ) \s*=\s* # divider (.*) # value (including list values and comments) $ # line end s=^ (\s*) # 1: indentation ((?:\[\s*)+) # 2: section marker open ( # 3: section name open (?:"\s*\S.*?\s*")| # at least one non-space with double quotes (?:'\s*\S.*?\s*')| # at least one non-space with single quotes (?:[^'"\s].*?) # at least one non-space unquoted ) # section name close ((?:\s*\])+) # 4: section marker close \s*(\#.*)? # 5: optional comment $s^ (?: (?: ( (?: (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#][^,\#]*?) # unquoted ) \s*,\s* # comma )* # match all list items ending in a comma (if any) ) ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#\s][^,]*?) # unquoted )? # last item in a list - or string value )| (,) # alternatively a single comma - empty list ) \s*(\#.*)? # optional comment $s ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#].*?) # unquoted ) \s*,\s* # comma s^ ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'"\#].*?) # unquoted ) \s*(\#.*)? # optional comment $s^'''(.*?)'''\s*(#.*)?$s^"""(.*?)"""\s*(#.*)?$s^(.*?)'''\s*(#.*)?$s^(.*?)"""\s*(#.*)?$s'''s"""tyestnotontofft1t0ttruetfalsec Ks|djo g}n|djo h}n|i|ti||d|ti }x8|i D]*} | |i jot d| qjqjW|i|d|_g|_|d|_|d|_|d|_|d|_|d|_|d|_|d |_|d |_|d |_t|_d|_g|_g|_t|to||_t i!i"|ot#|i$pg}q|iot%d |iq|io*t#|d }|i'd|i(ng}nt|t)t*fot)|}nt|t+o|t|t,o|i+}nx|D]} || || infile must be a filename, file like object, or list of lines.is s s sParsing failed.(s s s (;tinfileR6toptionsRctkwargsR8R2R.tOPTION_DEFAULTStcopyRCRmRDR_tfilenamet_errorsR#R"R$R%R&R(R)R*R+ROtBOMtnewlinestinitial_commentt final_commentRURVtostpathtisfiletopenRtIOErrorthtwritetcloseR]R^R:Rt_handle_configspecR'thasattrt _handle_bomR-tendtendswithRntrstript_parseRterrorterrorstconfig( R.RRRRR-RRnRCRRD((RR2s                                .       cCs}|idj o-|iitjo|i||iSnt|tt fo|d}n|}|idj ot|ii}|djolxRt i D]D\}\}}|pqn|i|o|i||SqqW|i||iSnt|}|i|p|i||iSn|t|}t|tt fo||d>> c = ConfigObj() >>> c['DEFAULT'] = { ... 'b': 'goodbye', ... 'userdir': 'c:\\home', ... 'c': '%(d)s', ... 'd': '%(c)s' ... } >>> c['section'] = { ... 'a': '%(datadir)s\\some path\\file.py', ... 'b': '%(userdir)s\\some path\\file.py', ... 'c': 'Yo %(a)s', ... 'd': '%(not_here)s', ... 'e': '%(c)s', ... } >>> c['section']['DEFAULT'] = { ... 'datadir': 'c:\\silly_test', ... 'a': 'hello - %(b)s', ... } >>> c['section']['a'] == 'c:\\silly_test\\some path\\file.py' 1 >>> c['section']['b'] == 'c:\\home\\some path\\file.py' 1 >>> c['section']['c'] == 'Yo hello - goodbye' 1 Switching Interpolation Off >>> c.interpolation = False >>> c['section']['a'] == '%(datadir)s\\some path\\file.py' 1 >>> c['section']['b'] == '%(userdir)s\\some path\\file.py' 1 >>> c['section']['c'] == 'Yo %(a)s' 1 Testing the interpolation errors. >>> c.interpolation = True >>> c['section']['d'] Traceback (most recent call last): MissingInterpolationOption: missing option "not_here" in interpolation. >>> c['section']['e'] Traceback (most recent call last): InterpolationDepthError: max interpolation depth exceeded in value "%(c)s". Testing our quoting. >>> i._quote('"""'''') Traceback (most recent call last): SyntaxError: EOF while scanning triple-quoted string >>> try: ... i._quote('\n', multiline=False) ... except ConfigObjError, e: ... e.msg 'Value "\n" cannot be safely quoted.' >>> k._quote(' "' ', multiline=False) Traceback (most recent call last): SyntaxError: EOL while scanning single-quoted string Testing with "stringify" off. >>> c.stringify = False >>> c['test'] = 1 Traceback (most recent call last): TypeError: Value is not a string "1". iit#it[t]s,Cannot compute the section depth at line %s.s(Cannot compute nesting level at line %s.sSection too nested at line %s.s"Duplicate section name at line %s.R@is"""s'''s Parse error in value at line %s.s"Duplicate keyword name at line %s.sInvalid line at line "%s".R,N(1t comment_listROt done_startR.t this_sectionRRtmaxlinet cur_indext reset_commentR-tstriptslineRRZRRRt_sectionmarkerRLtmatR6tgroupstindentt sect_opent sect_namet sect_closetcommentR)tcountt cur_deptht _handle_errorRR=t _match_depthR;R1t_unquoteRXRR8RBRAt_keywordRTREt _multilineRt _handle_valueR(R.RRRRRRRRRR;RRRTRR-RRRRE((RRsF                          %             cCs]x8||ijo'||ijo tn|i}qW|i|jo|SntdS(s Given a section and a depth level, walk back through the sections parents to see if the depth level matches a previous section. Return a reference to the right section, or raise a SyntaxError. N(R=tsectR;R1(R.RR=((RRs cCsN||}||}||||}|io |n|i i |dS(s Handle an error according to the error settings. Either raise the error or store it. The error will have occured at ``cur_index`` N( RRR-ttextR0t ErrorClassRR.R#RRZ(R.RRRRR0RR-((RRs    cCs;|d|djo"|ddjo|dd!}n|S(s%Return an unquoted version of a valueiit"t'iN(RR(RE(R.RE((RRs&c Csit|ttfo||pdSn3t|djo|i|ddtdSndig} |D]}| |i|dtqh~ Snt|t p+|i ot |}qtd|nd}d} d }d } d }d }|pd Sn|i o d|jp/|o$d|jo d|jp d|j o|ip |}qad|jotd|qa|d| jo(|d| jod|jo |}qad|jod|jotd|qad|jo |}qa| }nd|iddjo'|iddjotd|n|iddjo |}n|}||S(sC Return a safely quoted version of a value. Raise a ConfigObjError if the value cannot be safely quoted. If multiline is ``True`` (default) then use triple quotes if necessary. Don't quote values that don't need it. Recursively quote members of a list and return a comma joined list. Multiline is ``False`` for lists. Obey list syntax for empty and single member lists. If ``list_values=False`` then the value is only quoted if it contains a `` `` (is multiline). t,iit multilines, sValue "%s" is not a string.s'%s's"%s"s%ss '"s"""%s"""s'''%s'''s""s RRs#Value "%s" cannot be safely quoted.is"""s'''N(RURER]R^RR.t_quoteRORsRnRQRVR(RR_tsquottdquottnoquott wspace_plusttsquotttdquotR$RtquotRRF( R.RERRRQRRRRRRnR((RRsJ; G   /    , c Csr|ipI|ii|}|djo tn|i\}}||fSn|i i|}|djo tn|i\}}} }|djo|djo tn| dj og|fSn|dj o|i |}n|djo||fSn|ii|}g}|D]}||i |q+~}|dj o||g7}n||fS(s Given a value string, unquote, remove comment, handle lists. (including empty and single member lists) Testing list values. >>> testconfig3 = ''' ... a = , ... b = test, ... c = test1, test2 , test3 ... d = test1, test2, test3, ... ''' >>> d = ConfigObj(testconfig3.split('\n'), raise_errors=True) >>> d['a'] == [] 1 >>> d['b'] == ['test'] 1 >>> d['c'] == ['test1', 'test2', 'test3'] 1 >>> d['d'] == ['test1', 'test2', 'test3'] 1 Testing with list values off. >>> e = ConfigObj( ... testconfig3.split('\n'), ... raise_errors=True, ... list_values=False) >>> e['a'] == ',' 1 >>> e['b'] == 'test,' 1 >>> e['c'] == 'test1, test2 , test3' 1 >>> e['d'] == 'test1, test2, test3,' 1 Testing creating from a dictionary. >>> f = { ... 'key1': 'val1', ... 'key2': 'val2', ... 'section 1': { ... 'key1': 'val1', ... 'key2': 'val2', ... 'section 1b': { ... 'key1': 'val1', ... 'key2': 'val2', ... }, ... }, ... 'section 2': { ... 'key1': 'val1', ... 'key2': 'val2', ... 'section 2b': { ... 'key1': 'val1', ... 'key2': 'val2', ... }, ... }, ... 'key3': 'val3', ... } >>> g = ConfigObj(f) >>> f == g 1 Testing we correctly detect badly built list values (4 of them). >>> testconfig4 = ''' ... config = 3,4,, ... test = 3,,4 ... fish = ,, ... dummy = ,,hello, goodbye ... ''' >>> try: ... ConfigObj(testconfig4.split('\n')) ... except ConfigObjError, e: ... len(e.errors) 4 Testing we correctly detect badly quoted values (4 of them). >>> testconfig5 = ''' ... config = "hello # comment ... test = 'goodbye ... fish = 'goodbye # comment ... dummy = "hello again ... ''' >>> try: ... ConfigObj(testconfig5.split('\n')) ... except ConfigObjError, e: ... len(e.errors) 4 R,N(R.R$t _nolistvalueRLRERR6R1RRt _valueexptsinglet empty_listRt _listvalueexptfindallRzRnRQ( R.RERRRQR$RnRRzR((RRs0\         * c Cs@|d }|d}|i|d} |i|d} | i|}|dj o't |i } | i || Sn!|i|djo tnx[||joG|d7}|d7}||} | i|djo|| 7}qPqWt| i| }|djo tn|i \}}||||fS(s Extract the value, where we are in a multiline situation Testing multiline values. >>> i == { ... 'name4': ' another single line value ', ... 'multi section': { ... 'name4': '\n Well, this is a\n multiline ' ... 'value\n ', ... 'name2': '\n Well, this is a\n multiline ' ... 'value\n ', ... 'name3': '\n Well, this is a\n multiline ' ... 'value\n ', ... 'name1': '\n Well, this is a\n multiline ' ... 'value\n ', ... }, ... 'name2': ' another single line value ', ... 'name3': ' a single line value ', ... 'name1': ' a single line value ', ... } 1 iiiis N(RERtnewvalueR.t _triple_quotet single_linet multi_lineRLRR6R]RtretvalRZRRFR1RRR-R( R.RERRRRRRRR-RRR((RRs4           cCsy"t|dtdtdt}WnItj o}td|n&tj o}td|nX|i ||dS(sParse the configspec.R#R&R$sParsing configspec failed: %ssReading configspec failed: %sN( RR'RRRORteRRR.t_set_configspec_value(R.R'R((RRscCsd|ijo5|d|idRDRXR.R (R.R'RRD((RR s   c Csy|i}|i}Wntj oyg}|D]%} t|| t o || q2q2~}g}|D]%} t|| t p || qkqk~}nXd|jot |djo t nh}h}x"|D]} || }||| t scalar_keystAttributeErrorRnRDRUR:RRRQRRXR.t_handle_repeat( R.RR'R>RQR R?RnR RD((RRs8  9>       cCsSd||i|i|dt|id|i|i||i|fS(s.Write an individual line, for the write methods %s%s%s%s%sRs = N( t indent_stringR.RRRDRORRwR(R.RRDRwR((Rt _write_linescCsRd||id||i|i|dt|id||i|fS(sWrite a section marker lines %s%s%s%s%sRRRN( RR.RR=RRRDROR(R.RR=RDR((Rt _write_markerscCsq|pdSn|idjo|id}n|idt}|idp|td7}n||S(sM Deal with a comment. >>> filename = a.filename >>> a.filename = None >>> values = a.write() >>> index = 0 >>> while index < 23: ... index += 1 ... line = values[index-1] ... assert line.endswith('# comment ' + str(index)) >>> a.filename = filename >>> start_comment = ['# Initial Comment', '', '#'] >>> end_comment = ['', '#', '# Final Comment'] >>> newconfig = start_comment + testconfig1.split('\n') + end_comment >>> nc = ConfigObj(newconfig) >>> nc.initial_comment ['# Initial Comment', '', '#'] >>> nc.final_comment ['', '#', '# Final Comment'] >>> nc.initial_comment == start_comment 1 >>> nc.final_comment == end_comment 1 R,s R!Rs# N(RR.R)RtstartRR(R.RR((Rt_handle_comment scCs^|idjodSn|idjo d|Sn|idjodt|SntdS(sW Compute the indent string, according to current indent_type and depth R,s R!N(R.R)R=RR1(R.R=((Rt_compute_indent_string/s cCs:|idjo t|_ng}|id}|id} |djo~|i }t |_ |}xc|i D]T} |i| } | i}|o|i| o| | } n|i| qpWn|i|i|i} x!|i|iD]}||ijoqnxa|i|D]R}|i|i}|o|i| o| |}n|i| |q#W||}|i|i|}t!|t"o?|i|i#| |i|||i$|i%d|q|i|i&| |||qW||joox_|i'D]T} |i| } | i}|o|i| o| | } n|i| q"W||_ n||j o|Sn|i(djo|djo|i*o1g}|D]}||i-|i*q~}n|i.o]|i*djpt/i0|i*i1djo.|p|idnt2|d|d>> filename = a.filename >>> a.filename = 'test.ini' >>> a.write() >>> a.filename = filename >>> a == ConfigObj('test.ini', raise_errors=True) 1 >>> os.remove('test.ini') >>> b.filename = 'test.ini' >>> b.write() >>> b == ConfigObj('test.ini', raise_errors=True) 1 >>> os.remove('test.ini') >>> i.filename = 'test.ini' >>> i.write() >>> i == ConfigObj('test.ini', raise_errors=True) 1 >>> os.remove('test.ini') >>> a = ConfigObj() >>> a['DEFAULT'] = {'a' : 'fish'} >>> a['a'] = '%(a)s' >>> a.write() ['a = %(a)s', '[DEFAULT]', 'a = fish'] Rs# RRR,iRN(;R.R)R6RRRtcstcspRR"tint_valRORR-RRt stripped_lineRRZRR=RR>R?RDRCRAt comment_linetlstripRwRRBRRUR:RtextendRRRRtoutfileR*RntlRRRRPRtBOM_UTF8RRtlinesepRstoutputRRR(R.RRRRwRRRRRRR R-RRRRnRD((RR>s              19% 9  cCsJ|tjoO|itjo tdn|o!ttjotdnn|}n|i}d|ijo6|d} x%|i D]}|i ||| qWnh}t} t}x|D]}|djoqn||ij p ||ijot} t}nt} ||}y |i|||d| }WnT|ij oE} | p t| tot||>> try: ... from validate import Validator ... except ImportError: ... print >> sys.stderr, 'Cannot import the Validator object, skipping the related tests' ... else: ... config = ''' ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [section] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [[sub section]] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... '''.split('\n') ... configspec = ''' ... test1= integer(30,50) ... test2= string ... test3=integer ... test4=float(6.0) ... [section ] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... [[sub section]] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... '''.split('\n') ... val = Validator() ... c1 = ConfigObj(config, configspec=configspec) ... test = c1.validate(val) ... test == { ... 'test1': True, ... 'test2': True, ... 'test3': True, ... 'test4': False, ... 'section': { ... 'test1': True, ... 'test2': True, ... 'test3': True, ... 'test4': False, ... 'sub section': { ... 'test1': True, ... 'test2': True, ... 'test3': True, ... 'test4': False, ... }, ... }, ... } 1 >>> val.check(c1.configspec['test4'], c1['test4']) Traceback (most recent call last): VdtValueTooSmallError: the value "5.0" is too small. >>> val_test_config = ''' ... key = 0 ... key2 = 1.1 ... [section] ... key = some text ... key2 = 1.1, 3.0, 17, 6.8 ... [[sub-section]] ... key = option1 ... key2 = True'''.split('\n') >>> val_test_configspec = ''' ... key = integer ... key2 = float ... [section] ... key = string ... key2 = float_list(4) ... [[sub-section]] ... key = option(option1, option2) ... key2 = boolean'''.split('\n') >>> val_test = ConfigObj(val_test_config, configspec=val_test_configspec) >>> val_test.validate(val) 1 >>> val_test['key'] = 'text not a digit' >>> val_res = val_test.validate(val) >>> val_res == {'key2': True, 'section': True, 'key': False} 1 >>> configspec = ''' ... test1=integer(30,50, default=40) ... test2=string(default="hello") ... test3=integer(default=3) ... test4=float(6.0, default=6.0) ... [section ] ... test1=integer(30,50, default=40) ... test2=string(default="hello") ... test3=integer(default=3) ... test4=float(6.0, default=6.0) ... [[sub section]] ... test1=integer(30,50, default=40) ... test2=string(default="hello") ... test3=integer(default=3) ... test4=float(6.0, default=6.0) ... '''.split('\n') >>> default_test = ConfigObj(['test1=30'], configspec=configspec) >>> default_test {'test1': '30', 'section': {'sub section': {}}} >>> default_test.validate(val) 1 >>> default_test == { ... 'test1': 30, ... 'test2': 'hello', ... 'test3': 3, ... 'test4': 6.0, ... 'section': { ... 'test1': 40, ... 'test2': 'hello', ... 'test3': 3, ... 'test4': 6.0, ... 'sub section': { ... 'test1': 40, ... 'test3': 3, ... 'test2': 'hello', ... 'test4': 6.0, ... }, ... }, ... } 1 Now testing with repeated sections : BIG TEST >>> repeated_1 = ''' ... [dogs] ... [[__many__]] # spec for a dog ... fleas = boolean(default=True) ... tail = option(long, short, default=long) ... name = string(default=rover) ... [[[__many__]]] # spec for a puppy ... name = string(default="son of rover") ... age = float(default=0.0) ... [cats] ... [[__many__]] # spec for a cat ... fleas = boolean(default=True) ... tail = option(long, short, default=short) ... name = string(default=pussy) ... [[[__many__]]] # spec for a kitten ... name = string(default="son of pussy") ... age = float(default=0.0) ... '''.split('\n') >>> repeated_2 = ''' ... [dogs] ... ... # blank dogs with puppies ... # should be filled in by the configspec ... [[dog1]] ... [[[puppy1]]] ... [[[puppy2]]] ... [[[puppy3]]] ... [[dog2]] ... [[[puppy1]]] ... [[[puppy2]]] ... [[[puppy3]]] ... [[dog3]] ... [[[puppy1]]] ... [[[puppy2]]] ... [[[puppy3]]] ... [cats] ... ... # blank cats with kittens ... # should be filled in by the configspec ... [[cat1]] ... [[[kitten1]]] ... [[[kitten2]]] ... [[[kitten3]]] ... [[cat2]] ... [[[kitten1]]] ... [[[kitten2]]] ... [[[kitten3]]] ... [[cat3]] ... [[[kitten1]]] ... [[[kitten2]]] ... [[[kitten3]]] ... '''.split('\n') >>> repeated_3 = ''' ... [dogs] ... ... [[dog1]] ... [[dog2]] ... [[dog3]] ... [cats] ... ... [[cat1]] ... [[cat2]] ... [[cat3]] ... '''.split('\n') >>> repeated_4 = ''' ... [__many__] ... ... name = string(default=Michael) ... age = float(default=0.0) ... sex = option(m, f, default=m) ... '''.split('\n') >>> repeated_5 = ''' ... [cats] ... [[__many__]] ... fleas = boolean(default=True) ... tail = option(long, short, default=short) ... name = string(default=pussy) ... [[[description]]] ... height = float(default=3.3) ... weight = float(default=6) ... [[[[coat]]]] ... fur = option(black, grey, brown, "tortoise shell", default=black) ... condition = integer(0,10, default=5) ... '''.split('\n') >>> from validate import Validator >>> val= Validator() >>> repeater = ConfigObj(repeated_2, configspec=repeated_1) >>> repeater.validate(val) 1 >>> repeater == { ... 'dogs': { ... 'dog1': { ... 'fleas': True, ... 'tail': 'long', ... 'name': 'rover', ... 'puppy1': {'name': 'son of rover', 'age': 0.0}, ... 'puppy2': {'name': 'son of rover', 'age': 0.0}, ... 'puppy3': {'name': 'son of rover', 'age': 0.0}, ... }, ... 'dog2': { ... 'fleas': True, ... 'tail': 'long', ... 'name': 'rover', ... 'puppy1': {'name': 'son of rover', 'age': 0.0}, ... 'puppy2': {'name': 'son of rover', 'age': 0.0}, ... 'puppy3': {'name': 'son of rover', 'age': 0.0}, ... }, ... 'dog3': { ... 'fleas': True, ... 'tail': 'long', ... 'name': 'rover', ... 'puppy1': {'name': 'son of rover', 'age': 0.0}, ... 'puppy2': {'name': 'son of rover', 'age': 0.0}, ... 'puppy3': {'name': 'son of rover', 'age': 0.0}, ... }, ... }, ... 'cats': { ... 'cat1': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'kitten1': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten2': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten3': {'name': 'son of pussy', 'age': 0.0}, ... }, ... 'cat2': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'kitten1': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten2': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten3': {'name': 'son of pussy', 'age': 0.0}, ... }, ... 'cat3': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'kitten1': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten2': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten3': {'name': 'son of pussy', 'age': 0.0}, ... }, ... }, ... } 1 >>> repeater = ConfigObj(repeated_3, configspec=repeated_1) >>> repeater.validate(val) 1 >>> repeater == { ... 'cats': { ... 'cat1': {'fleas': True, 'tail': 'short', 'name': 'pussy'}, ... 'cat2': {'fleas': True, 'tail': 'short', 'name': 'pussy'}, ... 'cat3': {'fleas': True, 'tail': 'short', 'name': 'pussy'}, ... }, ... 'dogs': { ... 'dog1': {'fleas': True, 'tail': 'long', 'name': 'rover'}, ... 'dog2': {'fleas': True, 'tail': 'long', 'name': 'rover'}, ... 'dog3': {'fleas': True, 'tail': 'long', 'name': 'rover'}, ... }, ... } 1 >>> repeater = ConfigObj(configspec=repeated_4) >>> repeater['Michael'] = {} >>> repeater.validate(val) 1 >>> repeater == { ... 'Michael': {'age': 0.0, 'name': 'Michael', 'sex': 'm'}, ... } 1 >>> repeater = ConfigObj(repeated_3, configspec=repeated_5) >>> repeater == { ... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}}, ... 'cats': {'cat1': {}, 'cat2': {}, 'cat3': {}}, ... } 1 >>> repeater.validate(val) 1 >>> repeater == { ... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}}, ... 'cats': { ... 'cat1': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'description': { ... 'weight': 6.0, ... 'height': 3.2999999999999998, ... 'coat': {'fur': 'black', 'condition': 5}, ... }, ... }, ... 'cat2': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'description': { ... 'weight': 6.0, ... 'height': 3.2999999999999998, ... 'coat': {'fur': 'black', 'condition': 5}, ... }, ... }, ... 'cat3': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'description': { ... 'weight': 6.0, ... 'height': 3.2999999999999998, ... 'coat': {'fur': 'black', 'condition': 5}, ... }, ... }, ... }, ... } 1 Test that interpolation is preserved for validated string values. Also check that interpolation works in configspecs. >>> t = ConfigObj() >>> t['DEFAULT'] = {} >>> t['DEFAULT']['test'] = 'a' >>> t['test'] = '%(test)s' >>> t['test'] 'a' >>> v = Validator() >>> t.configspec = {'test': 'string'} >>> t.validate(v) 1 >>> t.interpolation = False >>> t {'test': '%(test)s', 'DEFAULT': {'test': 'a'}} >>> specs = [ ... 'interpolated string = string(default="fuzzy-%(man)s")', ... '[DEFAULT]', ... 'man = wuzzy', ... ] >>> c = ConfigObj(configspec=specs) >>> c.validate(v) 1 >>> c['interpolated string'] 'fuzzy-wuzzy' FIXME: Above tests will fail if we couldn't import Validator (the ones that don't raise errors will produce different output and still fail as tests) sNo configspec supplied.sMissing validate module.R tmissingR,RKtpreserve_errorsRN(#RR6R.R'RWR"tVdtMissingValuet ImportErrort spec_sectiontmanyR?RDRRRRtret_truet ret_falseR>RCR!RQROt validatortchecktbaseErrorClassRRUR(R]R^RnR RRZtvalidate(R.R)R"RR%RRQR*R(R!R'RR&RnR RD((RR,s        !       .        (*R3R4R5RRtVERBOSERRRRRt_single_line_singlet_single_line_doublet_multi_line_singlet_multi_line_doubleRRRRORR6R2RRRRRRRRRRRRRR RRRRRRR,(((RR9sN         $Nv e       E ~ 8    % vcBs#tZdZdZedZRS(s A simple validator. Can be used to check that all members expected are present. To use it, provide a configspec with all your members in (the value given will be ignored). Pass an instance of ``SimpleVal`` to the ``validate`` method of your ``ConfigObj``. ``validate`` will return ``True`` if all members are present, or a dictionary with True/False meaning present/missing. (Whole missing sections will be replaced with ``False``) >>> val = SimpleVal() >>> config = ''' ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [section] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [[sub section]] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... '''.split('\n') >>> configspec = ''' ... test1='' ... test2='' ... test3='' ... test4='' ... [section] ... test1='' ... test2='' ... test3='' ... test4='' ... [[sub section]] ... test1='' ... test2='' ... test3='' ... test4='' ... '''.split('\n') >>> o = ConfigObj(config, configspec=configspec) >>> o.validate(val) 1 >>> o = ConfigObj(configspec=configspec) >>> o.validate(val) 0 cCs t|_dS(N(RR.R+(R.((RR2 scCs|o |in|S(s9A dummy check method, always returns the value unchanged.N(R!R.R+tmember(R.R*R2R!((RR* s (R3R4R5R2ROR*(((RR s 2 cCs|djog}g}n|tjo|Sn|tjo4|i|dtf|o|in|Snx|iD]{\}}|tjoqnt |i |to+|i|t|||||qn|i|||fqW|o|in|S(s An example function that will turn a nested dictionary of results (as returned by ``ConfigObj.validate``) into a flat list. ``cfg`` is the ConfigObj instance being checked, ``res`` is the results dictionary returned by ``validate``. (This is a recursive function, so you shouldn't use the ``levels`` or ``results`` arguments - they are used by the function. Returns a list of keys that failed. Each member of the list is a tuple : :: ([list of sections...], key, result) If ``validate`` was called with ``preserve_errors=False`` (the default) then ``result`` will always be ``False``. *list of sections* is a flattened list of sections that the key was found in. If the section was missing then key will be ``None``. If the value (or section) was missing then ``result`` will be ``False``. If ``validate`` was called with ``preserve_errors=True`` and a value was present, but failed the check, then ``result`` will be the exception object returned. You can use this as a string that describes the failure. For example *The value "3" is of the wrong type*. # FIXME: is the ordering of the output arbitrary ? >>> import validate >>> vtor = validate.Validator() >>> my_ini = ''' ... option1 = True ... [section1] ... option1 = True ... [section2] ... another_option = Probably ... [section3] ... another_option = True ... [[section3b]] ... value = 3 ... value2 = a ... value3 = 11 ... ''' >>> my_cfg = ''' ... option1 = boolean() ... option2 = boolean() ... option3 = boolean(default=Bad_value) ... [section1] ... option1 = boolean() ... option2 = boolean() ... option3 = boolean(default=Bad_value) ... [section2] ... another_option = boolean() ... [section3] ... another_option = boolean() ... [[section3b]] ... value = integer ... value2 = integer ... value3 = integer(0, 10) ... [[[section3b-sub]]] ... value = string ... [section4] ... another_option = boolean() ... ''' >>> cs = my_cfg.split('\n') >>> ini = my_ini.split('\n') >>> cfg = ConfigObj(ini, configspec=cs) >>> res = cfg.validate(vtor, preserve_errors=True) >>> errors = [] >>> for entry in flatten_errors(cfg, res): ... section_list, key, error = entry ... section_list.insert(0, '[root]') ... if key is not None: ... section_list.append(key) ... else: ... section_list.append('[missing]') ... section_string = ', '.join(section_list) ... errors.append((section_string, ' = ', error)) >>> errors.sort() >>> for entry in errors: ... print entry[0], entry[1], (entry[2] or 0) [root], option2 = 0 [root], option3 = the value "Bad_value" is of the wrong type. [root], section1, option2 = 0 [root], section1, option3 = the value "Bad_value" is of the wrong type. [root], section2, another_option = the value "Probably" is of the wrong type. [root], section3, section3b, section3b-sub, [missing] = 0 [root], section3, section3b, value2 = the value "a" is of the wrong type. [root], section3, section3b, value3 = the value "11" is too big. [root], section4, [missing] = 0 N(tlevelsR6tresultstresRRRORZRdRlRTRQRUtcfgRPR:R (R6R5R3R4RQRT((RR s._       cCsdS(s Dummy function to hold some of the doctests. >>> a.depth 0 >>> a == { ... 'key2': 'val', ... 'key1': 'val', ... 'lev1c': { ... 'lev2c': { ... 'lev3c': { ... 'key1': 'val', ... }, ... }, ... }, ... 'lev1b': { ... 'key2': 'val', ... 'key1': 'val', ... 'lev2ba': { ... 'key1': 'val', ... }, ... 'lev2bb': { ... 'key1': 'val', ... }, ... }, ... 'lev1a': { ... 'key2': 'val', ... 'key1': 'val', ... }, ... } 1 >>> b.depth 0 >>> b == { ... 'key3': 'val3', ... 'key2': 'val2', ... 'key1': 'val1', ... 'section 1': { ... 'keys11': 'val1', ... 'keys13': 'val3', ... 'keys12': 'val2', ... }, ... 'section 2': { ... 'section 2 sub 1': { ... 'fish': '3', ... }, ... 'keys21': 'val1', ... 'keys22': 'val2', ... 'keys23': 'val3', ... }, ... } 1 >>> t = ''' ... 'a' = b # !"$%^&*(),::;'@~#= 33 ... "b" = b #= 6, 33 ... ''' .split('\n') >>> t2 = ConfigObj(t) >>> assert t2 == {'a': 'b', 'b': 'b'} >>> t2.inline_comments['b'] = '' >>> del t2['a'] >>> assert t2.write() == ['','b = b', ''] # Test ``list_values=False`` stuff >>> c = ''' ... key1 = no quotes ... key2 = 'single quotes' ... key3 = "double quotes" ... key4 = "list", 'with', several, "quotes" ... ''' >>> cfg = ConfigObj(c.splitlines(), list_values=False) >>> cfg == {'key1': 'no quotes', 'key2': "'single quotes'", ... 'key3': '"double quotes"', ... 'key4': '"list", \'with\', several, "quotes"' ... } 1 >>> cfg = ConfigObj(list_values=False) >>> cfg['key1'] = 'Multiline\nValue' >>> cfg['key2'] = '''"Value" with 'quotes' !''' >>> cfg.write() ["key1 = '''Multiline\nValue'''", 'key2 = "Value" with \'quotes\' !'] >>> cfg.list_values = True >>> cfg.write() == ["key1 = '''Multiline\nValue'''", ... 'key2 = \'\'\'"Value" with \'quotes\' !\'\'\''] 1 Test flatten_errors: >>> from validate import Validator, VdtValueTooSmallError >>> config = ''' ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [section] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [[sub section]] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... '''.split('\n') >>> configspec = ''' ... test1= integer(30,50) ... test2= string ... test3=integer ... test4=float(6.0) ... [section ] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... [[sub section]] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... '''.split('\n') >>> val = Validator() >>> c1 = ConfigObj(config, configspec=configspec) >>> res = c1.validate(val) >>> flatten_errors(c1, res) == [([], 'test4', False), (['section', ... 'sub section'], 'test4', False), (['section'], 'test4', False)] True >>> res = c1.validate(val, preserve_errors=True) >>> check = flatten_errors(c1, res) >>> check[0][:2] ([], 'test4') >>> check[1][:2] (['section', 'sub section'], 'test4') >>> check[2][:2] (['section'], 'test4') >>> for entry in check: ... isinstance(entry[2], VdtValueTooSmallError) ... print str(entry[2]) True the value "5.0" is too small. True the value "5.0" is too small. True the value "5.0" is too small. Test unicode handling, BOM, write witha file like object and line endings : >>> u_base = ''' ... # initial comment ... # inital comment 2 ... ... test1 = some value ... # comment ... test2 = another value # inline comment ... # section comment ... [section] # inline comment ... test = test # another inline comment ... test2 = test2 ... ... # final comment ... # final comment2 ... ''' >>> u = u_base.encode('utf_8').splitlines(True) >>> u[0] = BOM_UTF8 + u[0] >>> uc = ConfigObj(u) >>> uc.encoding = None >>> uc.BOM == True 1 >>> uc == {'test1': 'some value', 'test2': 'another value', ... 'section': {'test': 'test', 'test2': 'test2'}} 1 >>> uc = ConfigObj(u, encoding='utf_8', default_encoding='latin-1') >>> uc.BOM 1 >>> isinstance(uc['test1'], unicode) 1 >>> uc.encoding 'utf_8' >>> uc.newlines '\n' >>> uc['latin1'] = "This costs lot's of " >>> a_list = uc.write() >>> len(a_list) 15 >>> isinstance(a_list[0], str) 1 >>> a_list[0].startswith(BOM_UTF8) 1 >>> u = u_base.replace('\n', '\r\n').encode('utf_8').splitlines(True) >>> uc = ConfigObj(u) >>> uc.newlines '\r\n' >>> uc.newlines = '\r' >>> from cStringIO import StringIO >>> file_like = StringIO() >>> uc.write(file_like) >>> file_like.seek(0) >>> uc2 = ConfigObj(file_like) >>> uc2 == uc 1 >>> uc2.filename == None 1 >>> uc2.newlines == '\r' 1 N((((Rt_doctest` st__main__sy key1= val # comment 1 key2= val # comment 2 # comment 3 [lev1a] # comment 4 key1= val # comment 5 key2= val # comment 6 # comment 7 [lev1b] # comment 8 key1= val # comment 9 key2= val # comment 10 # comment 11 [[lev2ba]] # comment 12 key1= val # comment 13 # comment 14 [[lev2bb]] # comment 15 key1= val # comment 16 # comment 17 [lev1c] # comment 18 # comment 19 [[lev2c]] # comment 20 # comment 21 [[[lev3c]]] # comment 22 key1 = val # comment 23s key1 = 'val1' key2 = "val2" key3 = val3 ["section 1"] # comment keys11 = val1 keys12 = val2 keys13 = val3 [section 2] keys21 = val1 keys22 = val2 keys23 = val3 [['section 2 sub 1']] fish = 3 sR name1 = """ a single line value """ # comment name2 = ''' another single line value ''' # comment name3 = """ a single line value """ name4 = ''' another single line value ''' [ "multi section" ] name1 = """ Well, this is a multiline value """ name2 = ''' Well, this is a multiline value ''' name3 = """ Well, this is a multiline value """ # a comment name4 = ''' Well, this is a multiline value ''' # I guess this is a comment too s tINTP_VERtatbR tglobs(Ft __future__t generatorstsyst version_infoR9t RuntimeErrorRRttypesRVtwarningsRtcodecsRt BOM_UTF16t BOM_UTF16_BEt BOM_UTF16_LER6RRRR,R#R$Rt NameErrorRRRORt __revision__Rt__all__RRRRR1RRRRRRRRRR:R8RtobjectRR R7R3t testconfig1t testconfig2t testconfig6tdoctesttmodulesRPtmt__dict__RR<tsplitR:R;R Rcttestmod(1RRRRRMRGRRNRRRR<R RRIRJRR;RR#R>RVRRRRRLRR:R9RRRRRQRRERR?RRROR RRRFROR7RR8((Rt?s     B 3 9`       Eo>  1m fFc@sdklZdkZeid ZeddfjoedndkZdkZdkl Z dk l Z dk l Z lZlZlZhe def<edd f<ed d f<ed d fYZ(d%e%fd?YZ)d(e%fd@YZ*d)e*fdAYZ+d+e%fdBYZ,d*e*fdCYZ-dDe.fdEYZ/d&e/fdFYZ0d'e1fdGYZ2eedHZ3dIZ4e5dJjodKZ6dLZ7dMZ8dk9Z9ei:i;dJZ<e<i=i>Z?e0e6i@dNd2eZAe0e7i@dNd2eZBe0e8i@dNd2eZCe?iDhdOe<dPeA<dQeB<dReC<e9iEe<dSe?ndS(T(s generatorsNisPython v.2.2 or later needed(s StringTypes(swarn(sBOM_UTF8s BOM_UTF16s BOM_UTF16_BEs BOM_UTF16_LEtutf_8tutf16_betutf_16tutf16_letu16tutf16sutf-16t utf_16_besutf-16bet utf_16_lesutf-16letu8tutftutf8sutf-8(sVdtMissingValueccs/d}x"|D]}|d7}||fVq WdS(senumerate for Python 2.2.iiN(titobjtitem(R R R ((t/usr/bin/configobj.pyt enumerate]s  iis4.2.0s5$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $srestructuredtext ent __version__tDEFAULT_INDENT_TYPEtNUM_INDENT_SPACEStMAX_INTERPOL_DEPTHtConfigObjErrort NestingErrort ParseErrortDuplicateErrortConfigspecErrort ConfigObjt SimpleValtInterpolationErrortInterpolationDepthErrortMissingInterpolationOptiontRepeatSectionErrort __docformat__tflatten_errorst ii t interpolationt raise_errorst list_valuest create_emptyt file_errort configspect stringifyt indent_typetencodingtdefault_encodingcBs tZdZdeddZRS(s This is the base class for all errors that ConfigObj raises. It is a subclass of SyntaxError. >>> raise ConfigObjError Traceback (most recent call last): ConfigObjError tcCs/||_||_||_ti||dS(N(tlinetselft line_numbertmessaget SyntaxErrort__init__(R.R0R/R-((RR2s   (t__name__t __module__t__doc__tNoneR2(((RRs cBstZdZRS(s This error indicates a level of nesting that doesn't match. >>> raise NestingError Traceback (most recent call last): NestingError (R3R4R5(((RRs cBstZdZRS(s This error indicates that a line is badly written. It is neither a valid ``key = value`` line, nor a valid section marker line. >>> raise ParseError Traceback (most recent call last): ParseError (R3R4R5(((RRs cBstZdZRS(s The keyword or section specified already exists. >>> raise DuplicateError Traceback (most recent call last): DuplicateError (R3R4R5(((RRs cBstZdZRS(s An error occured whilst parsing a configspec. >>> raise ConfigspecError Traceback (most recent call last): ConfigspecError (R3R4R5(((RRs cBstZdZRS(s,Base class for the two interpolation errors.(R3R4R5(((RRs cBstZdZdZRS(s=Maximum interpolation depth exceeded in string interpolation.cCsti|d|dS(s >>> raise InterpolationDepthError('yoda') Traceback (most recent call last): InterpolationDepthError: max interpolation depth exceeded in value "yoda". s/max interpolation depth exceeded in value "%s".N(RR2R.toption(R.R7((RR2s (R3R4R5R2(((RRs cBstZdZRS(s This error indicates additional sections in a section with a ``__many__`` (repeated) section. >>> raise RepeatSectionError Traceback (most recent call last): RepeatSectionError (R3R4R5(((RRs cBstZdZdZRS(s0A value specified for interpolation was missing.cCsti|d|dS(s >>> raise MissingInterpolationOption('yoda') Traceback (most recent call last): MissingInterpolationOption: missing option "yoda" in interpolation. s%missing option "%s" in interpolation.N(RR2R.R7(R.R7((RR2s (R3R4R5R2(((RRs tSectioncBs@tZdZeidZeedZdZdZ dZ dZ dZ edZ d Zd Zd Zd Zed ZdZdZdZdZdZeZdZdZeZdZdZdZee dZ!dZ"dZ#dZ$dZ%dZ&dZ'RS(sO A dictionary-like object that represents a section in a config file. It does string interpolation if the 'interpolate' attribute of the 'main' object is set to True. Interpolation is tried first from the 'DEFAULT' section of this object, next from the 'DEFAULT' section of the parent, lastly the main object. A Section will behave like an ordered dictionary - following the order of the ``scalars`` and ``sections`` attributes. You can use this to change the order of members. Iteration follows the order: scalars, then sections. s%\(([^)]*)\)s|.cCs|djo h}nti|||_||_||_g|_g|_ ||_ h|_ h|_ h|_ g|_x|D]}||||R(tlistttupleRDt TypeError(R.RTRER\RD((RR[VsF     cCs\ti||||ijo|ii|n|ii||i|=|i|=dS(s-Remove items from the sequence when deleting.N( R:t __delitem__R.RTR>RYR?RARB(R.RT((RR`s cCs*y ||SWntj o |SnXdS(s>A version of ``get`` that doesn't bypass string interpolation.N(R.RTtKeyErrortdefault(R.RTRb((RRPs  cCs#x|D]}||||RARBRYR?R<R"RURVRJ(R.RTReRQ((RRds    cCsI|i|i}|p tdn|d}||}||=||fS(sPops the first (key,val)s": 'popitem(): dictionary is empty'iN(R.R>R?tsequenceRaRTRQ(R.RQRTRf((Rtpopitems   cCs>ti|g|_g|_h|_h|_h|_dS(s A version of clear that also affects scalars/sections Also clears comments and configspec. Leaves other attributes alone : depth/main/parent are not affected N(R:tclearR.R>R?RARBR'(R.((RRhs     cCs8y ||SWn%tj o|||<||SnXdS(s:A version of setdefault that sets sequence if appropriate.N(R.RTRaRb(R.RTRb((Rt setdefaults   cCst|i|i|iS(R!N(tzipR.R>R?tvalues(R.((RtitemsscCs|i|iS(R!N(R.R>R?(R.((RtkeysscCs-g}|i|iD]}|||q~S(R!N(t_[1]R.R>R?RT(R.RnRT((RRkscCst|iS(R!N(titerR.Rl(R.((Rt iteritemsscCst|i|iS(R!N(RoR.R>R?(R.((RtiterkeysscCst|iS(R!N(RoR.Rk(R.((Rt itervaluessc CsPddig}|i|iD]'}|dt|t||fq~S(Ns{%s}s, s%s: %s(tjoinRnR.R>R?RTtrepr(R.RnRT((Rt__repr__scCsuh}xh|D]`}||}t|to|i}n't|ttfot|}n|||>> n = a.dict() >>> n == a 1 >>> n is a 0 N( tnewdictR.RDt this_entryRUR8R:R]R^(R.RvRwRD((RR:s  cCsqxj|iD]\\}}||jo9t||to%t|to||i|q |||>> a = '''[section1] ... option1 = True ... [[subsection]] ... more_options = False ... # end of file'''.splitlines() >>> b = '''# File is user.ini ... [section1] ... option1 = False ... # end of file'''.splitlines() >>> c1 = ConfigObj(b) >>> c2 = ConfigObj(a) >>> c2.merge(c1) >>> c2 {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}} N(R9RlRTRQR.RUR:tmerge(R.R9RQRT((RRxs  1cCs||ijo |i}n+||ijo |i}ntd||i|}||}t i ||t i ||||i ||i|||i|}|i|}|i|=|i|=||i|<||i|tthe_listR?RatindextposRQR:R`R[tnewkeyRYtinsertRAtcommRBtinline_comment(R.RyR}RRQRR|Rz((Rtrename*s$          c KsYh}xtt|iD]{}|i|}y-||||}|i|}|||>> config = '''[XXXXsection] ... XXXXkey = XXXXvalue'''.splitlines() >>> cfg = ConfigObj(config) >>> cfg {'XXXXsection': {'XXXXkey': 'XXXXvalue'}} >>> def transform(section, key): ... val = section[key] ... newkey = key.replace('XXXX', 'CLIENT1') ... section.rename(key, newkey) ... if isinstance(val, (tuple, list, dict)): ... pass ... else: ... val = val.replace('XXXX', 'CLIENT1') ... section[newkey] = val >>> cfg.walk(transform, call_on_sections=True) {'CLIENT1section': {'CLIENT1key': None}} >>> cfg {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}} R#tcall_on_sectionsN(touttrangetlenR.R>R RDtfunctiontkeywargsRQt ExceptionR#ROR?Rtwalk( R.RR#RRRQR RDR((RRGs<.      cCs#|d}|i|dtdS(sK Decode all strings and values to unicode, using the specified encoding. Works with subsections and list values. Uses the ``walk`` method. Testing ``encode`` and ``decode``. >>> m = ConfigObj(a) >>> m.decode('ascii') >>> def testuni(val): ... for entry in val: ... if not isinstance(entry, unicode): ... print >> sys.stderr, type(entry) ... raise AssertionError, 'decode failed.' ... if isinstance(val[entry], dict): ... testuni(val[entry]) ... elif not isinstance(val[entry], unicode): ... raise AssertionError, 'decode failed.' >>> testuni(m) >>> m.encode('ascii') >>> a == m 1 cCs||}t|ttfo1g}xQ|D]}|i|i |q-Wn*t|t o |}n|i |}|i |}|i |||||>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_bool('a') Traceback (most recent call last): ValueError: Value "fish" is neither True nor False >>> a['b'] = 'True' >>> a.as_bool('b') 1 >>> a['b'] = 'off' >>> a.as_bool('b') 0 s$Value "%s" is neither True nor FalseN( R.RTRQRRRORURVRaR<t_boolstlowerRW(R.RTRQ((RRs    cCst||S(sK A convenience method which coerces the specified value to an integer. If the value is an invalid literal for ``int``, a ``ValueError`` will be raised. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_int('a') Traceback (most recent call last): ValueError: invalid literal for int(): fish >>> a['b'] = '1' >>> a.as_int('b') 1 >>> a['b'] = '3.2' >>> a.as_int('b') Traceback (most recent call last): ValueError: invalid literal for int(): 3.2 N(tintR.RT(R.RT((Rtas_int scCst||S(s A convenience method which coerces the specified value to a float. If the value is an invalid literal for ``float``, a ``ValueError`` will be raised. >>> a = ConfigObj() >>> a['a'] = 'fish' >>> a.as_float('a') Traceback (most recent call last): ValueError: invalid literal for float(): fish >>> a['b'] = '1' >>> a.as_float('b') 1.0 >>> a['b'] = '3.2' >>> a.as_float('b') 3.2000000000000002 N(tfloatR.RT(R.RT((Rtas_float#s((R3R4R5tretcompileRGR6R2RJRIRSR[R`RPRcRdRgRhRiRlRmRkRpRqt__iter__RrRut__str__R:RxRRRRORRRRRRR(((RR8sB #    7               T *   * cBstZdZeideiZeideiZeideiZeideiZ eideiZ eidZ eidZ eidZ eid Zhd e e f<d e ef>> c = ''' ... [hello] ... member = value ... [hello again] ... member = value ... [ "hello" ] ... member = value ... ''' >>> ConfigObj(c.split('\n'), raise_errors = True) Traceback (most recent call last): DuplicateError: Duplicate section name at line 5. >>> d = ''' ... [hello] ... member = value ... [hello again] ... member1 = value ... member2 = value ... 'member1' = value ... [ "and again" ] ... member = value ... ''' >>> ConfigObj(d.split('\n'), raise_errors = True) Traceback (most recent call last): DuplicateError: Duplicate keyword name at line 6. s^ # line start (\s*) # indentation ( # keyword (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'"=].*?) # no quotes ) \s*=\s* # divider (.*) # value (including list values and comments) $ # line end s=^ (\s*) # 1: indentation ((?:\[\s*)+) # 2: section marker open ( # 3: section name open (?:"\s*\S.*?\s*")| # at least one non-space with double quotes (?:'\s*\S.*?\s*')| # at least one non-space with single quotes (?:[^'"\s].*?) # at least one non-space unquoted ) # section name close ((?:\s*\])+) # 4: section marker close \s*(\#.*)? # 5: optional comment $s^ (?: (?: ( (?: (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#][^,\#]*?) # unquoted ) \s*,\s* # comma )* # match all list items ending in a comma (if any) ) ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#\s][^,]*?) # unquoted )? # last item in a list - or string value )| (,) # alternatively a single comma - empty list ) \s*(\#.*)? # optional comment $s ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\#].*?) # unquoted ) \s*,\s* # comma s^ ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'"\#].*?) # unquoted ) \s*(\#.*)? # optional comment $s^'''(.*?)'''\s*(#.*)?$s^"""(.*?)"""\s*(#.*)?$s^(.*?)'''\s*(#.*)?$s^(.*?)"""\s*(#.*)?$s'''s"""tyestnotontofft1t0ttruetfalsec Ks|djo g}n|djo h}n|i|ti||d|ti }x8|i D]*} | |i jot d| qjqjW|i|d|_g|_|d|_|d|_|d|_|d|_|d|_|d|_|d |_|d |_|d |_t|_d|_g|_g|_t|to||_t i!i"|ot#|i$pg}q|iot%d |iq|io*t#|d }|i'd|i(ng}nt|t)t*fot)|}nt|t+o|t|t,o|i+}nx|D]} || || infile must be a filename, file like object, or list of lines.is s s sParsing failed.(s s s (;tinfileR6toptionsRctkwargsR8R2R.tOPTION_DEFAULTStcopyRCRmRDR_tfilenamet_errorsR#R"R$R%R&R(R)R*R+ROtBOMtnewlinestinitial_commentt final_commentRURVtostpathtisfiletopenRtIOErrorthtwritetcloseR]R^R:Rt_handle_configspecR'thasattrt _handle_bomR-tendtendswithRntrstript_parseRterrorterrorstconfig( R.RRRRR-RRnRCRRD((RR2s                                .       cCs}|idj o-|iitjo|i||iSnt|tt fo|d}n|}|idj ot|ii}|djolxRt i D]D\}\}}|pqn|i|o|i||SqqW|i||iSnt|}|i|p|i||iSn|t|}t|tt fo||d>> c = ConfigObj() >>> c['DEFAULT'] = { ... 'b': 'goodbye', ... 'userdir': 'c:\\home', ... 'c': '%(d)s', ... 'd': '%(c)s' ... } >>> c['section'] = { ... 'a': '%(datadir)s\\some path\\file.py', ... 'b': '%(userdir)s\\some path\\file.py', ... 'c': 'Yo %(a)s', ... 'd': '%(not_here)s', ... 'e': '%(c)s', ... } >>> c['section']['DEFAULT'] = { ... 'datadir': 'c:\\silly_test', ... 'a': 'hello - %(b)s', ... } >>> c['section']['a'] == 'c:\\silly_test\\some path\\file.py' 1 >>> c['section']['b'] == 'c:\\home\\some path\\file.py' 1 >>> c['section']['c'] == 'Yo hello - goodbye' 1 Switching Interpolation Off >>> c.interpolation = False >>> c['section']['a'] == '%(datadir)s\\some path\\file.py' 1 >>> c['section']['b'] == '%(userdir)s\\some path\\file.py' 1 >>> c['section']['c'] == 'Yo %(a)s' 1 Testing the interpolation errors. >>> c.interpolation = True >>> c['section']['d'] Traceback (most recent call last): MissingInterpolationOption: missing option "not_here" in interpolation. >>> c['section']['e'] Traceback (most recent call last): InterpolationDepthError: max interpolation depth exceeded in value "%(c)s". Testing our quoting. >>> i._quote('"""'''') Traceback (most recent call last): SyntaxError: EOF while scanning triple-quoted string >>> try: ... i._quote('\n', multiline=False) ... except ConfigObjError, e: ... e.msg 'Value "\n" cannot be safely quoted.' >>> k._quote(' "' ', multiline=False) Traceback (most recent call last): SyntaxError: EOL while scanning single-quoted string Testing with "stringify" off. >>> c.stringify = False >>> c['test'] = 1 Traceback (most recent call last): TypeError: Value is not a string "1". iit#it[t]s,Cannot compute the section depth at line %s.s(Cannot compute nesting level at line %s.sSection too nested at line %s.s"Duplicate section name at line %s.R@is"""s'''s Parse error in value at line %s.s"Duplicate keyword name at line %s.sInvalid line at line "%s".R,N(1t comment_listROt done_startR.t this_sectionRRtmaxlinet cur_indext reset_commentR-tstriptslineRRZRRRt_sectionmarkerRLtmatR6tgroupstindentt sect_opent sect_namet sect_closetcommentR)tcountt cur_deptht _handle_errorRR=t _match_depthR;R1t_unquoteRXRR8RBRAt_keywordRTREt _multilineRt _handle_valueR(R.RRRRRRRRRR;RRRTRR-RRRRE((RRsF                          %             cCs]x8||ijo'||ijo tn|i}qW|i|jo|SntdS(s Given a section and a depth level, walk back through the sections parents to see if the depth level matches a previous section. Return a reference to the right section, or raise a SyntaxError. N(R=tsectR;R1(R.RR=((RRs cCsN||}||}||||}|io |n|i i |dS(s Handle an error according to the error settings. Either raise the error or store it. The error will have occured at ``cur_index`` N( RRR-ttextR0t ErrorClassRR.R#RRZ(R.RRRRR0RR-((RRs    cCs;|d|djo"|ddjo|dd!}n|S(s%Return an unquoted version of a valueiit"t'iN(RR(RE(R.RE((RRs&c Csit|ttfo||pdSn3t|djo|i|ddtdSndig} |D]}| |i|dtqh~ Snt|t p+|i ot |}qtd|nd}d} d }d } d }d }|pd Sn|i o d|jp/|o$d|jo d|jp d|j o|ip |}qad|jotd|qa|d| jo(|d| jod|jo |}qad|jod|jotd|qad|jo |}qa| }nd|iddjo'|iddjotd|n|iddjo |}n|}||S(sC Return a safely quoted version of a value. Raise a ConfigObjError if the value cannot be safely quoted. If multiline is ``True`` (default) then use triple quotes if necessary. Don't quote values that don't need it. Recursively quote members of a list and return a comma joined list. Multiline is ``False`` for lists. Obey list syntax for empty and single member lists. If ``list_values=False`` then the value is only quoted if it contains a `` `` (is multiline). t,iit multilines, sValue "%s" is not a string.s'%s's"%s"s%ss '"s"""%s"""s'''%s'''s""s RRs#Value "%s" cannot be safely quoted.is"""s'''N(RURER]R^RR.t_quoteRORsRnRQRVR(RR_tsquottdquottnoquott wspace_plusttsquotttdquotR$RtquotRRF( R.RERRRQRRRRRRnR((RRsJ; G   /    , c Csr|ipI|ii|}|djo tn|i\}}||fSn|i i|}|djo tn|i\}}} }|djo|djo tn| dj og|fSn|dj o|i |}n|djo||fSn|ii|}g}|D]}||i |q+~}|dj o||g7}n||fS(s Given a value string, unquote, remove comment, handle lists. (including empty and single member lists) Testing list values. >>> testconfig3 = ''' ... a = , ... b = test, ... c = test1, test2 , test3 ... d = test1, test2, test3, ... ''' >>> d = ConfigObj(testconfig3.split('\n'), raise_errors=True) >>> d['a'] == [] 1 >>> d['b'] == ['test'] 1 >>> d['c'] == ['test1', 'test2', 'test3'] 1 >>> d['d'] == ['test1', 'test2', 'test3'] 1 Testing with list values off. >>> e = ConfigObj( ... testconfig3.split('\n'), ... raise_errors=True, ... list_values=False) >>> e['a'] == ',' 1 >>> e['b'] == 'test,' 1 >>> e['c'] == 'test1, test2 , test3' 1 >>> e['d'] == 'test1, test2, test3,' 1 Testing creating from a dictionary. >>> f = { ... 'key1': 'val1', ... 'key2': 'val2', ... 'section 1': { ... 'key1': 'val1', ... 'key2': 'val2', ... 'section 1b': { ... 'key1': 'val1', ... 'key2': 'val2', ... }, ... }, ... 'section 2': { ... 'key1': 'val1', ... 'key2': 'val2', ... 'section 2b': { ... 'key1': 'val1', ... 'key2': 'val2', ... }, ... }, ... 'key3': 'val3', ... } >>> g = ConfigObj(f) >>> f == g 1 Testing we correctly detect badly built list values (4 of them). >>> testconfig4 = ''' ... config = 3,4,, ... test = 3,,4 ... fish = ,, ... dummy = ,,hello, goodbye ... ''' >>> try: ... ConfigObj(testconfig4.split('\n')) ... except ConfigObjError, e: ... len(e.errors) 4 Testing we correctly detect badly quoted values (4 of them). >>> testconfig5 = ''' ... config = "hello # comment ... test = 'goodbye ... fish = 'goodbye # comment ... dummy = "hello again ... ''' >>> try: ... ConfigObj(testconfig5.split('\n')) ... except ConfigObjError, e: ... len(e.errors) 4 R,N(R.R$t _nolistvalueRLRERR6R1RRt _valueexptsinglet empty_listRt _listvalueexptfindallRzRnRQ( R.RERRRQR$RnRRzR((RRs0\         * c Cs@|d }|d}|i|d} |i|d} | i|}|dj o't |i } | i || Sn!|i|djo tnx[||joG|d7}|d7}||} | i|djo|| 7}qPqWt| i| }|djo tn|i \}}||||fS(s Extract the value, where we are in a multiline situation Testing multiline values. >>> i == { ... 'name4': ' another single line value ', ... 'multi section': { ... 'name4': '\n Well, this is a\n multiline ' ... 'value\n ', ... 'name2': '\n Well, this is a\n multiline ' ... 'value\n ', ... 'name3': '\n Well, this is a\n multiline ' ... 'value\n ', ... 'name1': '\n Well, this is a\n multiline ' ... 'value\n ', ... }, ... 'name2': ' another single line value ', ... 'name3': ' a single line value ', ... 'name1': ' a single line value ', ... } 1 iiiis N(RERtnewvalueR.t _triple_quotet single_linet multi_lineRLRR6R]RtretvalRZRRFR1RRR-R( R.RERRRRRRRR-RRR((RRs4           cCsy"t|dtdtdt}WnItj o}td|n&tj o}td|nX|i ||dS(sParse the configspec.R#R&R$sParsing configspec failed: %ssReading configspec failed: %sN( RR'RRRORteRRR.t_set_configspec_value(R.R'R((RRscCsd|ijo5|d|idRDRXR.R (R.R'RRD((RR s   c Csy|i}|i}Wntj oyg}|D]%} t|| t o || q2q2~}g}|D]%} t|| t p || qkqk~}nXd|jot |djo t nh}h}x"|D]} || }||| t scalar_keystAttributeErrorRnRDRUR:RRRQRRXR.t_handle_repeat( R.RR'R>RQR R?RnR RD((RRs8  9>       cCsSd||i|i|dt|id|i|i||i|fS(s.Write an individual line, for the write methods %s%s%s%s%sRs = N( t indent_stringR.RRRDRORRwR(R.RRDRwR((Rt _write_linescCsRd||id||i|i|dt|id||i|fS(sWrite a section marker lines %s%s%s%s%sRRRN( RR.RR=RRRDROR(R.RR=RDR((Rt _write_markerscCsq|pdSn|idjo|id}n|idt}|idp|td7}n||S(sM Deal with a comment. >>> filename = a.filename >>> a.filename = None >>> values = a.write() >>> index = 0 >>> while index < 23: ... index += 1 ... line = values[index-1] ... assert line.endswith('# comment ' + str(index)) >>> a.filename = filename >>> start_comment = ['# Initial Comment', '', '#'] >>> end_comment = ['', '#', '# Final Comment'] >>> newconfig = start_comment + testconfig1.split('\n') + end_comment >>> nc = ConfigObj(newconfig) >>> nc.initial_comment ['# Initial Comment', '', '#'] >>> nc.final_comment ['', '#', '# Final Comment'] >>> nc.initial_comment == start_comment 1 >>> nc.final_comment == end_comment 1 R,s R!Rs# N(RR.R)RtstartRR(R.RR((Rt_handle_comment scCs^|idjodSn|idjo d|Sn|idjodt|SntdS(sW Compute the indent string, according to current indent_type and depth R,s R!N(R.R)R=RR1(R.R=((Rt_compute_indent_string/s cCs:|idjo t|_ng}|id}|id} |djo~|i }t |_ |}xc|i D]T} |i| } | i}|o|i| o| | } n|i| qpWn|i|i|i} x!|i|iD]}||ijoqnxa|i|D]R}|i|i}|o|i| o| |}n|i| |q#W||}|i|i|}t!|t"o?|i|i#| |i|||i$|i%d|q|i|i&| |||qW||joox_|i'D]T} |i| } | i}|o|i| o| | } n|i| q"W||_ n||j o|Sn|i(djo|djo|i*o1g}|D]}||i-|i*q~}n|i.o]|i*djpt/i0|i*i1djo.|p|idnt2|d|d>> filename = a.filename >>> a.filename = 'test.ini' >>> a.write() >>> a.filename = filename >>> a == ConfigObj('test.ini', raise_errors=True) 1 >>> os.remove('test.ini') >>> b.filename = 'test.ini' >>> b.write() >>> b == ConfigObj('test.ini', raise_errors=True) 1 >>> os.remove('test.ini') >>> i.filename = 'test.ini' >>> i.write() >>> i == ConfigObj('test.ini', raise_errors=True) 1 >>> os.remove('test.ini') >>> a = ConfigObj() >>> a['DEFAULT'] = {'a' : 'fish'} >>> a['a'] = '%(a)s' >>> a.write() ['a = %(a)s', '[DEFAULT]', 'a = fish'] Rs# RRR,iRN(;R.R)R6RRRtcstcspRR"tint_valRORR-RRt stripped_lineRRZRR=RR>R?RDRCRAt comment_linetlstripRwRRBRRUR:RtextendRRRRtoutfileR*RntlRRRRPRtBOM_UTF8RRtlinesepRstoutputRRR(R.RRRRwRRRRRRR R-RRRRnRD((RR>s              19% 9  cCsJ|tjoO|itjo tdn|o!ttjotdnn|}n|i}d|ijo6|d} x%|i D]}|i ||| qWnh}t} t}x|D]}|djoqn||ij p ||ijot} t}nt} ||}y |i|||d| }WnT|ij oE} | p t| tot||>> try: ... from validate import Validator ... except ImportError: ... print >> sys.stderr, 'Cannot import the Validator object, skipping the related tests' ... else: ... config = ''' ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [section] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [[sub section]] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... '''.split('\n') ... configspec = ''' ... test1= integer(30,50) ... test2= string ... test3=integer ... test4=float(6.0) ... [section ] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... [[sub section]] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... '''.split('\n') ... val = Validator() ... c1 = ConfigObj(config, configspec=configspec) ... test = c1.validate(val) ... test == { ... 'test1': True, ... 'test2': True, ... 'test3': True, ... 'test4': False, ... 'section': { ... 'test1': True, ... 'test2': True, ... 'test3': True, ... 'test4': False, ... 'sub section': { ... 'test1': True, ... 'test2': True, ... 'test3': True, ... 'test4': False, ... }, ... }, ... } 1 >>> val.check(c1.configspec['test4'], c1['test4']) Traceback (most recent call last): VdtValueTooSmallError: the value "5.0" is too small. >>> val_test_config = ''' ... key = 0 ... key2 = 1.1 ... [section] ... key = some text ... key2 = 1.1, 3.0, 17, 6.8 ... [[sub-section]] ... key = option1 ... key2 = True'''.split('\n') >>> val_test_configspec = ''' ... key = integer ... key2 = float ... [section] ... key = string ... key2 = float_list(4) ... [[sub-section]] ... key = option(option1, option2) ... key2 = boolean'''.split('\n') >>> val_test = ConfigObj(val_test_config, configspec=val_test_configspec) >>> val_test.validate(val) 1 >>> val_test['key'] = 'text not a digit' >>> val_res = val_test.validate(val) >>> val_res == {'key2': True, 'section': True, 'key': False} 1 >>> configspec = ''' ... test1=integer(30,50, default=40) ... test2=string(default="hello") ... test3=integer(default=3) ... test4=float(6.0, default=6.0) ... [section ] ... test1=integer(30,50, default=40) ... test2=string(default="hello") ... test3=integer(default=3) ... test4=float(6.0, default=6.0) ... [[sub section]] ... test1=integer(30,50, default=40) ... test2=string(default="hello") ... test3=integer(default=3) ... test4=float(6.0, default=6.0) ... '''.split('\n') >>> default_test = ConfigObj(['test1=30'], configspec=configspec) >>> default_test {'test1': '30', 'section': {'sub section': {}}} >>> default_test.validate(val) 1 >>> default_test == { ... 'test1': 30, ... 'test2': 'hello', ... 'test3': 3, ... 'test4': 6.0, ... 'section': { ... 'test1': 40, ... 'test2': 'hello', ... 'test3': 3, ... 'test4': 6.0, ... 'sub section': { ... 'test1': 40, ... 'test3': 3, ... 'test2': 'hello', ... 'test4': 6.0, ... }, ... }, ... } 1 Now testing with repeated sections : BIG TEST >>> repeated_1 = ''' ... [dogs] ... [[__many__]] # spec for a dog ... fleas = boolean(default=True) ... tail = option(long, short, default=long) ... name = string(default=rover) ... [[[__many__]]] # spec for a puppy ... name = string(default="son of rover") ... age = float(default=0.0) ... [cats] ... [[__many__]] # spec for a cat ... fleas = boolean(default=True) ... tail = option(long, short, default=short) ... name = string(default=pussy) ... [[[__many__]]] # spec for a kitten ... name = string(default="son of pussy") ... age = float(default=0.0) ... '''.split('\n') >>> repeated_2 = ''' ... [dogs] ... ... # blank dogs with puppies ... # should be filled in by the configspec ... [[dog1]] ... [[[puppy1]]] ... [[[puppy2]]] ... [[[puppy3]]] ... [[dog2]] ... [[[puppy1]]] ... [[[puppy2]]] ... [[[puppy3]]] ... [[dog3]] ... [[[puppy1]]] ... [[[puppy2]]] ... [[[puppy3]]] ... [cats] ... ... # blank cats with kittens ... # should be filled in by the configspec ... [[cat1]] ... [[[kitten1]]] ... [[[kitten2]]] ... [[[kitten3]]] ... [[cat2]] ... [[[kitten1]]] ... [[[kitten2]]] ... [[[kitten3]]] ... [[cat3]] ... [[[kitten1]]] ... [[[kitten2]]] ... [[[kitten3]]] ... '''.split('\n') >>> repeated_3 = ''' ... [dogs] ... ... [[dog1]] ... [[dog2]] ... [[dog3]] ... [cats] ... ... [[cat1]] ... [[cat2]] ... [[cat3]] ... '''.split('\n') >>> repeated_4 = ''' ... [__many__] ... ... name = string(default=Michael) ... age = float(default=0.0) ... sex = option(m, f, default=m) ... '''.split('\n') >>> repeated_5 = ''' ... [cats] ... [[__many__]] ... fleas = boolean(default=True) ... tail = option(long, short, default=short) ... name = string(default=pussy) ... [[[description]]] ... height = float(default=3.3) ... weight = float(default=6) ... [[[[coat]]]] ... fur = option(black, grey, brown, "tortoise shell", default=black) ... condition = integer(0,10, default=5) ... '''.split('\n') >>> from validate import Validator >>> val= Validator() >>> repeater = ConfigObj(repeated_2, configspec=repeated_1) >>> repeater.validate(val) 1 >>> repeater == { ... 'dogs': { ... 'dog1': { ... 'fleas': True, ... 'tail': 'long', ... 'name': 'rover', ... 'puppy1': {'name': 'son of rover', 'age': 0.0}, ... 'puppy2': {'name': 'son of rover', 'age': 0.0}, ... 'puppy3': {'name': 'son of rover', 'age': 0.0}, ... }, ... 'dog2': { ... 'fleas': True, ... 'tail': 'long', ... 'name': 'rover', ... 'puppy1': {'name': 'son of rover', 'age': 0.0}, ... 'puppy2': {'name': 'son of rover', 'age': 0.0}, ... 'puppy3': {'name': 'son of rover', 'age': 0.0}, ... }, ... 'dog3': { ... 'fleas': True, ... 'tail': 'long', ... 'name': 'rover', ... 'puppy1': {'name': 'son of rover', 'age': 0.0}, ... 'puppy2': {'name': 'son of rover', 'age': 0.0}, ... 'puppy3': {'name': 'son of rover', 'age': 0.0}, ... }, ... }, ... 'cats': { ... 'cat1': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'kitten1': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten2': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten3': {'name': 'son of pussy', 'age': 0.0}, ... }, ... 'cat2': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'kitten1': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten2': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten3': {'name': 'son of pussy', 'age': 0.0}, ... }, ... 'cat3': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'kitten1': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten2': {'name': 'son of pussy', 'age': 0.0}, ... 'kitten3': {'name': 'son of pussy', 'age': 0.0}, ... }, ... }, ... } 1 >>> repeater = ConfigObj(repeated_3, configspec=repeated_1) >>> repeater.validate(val) 1 >>> repeater == { ... 'cats': { ... 'cat1': {'fleas': True, 'tail': 'short', 'name': 'pussy'}, ... 'cat2': {'fleas': True, 'tail': 'short', 'name': 'pussy'}, ... 'cat3': {'fleas': True, 'tail': 'short', 'name': 'pussy'}, ... }, ... 'dogs': { ... 'dog1': {'fleas': True, 'tail': 'long', 'name': 'rover'}, ... 'dog2': {'fleas': True, 'tail': 'long', 'name': 'rover'}, ... 'dog3': {'fleas': True, 'tail': 'long', 'name': 'rover'}, ... }, ... } 1 >>> repeater = ConfigObj(configspec=repeated_4) >>> repeater['Michael'] = {} >>> repeater.validate(val) 1 >>> repeater == { ... 'Michael': {'age': 0.0, 'name': 'Michael', 'sex': 'm'}, ... } 1 >>> repeater = ConfigObj(repeated_3, configspec=repeated_5) >>> repeater == { ... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}}, ... 'cats': {'cat1': {}, 'cat2': {}, 'cat3': {}}, ... } 1 >>> repeater.validate(val) 1 >>> repeater == { ... 'dogs': {'dog1': {}, 'dog2': {}, 'dog3': {}}, ... 'cats': { ... 'cat1': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'description': { ... 'weight': 6.0, ... 'height': 3.2999999999999998, ... 'coat': {'fur': 'black', 'condition': 5}, ... }, ... }, ... 'cat2': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'description': { ... 'weight': 6.0, ... 'height': 3.2999999999999998, ... 'coat': {'fur': 'black', 'condition': 5}, ... }, ... }, ... 'cat3': { ... 'fleas': True, ... 'tail': 'short', ... 'name': 'pussy', ... 'description': { ... 'weight': 6.0, ... 'height': 3.2999999999999998, ... 'coat': {'fur': 'black', 'condition': 5}, ... }, ... }, ... }, ... } 1 Test that interpolation is preserved for validated string values. Also check that interpolation works in configspecs. >>> t = ConfigObj() >>> t['DEFAULT'] = {} >>> t['DEFAULT']['test'] = 'a' >>> t['test'] = '%(test)s' >>> t['test'] 'a' >>> v = Validator() >>> t.configspec = {'test': 'string'} >>> t.validate(v) 1 >>> t.interpolation = False >>> t {'test': '%(test)s', 'DEFAULT': {'test': 'a'}} >>> specs = [ ... 'interpolated string = string(default="fuzzy-%(man)s")', ... '[DEFAULT]', ... 'man = wuzzy', ... ] >>> c = ConfigObj(configspec=specs) >>> c.validate(v) 1 >>> c['interpolated string'] 'fuzzy-wuzzy' FIXME: Above tests will fail if we couldn't import Validator (the ones that don't raise errors will produce different output and still fail as tests) sNo configspec supplied.sMissing validate module.R tmissingR,RKtpreserve_errorsRN(#RR6R.R'RWR"tVdtMissingValuet ImportErrort spec_sectiontmanyR?RDRRRRtret_truet ret_falseR>RCR!RQROt validatortchecktbaseErrorClassRRUR(R]R^RnR RRZtvalidate(R.R)R"RR%RRQR*R(R!R'RR&RnR RD((RR,s        !       .        (*R3R4R5RRtVERBOSERRRRRt_single_line_singlet_single_line_doublet_multi_line_singlet_multi_line_doubleRRRRORR6R2RRRRRRRRRRRRRR RRRRRRR,(((RR9sN         $Nv e       E ~ 8    % vcBs#tZdZdZedZRS(s A simple validator. Can be used to check that all members expected are present. To use it, provide a configspec with all your members in (the value given will be ignored). Pass an instance of ``SimpleVal`` to the ``validate`` method of your ``ConfigObj``. ``validate`` will return ``True`` if all members are present, or a dictionary with True/False meaning present/missing. (Whole missing sections will be replaced with ``False``) >>> val = SimpleVal() >>> config = ''' ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [section] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [[sub section]] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... '''.split('\n') >>> configspec = ''' ... test1='' ... test2='' ... test3='' ... test4='' ... [section] ... test1='' ... test2='' ... test3='' ... test4='' ... [[sub section]] ... test1='' ... test2='' ... test3='' ... test4='' ... '''.split('\n') >>> o = ConfigObj(config, configspec=configspec) >>> o.validate(val) 1 >>> o = ConfigObj(configspec=configspec) >>> o.validate(val) 0 cCs t|_dS(N(RR.R+(R.((RR2 scCs|o |in|S(s9A dummy check method, always returns the value unchanged.N(R!R.R+tmember(R.R*R2R!((RR* s (R3R4R5R2ROR*(((RR s 2 cCs|djog}g}n|tjo|Sn|tjo4|i|dtf|o|in|Snx|iD]{\}}|tjoqnt |i |to+|i|t|||||qn|i|||fqW|o|in|S(s An example function that will turn a nested dictionary of results (as returned by ``ConfigObj.validate``) into a flat list. ``cfg`` is the ConfigObj instance being checked, ``res`` is the results dictionary returned by ``validate``. (This is a recursive function, so you shouldn't use the ``levels`` or ``results`` arguments - they are used by the function. Returns a list of keys that failed. Each member of the list is a tuple : :: ([list of sections...], key, result) If ``validate`` was called with ``preserve_errors=False`` (the default) then ``result`` will always be ``False``. *list of sections* is a flattened list of sections that the key was found in. If the section was missing then key will be ``None``. If the value (or section) was missing then ``result`` will be ``False``. If ``validate`` was called with ``preserve_errors=True`` and a value was present, but failed the check, then ``result`` will be the exception object returned. You can use this as a string that describes the failure. For example *The value "3" is of the wrong type*. # FIXME: is the ordering of the output arbitrary ? >>> import validate >>> vtor = validate.Validator() >>> my_ini = ''' ... option1 = True ... [section1] ... option1 = True ... [section2] ... another_option = Probably ... [section3] ... another_option = True ... [[section3b]] ... value = 3 ... value2 = a ... value3 = 11 ... ''' >>> my_cfg = ''' ... option1 = boolean() ... option2 = boolean() ... option3 = boolean(default=Bad_value) ... [section1] ... option1 = boolean() ... option2 = boolean() ... option3 = boolean(default=Bad_value) ... [section2] ... another_option = boolean() ... [section3] ... another_option = boolean() ... [[section3b]] ... value = integer ... value2 = integer ... value3 = integer(0, 10) ... [[[section3b-sub]]] ... value = string ... [section4] ... another_option = boolean() ... ''' >>> cs = my_cfg.split('\n') >>> ini = my_ini.split('\n') >>> cfg = ConfigObj(ini, configspec=cs) >>> res = cfg.validate(vtor, preserve_errors=True) >>> errors = [] >>> for entry in flatten_errors(cfg, res): ... section_list, key, error = entry ... section_list.insert(0, '[root]') ... if key is not None: ... section_list.append(key) ... else: ... section_list.append('[missing]') ... section_string = ', '.join(section_list) ... errors.append((section_string, ' = ', error)) >>> errors.sort() >>> for entry in errors: ... print entry[0], entry[1], (entry[2] or 0) [root], option2 = 0 [root], option3 = the value "Bad_value" is of the wrong type. [root], section1, option2 = 0 [root], section1, option3 = the value "Bad_value" is of the wrong type. [root], section2, another_option = the value "Probably" is of the wrong type. [root], section3, section3b, section3b-sub, [missing] = 0 [root], section3, section3b, value2 = the value "a" is of the wrong type. [root], section3, section3b, value3 = the value "11" is too big. [root], section4, [missing] = 0 N(tlevelsR6tresultstresRRRORZRdRlRTRQRUtcfgRPR:R (R6R5R3R4RQRT((RR s._       cCsdS(s Dummy function to hold some of the doctests. >>> a.depth 0 >>> a == { ... 'key2': 'val', ... 'key1': 'val', ... 'lev1c': { ... 'lev2c': { ... 'lev3c': { ... 'key1': 'val', ... }, ... }, ... }, ... 'lev1b': { ... 'key2': 'val', ... 'key1': 'val', ... 'lev2ba': { ... 'key1': 'val', ... }, ... 'lev2bb': { ... 'key1': 'val', ... }, ... }, ... 'lev1a': { ... 'key2': 'val', ... 'key1': 'val', ... }, ... } 1 >>> b.depth 0 >>> b == { ... 'key3': 'val3', ... 'key2': 'val2', ... 'key1': 'val1', ... 'section 1': { ... 'keys11': 'val1', ... 'keys13': 'val3', ... 'keys12': 'val2', ... }, ... 'section 2': { ... 'section 2 sub 1': { ... 'fish': '3', ... }, ... 'keys21': 'val1', ... 'keys22': 'val2', ... 'keys23': 'val3', ... }, ... } 1 >>> t = ''' ... 'a' = b # !"$%^&*(),::;'@~#= 33 ... "b" = b #= 6, 33 ... ''' .split('\n') >>> t2 = ConfigObj(t) >>> assert t2 == {'a': 'b', 'b': 'b'} >>> t2.inline_comments['b'] = '' >>> del t2['a'] >>> assert t2.write() == ['','b = b', ''] # Test ``list_values=False`` stuff >>> c = ''' ... key1 = no quotes ... key2 = 'single quotes' ... key3 = "double quotes" ... key4 = "list", 'with', several, "quotes" ... ''' >>> cfg = ConfigObj(c.splitlines(), list_values=False) >>> cfg == {'key1': 'no quotes', 'key2': "'single quotes'", ... 'key3': '"double quotes"', ... 'key4': '"list", \'with\', several, "quotes"' ... } 1 >>> cfg = ConfigObj(list_values=False) >>> cfg['key1'] = 'Multiline\nValue' >>> cfg['key2'] = '''"Value" with 'quotes' !''' >>> cfg.write() ["key1 = '''Multiline\nValue'''", 'key2 = "Value" with \'quotes\' !'] >>> cfg.list_values = True >>> cfg.write() == ["key1 = '''Multiline\nValue'''", ... 'key2 = \'\'\'"Value" with \'quotes\' !\'\'\''] 1 Test flatten_errors: >>> from validate import Validator, VdtValueTooSmallError >>> config = ''' ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [section] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... [[sub section]] ... test1=40 ... test2=hello ... test3=3 ... test4=5.0 ... '''.split('\n') >>> configspec = ''' ... test1= integer(30,50) ... test2= string ... test3=integer ... test4=float(6.0) ... [section ] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... [[sub section]] ... test1=integer(30,50) ... test2=string ... test3=integer ... test4=float(6.0) ... '''.split('\n') >>> val = Validator() >>> c1 = ConfigObj(config, configspec=configspec) >>> res = c1.validate(val) >>> flatten_errors(c1, res) == [([], 'test4', False), (['section', ... 'sub section'], 'test4', False), (['section'], 'test4', False)] True >>> res = c1.validate(val, preserve_errors=True) >>> check = flatten_errors(c1, res) >>> check[0][:2] ([], 'test4') >>> check[1][:2] (['section', 'sub section'], 'test4') >>> check[2][:2] (['section'], 'test4') >>> for entry in check: ... isinstance(entry[2], VdtValueTooSmallError) ... print str(entry[2]) True the value "5.0" is too small. True the value "5.0" is too small. True the value "5.0" is too small. Test unicode handling, BOM, write witha file like object and line endings : >>> u_base = ''' ... # initial comment ... # inital comment 2 ... ... test1 = some value ... # comment ... test2 = another value # inline comment ... # section comment ... [section] # inline comment ... test = test # another inline comment ... test2 = test2 ... ... # final comment ... # final comment2 ... ''' >>> u = u_base.encode('utf_8').splitlines(True) >>> u[0] = BOM_UTF8 + u[0] >>> uc = ConfigObj(u) >>> uc.encoding = None >>> uc.BOM == True 1 >>> uc == {'test1': 'some value', 'test2': 'another value', ... 'section': {'test': 'test', 'test2': 'test2'}} 1 >>> uc = ConfigObj(u, encoding='utf_8', default_encoding='latin-1') >>> uc.BOM 1 >>> isinstance(uc['test1'], unicode) 1 >>> uc.encoding 'utf_8' >>> uc.newlines '\n' >>> uc['latin1'] = "This costs lot's of " >>> a_list = uc.write() >>> len(a_list) 15 >>> isinstance(a_list[0], str) 1 >>> a_list[0].startswith(BOM_UTF8) 1 >>> u = u_base.replace('\n', '\r\n').encode('utf_8').splitlines(True) >>> uc = ConfigObj(u) >>> uc.newlines '\r\n' >>> uc.newlines = '\r' >>> from cStringIO import StringIO >>> file_like = StringIO() >>> uc.write(file_like) >>> file_like.seek(0) >>> uc2 = ConfigObj(file_like) >>> uc2 == uc 1 >>> uc2.filename == None 1 >>> uc2.newlines == '\r' 1 N((((Rt_doctest` st__main__sy key1= val # comment 1 key2= val # comment 2 # comment 3 [lev1a] # comment 4 key1= val # comment 5 key2= val # comment 6 # comment 7 [lev1b] # comment 8 key1= val # comment 9 key2= val # comment 10 # comment 11 [[lev2ba]] # comment 12 key1= val # comment 13 # comment 14 [[lev2bb]] # comment 15 key1= val # comment 16 # comment 17 [lev1c] # comment 18 # comment 19 [[lev2c]] # comment 20 # comment 21 [[[lev3c]]] # comment 22 key1 = val # comment 23s key1 = 'val1' key2 = "val2" key3 = val3 ["section 1"] # comment keys11 = val1 keys12 = val2 keys13 = val3 [section 2] keys21 = val1 keys22 = val2 keys23 = val3 [['section 2 sub 1']] fish = 3 sR name1 = """ a single line value """ # comment name2 = ''' another single line value ''' # comment name3 = """ a single line value """ name4 = ''' another single line value ''' [ "multi section" ] name1 = """ Well, this is a multiline value """ name2 = ''' Well, this is a multiline value ''' name3 = """ Well, this is a multiline value """ # a comment name4 = ''' Well, this is a multiline value ''' # I guess this is a comment too s tINTP_VERtatbR tglobs(Ft __future__t generatorstsyst version_infoR9t RuntimeErrorRRttypesRVtwarningsRtcodecsRt BOM_UTF16t BOM_UTF16_BEt BOM_UTF16_LER6RRRR,R#R$Rt NameErrorRRRORt __revision__Rt__all__RRRRR1RRRRRRRRRR:R8RtobjectRR R7R3t testconfig1t testconfig2t testconfig6tdoctesttmodulesRPtmt__dict__RR<tsplitR:R;R Rcttestmod(1RRRRRMRGRRNRRRR<R RRIRJRR;RR#R>RVRRRRRLRR:R9RRRRRQRRERR?RRROR RRRFROR7RR8((Rt?s     B 3 9`       Eo>  1autostart = boolean(default=True) model = option('1710', '1720', '1721', '1750', '1751', '1760', '2610', '2611', '2620', '2621', '2610XM', '2611XM', '2620XM', '2621XM', '2650XM', '2651XM', '2691', '3725', '3745', '3620', '3640', '3660', '7200', default='7200') ghostios = boolean(default=False) ghostsize = integer(min=1, default=None) sparsemem = boolean(default=False) idlemax = integer(min=1, default=None) idlesleep = integer(min=1, default=None) oldidle = boolean(default=False) debug = integer(min=0, max=9, default=0) [__many__] port = integer(min=1, max=65535, default=None) workingdir = string(default=None) console = integer(min=1, max=65535, default=None) udp = integer(min=1, max=65535, default=None) [[__many__]] model = option('1710', '1720', '1721', '1750', '1751, '1760', '2610', '2611', '2620', '2621', '2610XM', '2611XM', '2620XM', '2621XM', '2650XM', '2651XM', '2691', '3725', '3745', '3620', '3640', '3660', '7200', default=None) console = integer(min=1, max=65535, default=None) aux = integer(min=1, max=65535, default=None) mac = string(default=None) image = string(default=None) ram = integer(min=0, default=None) nvram = integer(min=0, default=None) cnfg = string(default=None) confreg = string(default=None) idlepc = string(default=None) exec_area = string(default=None) clock = integer(min=0, default=None) npe = option('npe-100', 'npe-150', 'npe-175', 'npe-200', 'npe-225', 'npe-300', 'npe-400', 'npe-g1', 'npe-g2', default=None) midplane = option('std', 'vxr', default=None) disk0 = integer(min=0, default=None) disk1 = integer(min=0, default=None) mmap = boolean(default=None) ghostios = boolean(default=None) ghostsize = integer(min=1, default=None) sparsemem = boolean(default=None) autostart = boolean(default=None) configuration = string(default=None) idlemax = integer(min=1, default=None) idlesleep = integer(min=1, default=None) oldidle = boolean(default=None) #!/usr/bin/env python """ dynamips_lib.py Copyright (C) 2006 Greg Anuzelli Derived from recipe on ASPN Cookbook Recipe Author: James Thiele, http://www.eskimo.com/~jet/python/examples/cmd/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ import os, cmd, time, re, StringIO, csv, base64 from dynamips_lib import DynamipsError, DynamipsWarning, IDLEPROPGET, IDLEPROPSHOW, IDLEPROPSET from configobj import ConfigObj interface_re = re.compile(r"""^(g|gi|f|fa|a|at|s|se|e|et|p|po)([0-9]+)\/([0-9]+)$""", re.IGNORECASE) # Regex matching intefaces interface_noport_re = re.compile(r"""^(g|gi|f|fa|a|at|s|se|e|et|p|po)([0-9]+)$""", re.IGNORECASE) # Regex matching intefaces with out a port (e.g. "f0") globaldebug = 0 # determine if we are in the debugger try: DBGPHideChildren except NameError: DEBUGGER = False else: DEBUGGER = True # Import readline if it is available. If it is, tab completion will work try: import readline except ImportError: pass class Console(cmd.Cmd): def __init__(self): cmd.Cmd.__init__(self) # Import the main namespace for use in this module # Yes, normally this is bad mojo, but I'm doing this to provide the console # access to the entire namespace in case the user wants to futz with stuff import __main__ self.namespace = __main__ debuglevel = self.namespace.debuglevel self.prompt = '=> ' self.intro = 'Dynagen management console for Dynamips\nCopyright (c) 2005-2007 Greg Anuzelli\n' ## Command definitions ## def do_list(self, args): """list\nList all devices""" table = [] print "%-10s %-10s %-10s %-15s %-10s" % ('Name','Type','State','Server','Console') for device in self.namespace.devices.values(): row = [] row.append("%-10s" % device.name) try: model = device.model if model == 'c3600': model = device.chassis if model == 'c7200': model = '7200' row.append("%-10s" % model) except AttributeError: row.append("%-10s" % device.adapter) try: row.append("%-10s" % device.state) except AttributeError: row.append("%-10s" % 'always on') try: server = device.dynamips.host + ':' + str(device.dynamips.port) row.append("%-15s" % server) except AttributeError: row.append("%-15s" % 'n/a') try: row.append("%-10s" % device.console) except AttributeError: row.append("%-10s" % 'n/a') table.append(row) table.sort(con_cmp) # Sort the table by the console port # for line in table: for item in line: print item, print def do_suspend(self, args): """suspend {/all | router1 [router2] ...}\nsuspend all or a specific router(s)""" if '?' in args or args.strip() == '': print self.do_suspend.__doc__ return devices = args.split(' ') if '/all' in devices: for device in self.namespace.devices.values(): try: for line in device.suspend(): print line.strip() except IndexError: pass except AttributeError: # If this device doesn't support suspend just ignore it pass except DynamipsError, e: error(e) return for device in devices: try: print self.namespace.devices[device].suspend()[0].strip() except IndexError: pass except (KeyError, AttributeError): error('invalid device: ' + device) except DynamipsError, e: error(e) def do_start(self, args): """start {/all | router1 [router2] ...}\nstart all or a specific router(s)""" if '?' in args or args.strip() == '': print self.do_start.__doc__ return devices = args.split(' ') if '/all' in devices: for device in self.namespace.devices.values(): try: if device.idlepc == None: if self.namespace.useridledb and device.imagename in self.namespace.useridledb: device.idlepc = self.namespace.useridledb[device.imagename] else: print("Warining: Starting %s with no idle-pc value" % device.name) for line in device.start(): print line.strip() except IndexError: pass except AttributeError: # If this device doesn't support start just ignore it pass except DynamipsError, e: error(e) return for devname in devices: try: device = self.namespace.devices[devname] if device.idlepc == None: if self.namespace.useridledb and device.imagename in self.namespace.useridledb: device.idlepc = self.namespace.useridledb[device.imagename] else: print("Warining: Starting %s with no idle-pc value" % device.name) for line in device.start(): print line.strip() except IndexError: pass except (KeyError, AttributeError): error('invalid device: ' + devname) except DynamipsError, e: error(e) def do_stop(self, args): """stop {/all | router1 [router2] ...}\nstop all or a specific router(s)""" if '?' in args or args.strip() == '': print self.do_stop.__doc__ return devices = args.split(' ') if '/all' in devices: for device in self.namespace.devices.values(): try: for line in device.stop(): print line.strip() except IndexError: pass except AttributeError: # If this device doesn't support stop just ignore it pass except DynamipsError, e: error(e) return for device in devices: try: print self.namespace.devices[device].stop()[0].strip() except IndexError: pass except (KeyError, AttributeError): error('invalid device: ' + device) except DynamipsError, e: error(e) def do_resume(self, args): """resume {/all | router1 [router2] ...}\nresume all or a specific router(s)""" if '?' in args or args.strip() == '': print self.do_resume.__doc__ return devices = args.split(' ') if '/all' in devices: for device in self.namespace.devices.values(): try: for line in device.resume(): print line.strip() except IndexError: pass except AttributeError: # If this device doesn't support resume just ignore it pass except DynamipsError, e: error(e) return for device in devices: try: print self.namespace.devices[device].resume()[0].strip() except IndexError: pass except (KeyError, AttributeError): error('invalid device: ' + device) except DynamipsError, e: error(e) def do_reload(self, args): """reload {/all | router1 [router2] ...}\nreload all or a specific router(s)""" if '?' in args or args.strip() == '': print self.do_reload.__doc__ return devices = args.split(' ') if '/all' in devices: for device in self.namespace.devices.values(): try: for line in device.stop(): print line.strip() for line in device.start(): print line.strip() except IndexError: pass except AttributeError: # If this device doesn't support stop/start just ignore it pass except DynamipsError, e: error(e) return for device in devices: try: print self.namespace.devices[device].stop()[0].strip() print self.namespace.devices[device].start()[0].strip() except IndexError: pass except (KeyError, AttributeError): error('invalid device: ' + device) except DynamipsError, e: error(e) def do_ver(self, args): """Print the dynagen version""" print 'dynagen ' + self.namespace.VERSION print 'dynamips version(s):' for d in self.namespace.dynamips.values(): print ' %s: %s' % (d.host, d.version) def do_hist(self, args): """Print a list of commands that have been entered""" print self._hist def do_exit(self, args): """Exits from the console""" return -1 def do_disconnect(self, args): """Exits from the console, but does not shut down the lab on Dynagen""" return -2 def do_shell(self, args): """Pass command to a system shell when line begins with '!'""" os.system(args) def do_telnet(self, args): """telnet {/all | router1 [router2] ...}\nconnect to the console(s) of all or a specific router(s)\nThis is identical to the console command.""" if '?' in args or args.strip() == '': print self.do_telnet.__doc__ return Console.do_console(self,args) def do_console(self, args): """console {/all | router1 [router2] ...}\nconnect to the console(s) of all or a specific router(s)\n""" if '?' in args or args.strip() == '': print self.do_telnet.__doc__ return devices = args.split(' ') if '/all' in args.split(' '): # Set devices to all the devices devices = self.namespace.devices.values() else: devices = [] for device in args.split(' '): # Create a list of all the device objects try: devices.append(self.namespace.devices[device]) except KeyError: error('unknown device: ' + device) for device in devices: try: if not device.isrouter: continue if device.state != 'running': print "Skipping %s device: %s" % (device.state, device.name) continue telnet(device.name) except IndexError: pass except (KeyError, AttributeError): error('invalid device: ' + device.name) except DynamipsError, e: error(e) def do_show(self, args): """show mac ethernet_switch_name\nshow the mac address table of an ethernet switch""" if '?' in args or args.strip() == '': print self.do_show.__doc__ return params = args.split(' ') if params[0].lower() == 'mac': try: result = self.namespace.devices[params[1]].show_mac() for chunks in result: lines = chunks.strip().split('\r\n') for line in lines: if line != '100-OK': print line[4:] except IndexError: error('missing device') except (KeyError, AttributeError): error('invalid device: ' + params[1]) except DynamipsError, e: error(e) else: error('invalid show command') def do_clear(self, args): """clear mac ethernet_switch_name\nclear the mac address table of an ethernet switch""" if '?' in args or args.strip() == '': print self.do_clear.__doc__ return params = args.split(' ') if params[0].lower() == 'mac': try: print self.namespace.devices[params[1]].clear_mac()[0].strip() except IndexError: error('missing device') except (KeyError, AttributeError): error('invalid device: ' + params[1]) except DynamipsError, e: error(e) else: error('invalid clear command') def do_save(self, args): """save {/all | router1 [router2] ...}\nstores router configs in the network file""" if '?' in args or args.strip() == '': print self.do_save.__doc__ return netfile = self.namespace.globalconfig if '/all' in args.split(' '): # Set devices to all the devices devices = self.namespace.devices.values() else: devices = [] for device in args.split(' '): # Create a list of all the device objects try: devices.append(self.namespace.devices[device]) except KeyError: error('unknown device: ' + device) # Get the config for each router and store it in the config dict for device in devices: try: config = device.config_b64 except AttributeError: # This device doesn't support export continue except DynamipsError, e: print e # Try saving the other devices though continue # What server and port is this device on? host = device.dynamips.host port = device.dynamips.port # Find the config section for this device if netfile.has_key(host + ':' + str(port)): serverSection = host + ':' + str(port) elif netfile.has_key(host): serverSection = host else: error("can't find server section for device: " + device.name) for section in netfile[serverSection].sections: # Check to see if 1) this device is a router, and # 2) if it is the section for the device we need to save try: (devtype, devname) = section.split() except ValueError: continue if devtype.lower() == 'router' and devname == device.name: netfile[serverSection][section]['configuration'] = config # And populate the configurations dictionary self.namespace.configurations[device.name] = config print 'saved configuration from: ' + device.name netfile.write() def do_push(self,args): """push {/all | router1 [router2] ...}\npushes router configs from the network file to the router's nvram""" if '?' in args or args.strip() == '': print self.do_push.__doc__ return configurations = self.namespace.configurations if '/all' in args.split(' '): # Set devices to all the devices devices = self.namespace.devices.values() else: devices = [] for device in args.split(' '): # Create a list of all the device objects try: devices.append(self.namespace.devices[device]) except KeyError: error('unknown device: ' + device) # Set the config for each router for device in devices: try: device.config_b64 = configurations[device.name] except AttributeError: # This device doesn't support importing continue except KeyError: print 'No saved configuration found for device: ' + device.name continue except DynamipsError, e: print e # Try saving the other devices though continue print 'Pushed config to: ' + device.name def do_export(self, args): """export {/all | router1 [router2] ...} \"directory\"\nsaves router configs individual files in \"directory\"\nEnclose the directory in quotes if there are spaces in the filespec.""" if '?' in args or args.strip() == '': print self.do_export.__doc__ return try: items = getItems(args) except DynamipsError, e: error(e) return if len(items) < 2: print self.do_export.__doc__ return # The last item is the directory (or should be anyway) directory = items.pop() if '/all' in items: # Set devices to all the devices devices = self.namespace.devices.values() else: devices = [] for device in items: # Create a list of all the device objects try: devices.append(self.namespace.devices[device]) except KeyError: error('unknown device: ' + device) return # Set the current directory to the one that contains our network file try: netdir = os.getcwd() subdir = os.path.dirname(self.namespace.FILENAME) debug("current dir is -> " + os.getcwd()) if subdir != '': debug("changing dir to -> " + subdir) os.chdir(subdir) except OSError,e: error(e) os.chdir(netdir) # Reset the current working directory return try: debug("making -> " + str(directory)) os.makedirs(directory) except OSError: # Directory exists result = raw_input("The directory \"%s\" already exists. Ok to overwrite (Y/N)? " % directory) if result.lower() != 'y': os.chdir(netdir) # Reset the current working directory return # Get the config for each router and store it in the config dict for device in devices: try: config = base64.decodestring(device.config_b64) config = config.replace('\r', '') except AttributeError: # This device doesn't support export continue except DynamipsError, e: print e # Try saving the other devices though continue except TypeError: error("Unknown error exporting config for " + device.name) continue # Write out the config to a file print "Exporting %s to \"%s\"" % (device.name, directory + os.sep + device.name + '.cfg') try: f = open(directory + os.sep + device.name + '.cfg', 'w') f.write(config) f.close() except IOError, e: error(e) os.chdir(netdir) # Reset the current working directory return # Change directory back to net dir for subsequent execution os.chdir(netdir) def do_import(self, args): """import {/all | router1 [router2] \"directory\"\nimport all or individual configuration files \nEnclose the directory or filename in quotes if there are spaces in the filespec.""" if '?' in args or args.strip() == '': print self.do_import.__doc__ return items = getItems(args) if len(items) < 2: print self.do_export.__doc__ return # The last item is the directory (or should be anyway) directory = items.pop() # Set the current directory to the one that contains our network file try: netdir = os.getcwd() subdir = os.path.dirname(self.namespace.FILENAME) debug("current dir is -> " + os.getcwd()) if subdir != '': debug("changing dir to -> " + subdir) os.chdir(subdir) except OSError,e: error(e) return # Walk through all the config files, and attempt to import them try: contents = os.listdir(directory) except OSError, e: error(e) return for file in contents: if file[-4:].lower() == '.cfg': device = file[:-4] if '/all' in items or device in items: print "Importing %s from \"%s\"" % (device, file) try: f = open(directory + os.sep + file, 'r') config = f.read() config = "\n!\n" + config f.close() # Encodestring puts in a bunch of newlines. Split them out then join them back together encoded = ''.join(base64.encodestring(config).split()) self.namespace.devices[device].config_b64 = encoded except IOError, e: error(e) os.chdir(netdir) # Reset the current working directory return except KeyError: error("Ignoring unknown device: " + device) # Don't return, continue trying to import the other devices except DynamipsError, e: error(e) # Don't return, continue trying to import the other devices os.chdir(netdir) def do_filter(self, args): """filter device interface filter_name direction [options] applies a connection filter Examples: filter R1 s1/0 freq_drop in 50 -- Drops 1 out of every 50 packets inbound to R1 s1/0 filter R1 s1/0 none in -- Removes all inbound filters from R1 s1/0""" filters = ['freq_drop', 'capture', 'none'] # The known list of filters if '?' in args or args.strip() == '': print self.do_filter.__doc__ return try: if len(args.split(' ')) > 4: (device, interface, filterName, direction, options) = args.split(' ', 4) else: (device, interface, filterName, direction) = args.split(' ', 3) options = None except ValueError: print self.do_filter.__doc__ return if device not in self.namespace.devices: print 'Unknown device: ' + device return if filterName not in filters: print 'Unknown filter: ' + filterName return # Parse out the slot and port match_obj = interface_re.search(interface) if not match_obj: print 'Error parsing interface descriptor: ' + interface return try: (slot, port) = match_obj.group(2,3) slot = int(slot) port = int(port) except ValueError: print 'Error parsing interface descriptor: ' + interface return # Apply the filter try: self.namespace.devices[device].slot[slot].filter(port, filterName, direction, options) except DynamipsError, e: print e return except IndexError: print "No such interface %s on device %s" % (interface, device) return def do_capture(self, args): """[no] capture device interface filename [link-type] Begins a capture of all packets in and out of "interface" on "device". Enclose the filename in quotes if there are spaces in the filespec. The capture file is written to the dynamips host. Link type is one of: ETH (Ethernet 10/100/1000) FR (Frame-Relay) HDLC (Cisco HDLC) PPP (PPP on serial) Captures of ethernet interfaces default to EN10MB, but for serial interfaces the link type must be specified. Examples: capture R1 f0/0 example.cap -- Capture packets in and out of f0/0 on R1 and write the output to example.cap capture R1 s0/0 example2.cap HDLC -- Capture and specify HDLC encapsulation no capture R1 s0/0 -- End the packet capture""" # link type transformation linkTransform = { 'ETH':'EN10MB', 'FR':'FRELAY', 'HDLC':'C_HDLC', 'PPP':'PPP_SERIAL' } if '?' in args or args.strip() == '': print self.do_capture.__doc__ return try: if len(args.split(' ')) > 3: (device, interface, filename, linktype) = args.split(' ', 3) try: linktype = linktype.upper() linktype = linkTransform[linktype] except KeyError: print 'Invalid linktype: ' + linktype return else: (device, interface, filename) = args.split(' ', 2) linktype = None except ValueError: print self.do_capture.__doc__ return if device not in self.namespace.devices: print 'Unknown device: ' + device return # Parse out the slot and port match_obj = interface_re.search(interface) if match_obj: try: (inttype, slot, port) = match_obj.group(1,2,3) slot = int(slot) port = int(port) except ValueError: print 'Error parsing interface descriptor: ' + interface return else: # Try checking for WIC interface specification (e.g. S1) match_obj = interface_noport_re.search(interface) if not match_obj: print 'Error parsing interface descriptor: ' + interface return (inttype, port) = match_obj.group(1,2) slot = 0 if linktype == None: if inttype.lower() in ['e', 'et', 'f', 'fa', 'g', 'gi']: linktype = 'EN10MB' elif inttype.lower() in ['s', 'se']: print 'Error: Link type must be specified for serial interfaces' return else: print 'Error: Packet capture is not supported on this interface type' return interface = inttype[0].lower() # Apply the filter try: self.namespace.devices[device].slot[slot].filter(interface, port, 'capture', 'both', linktype + " " + filename) except DynamipsError, e: print e return except IndexError: print "Error: No such interface %s on device %s" % (interface, device) return except AttributeError: print "Error: Interface %s on device %s is not connected" % (interface, device) return def do_no(self, args): """negates a command """ if '?' in args or args.strip() == '': print self.do_no.__doc__ return try: (command, options) = args.split(' ', 1) if command.lower() == 'capture': if len(options.split(' ')) == 2: (device, interface) = options.split(' ', 1) else: print 'Error parsing command' return except ValueError: print 'Error parsing command' return if device not in self.namespace.devices: print 'Unknown device: ' + device return # Parse out the slot and port match_obj = interface_re.search(interface) if match_obj: try: (inttype, slot, port) = match_obj.group(1,2,3) slot = int(slot) port = int(port) except ValueError: print 'Error parsing interface descriptor: ' + interface return else: # Try checking for WIC interface specification (e.g. S1) match_obj = interface_noport_re.search(interface) if not match_obj: print 'Error parsing interface descriptor: ' + interface return (inttype, port) = match_obj.group(1,2) slot = 0 interface = inttype[0].lower() # Remove the filter try: self.namespace.devices[device].slot[slot].filter(interface, port, 'none', 'both') except DynamipsError, e: print e return except IndexError: print "No such interface %s on device %s" % (interface, device) return def do_send(self, args): """send [host] commandstring send a raw hypervisor command to a dynamips server Examples: send bender hypervisor version -- Send the 'hypervisor version' command to the host named bender""" if '?' in args or args.strip() == '': print self.do_send.__doc__ return try: (host, command) = args.split(' ', 1) except ValueError: print 'Error parsing command' return #if host not in self.namespace.dynamips: found = False for server in self.namespace.dynamips.values(): if host.lower() == server.host.lower(): found = True break if not found: error('Unknown host ' + host) return try: result = server.send_raw(command) except DynamipsError, e: print e return for line in result: print line def do_idlepc(self, args): """idlepc {get|set|show|save|idlemax|idlesleep|showdrift} device [value] idlepc save device [default] get, set, or show the online idlepc value(s) Examples: idlepc get r1 -- Get a list of the possible idlepc value(s) for router r1 idlepc show r1 -- Show the previously determined idlepc values for router r1 idlepc set r1 0x12345 -- Manually set r1's idlepc to 0x12345 idlepc save r1 -- Save r1's current idlepc value to the "router r1" section of your network file idlepc save r1 default -- Save r1's current idlepc value to the device defaults section of your network file (i.e. [[7200]]) idlepc save r1 db -- Save r1's current idlepc value to the idlepc database idlepc idlemax r1 1500 -- Commands for advanced manipulation of idlepc idlepc idlesleep r1 30 settings idlepc showdrift r1 """ if '?' in args or args.strip() == '': print self.do_idlepc.__doc__ return try: command = args.split()[0] command = command.lower() params = args.split()[1:] if len(params) < 1: print self.do_idlepc.__doc__ return if command == 'get' or command == 'show': device = params[0] if command == 'get': if self.namespace.devices[device].idlepc != None: print '%s already has an idlepc value applied.' % device return print 'Please wait while gathering statistics...' result = self.namespace.devices[device].idleprop(IDLEPROPGET) elif command == 'show': result = self.namespace.devices[device].idleprop(IDLEPROPSHOW) result.pop() # Remove the '100-OK' line idles = {} i = 1 for line in result: (value, count) = line.split()[1:] # Flag potentially "best" idlepc values (between 50 and 60) iCount = int(count[1:-1]) if 50 < iCount < 60: flag = '*' else: flag = ' ' print "%s %2i: %s %s" % (flag, i, value, count) idles[i] = value i += 1 # Allow user to choose a value by number if len(idles) == 0: print 'No idlepc values found\n' else: print 'Potentially better idlepc values marked with "*"' selection = raw_input("Enter the number of the idlepc value to apply [1-%i] or ENTER for no change: " % len(idles)) if selection == "": print 'No changes made' return try: selection = int(selection) except ValueError: print "Invalid selection" return if selection < 1 or selection > len(idles): print "Invalid selection" return # Apply the selected idle self.namespace.devices[device].idleprop(IDLEPROPSET, idles[selection]) print "Applied idlepc value %s to %s\n" % (idles[selection], device) elif command == 'set': (device, value) = params self.namespace.devices[device].idleprop(IDLEPROPSET, value) print "Applied idlepc value %s to %s\n" % (value, device) elif command == 'save': if len(params) == 1: device = params[0] location = "" elif len(params) == 2: (device, location) = params if location.lower() not in ['default', 'db']: print "***Error: unknown keyword %s" % location return else: raise ValueError idlepc = self.namespace.devices[device].idlepc if idlepc == None: print "****Error: device %s has no idlepc value to save" % device return netfile = self.namespace.globalconfig host = self.namespace.devices[device].dynamips.host port = self.namespace.devices[device].dynamips.port # Find the dynamips config section for this device if netfile.has_key(host): serverSection = host elif netfile.has_key(host + ':' + str(port)): serverSection = host + ':' + str(port) else: error("can't find server section for device: " + device) if location.lower() == 'default': # Find the default section for this device model = self.namespace.devices[device].model if model == 'c3600' or model == 'c2600': # The section default is actually the chassis section = self.namespace.devices[device].chassis else: try: section = model[1:] except: print "***Error: could not determine default section for device " + device return elif location.lower() == 'db': # Store the idlepc value for this image in the idlepc user database if not self.namespace.useridledb: # We need to create a new file self.namespace.useridledb = ConfigObj() self.namespace.useridledb.filename = self.namespace.useridledbfile self.namespace.useridledb[self.namespace.devices[device].imagename] = idlepc try: self.namespace.useridledb.write() except IOError,e: print '***Error: ' + str(e) return print "idlepc value for image \"%s\" written to the database" % self.namespace.devices[device].imagename return else: for section in netfile[serverSection].sections: # Check to see if 1) this device is a router, and # 2) if it is the section for the device we need to save try: (devtype, devname) = section.split() except ValueError: continue if devtype.lower() == 'router' and devname == device: break # Perform a sanity check. I'd hate to trash a network file... if section not in netfile[serverSection].sections: print "***Error: section %s not found in network configuration file for host %s" % (section, host) return netfile[serverSection][section]['idlepc'] = idlepc netfile.write() print 'idlepc value saved to section: ' + section elif command == 'showdrift': device = params[0] print 'Current idlemax value: %i' % self.namespace.devices[device].idlemax print 'Current idlesleep value: %i' % self.namespace.devices[device].idlesleep result = self.namespace.devices[device].idlepcdrift for line in result: print line[4:] return elif command in ['idlemax', 'idlesleep']: (device, value) = params value = int(value) if command == 'idlemax': self.namespace.devices[device].idlemax = value elif command == 'idlesleep': self.namespace.devices[device].idlesleep = value print 'OK' return else: print '***Error: Unknown command ' + command return except ValueError: print '***Error: Incorrect number of paramaters or invalid parameters' return except KeyError: print '***Error: Unknown device: ' + device return except DynamipsError, e: print e return def do_confreg(self, args): """confreg {/all | router1 [router2] <0x0-0xFFFF>}\n set the config register(s)""" if '?' in args or args.strip() == '': print self.do_confreg.__doc__ return devices = args.split(' ') if devices[-1][:2] == '0x': confreg = devices.pop() flag = 'set' else: print "***Error: No confreg value specified" return if '/all' in devices: for device in self.namespace.devices.values(): try: if flag == 'set': device.confreg = confreg #else: # confreg = device.confreg # print device.name + ": " + confreg except IndexError: pass except AttributeError: # If this device doesn't support stop just ignore it pass except DynamipsError, e: error(e) return for device in devices: try: self.namespace.devices[device].confreg = confreg except IndexError: pass except (KeyError, AttributeError): error('invalid device: ' + device) except DynamipsError, e: error(e) """ def do_cpuinfo(self, args): #cpuinfo {/all | router1 [router2] ...}\nshow cpu info for a specific router(s) if '?' in args or args.strip() == '': print self.do_cpuinfo.__doc__ return devices = args.split(' ') if '/all' in devices: for device in self.namespace.devices.values(): try: for line in device.cpuinfo(): print line.strip() except IndexError: pass except AttributeError: # If this device doesn't support stop just ignore it pass except DynamipsError, e: error(e) return for device in devices: try: print self.namespace.devices[device].cpuinfo()[0].strip() except IndexError: pass except (KeyError, AttributeError): error('invalid device: ' + device) except DynamipsError, e: error(e) """ def do_help(self, args): """Get help on commands 'help' or '?' with no arguments prints a list of commands for which help is available 'help ' or '? ' gives help on """ ## The only reason to define this method is for the help text in the doc string cmd.Cmd.do_help(self, args) ## Override methods in Cmd object ## def preloop(self): """Initialization before prompting user for commands. Despite the claims in the Cmd documentaion, Cmd.preloop() is not a stub. """ cmd.Cmd.preloop(self) ## sets up command completion self._hist = [] ## No history yet self._locals = {} ## Initialize execution namespace for user self._globals = {} # Give the console access to the namespace self._globals['namespace'] = self.namespace def postloop(self): """Take care of any unfinished business. Despite the claims in the Cmd documentaion, Cmd.postloop() is not a stub. """ cmd.Cmd.postloop(self) ## Clean up command completion print "Exiting..." def precmd(self, line): """ This method is called after the line has been input but before it has been interpreted. If you want to modifdy the input line before execution (for example, variable substitution) do it here. """ self._hist += [ line.strip() ] # Add "con" as a shortcut for "console" tokens = line.split() try: if tokens[0].lower() == 'con': tokens[0] = 'console' line = ' '.join(tokens) elif tokens[0].lower() == 'dis': tokens[0] = 'disconnect' line = ' '.join(tokens) except IndexError: pass return line def postcmd(self, stop, line): """If you want to stop the console, return something that evaluates to true. If you want to do some post command processing, do it here. """ return stop def emptyline(self): """Do nothing on empty input line""" pass def do_py(self, line): """py \nExecute python statements""" if line == '?': print self.do_py.__doc__ return try: exec(line) in self._locals, self._globals except Exception, e: print e.__class__, ":", e def default(self, line): """Called on an input line when the command prefix is not recognized. In that case we execute the line as Python code. """ error('unknown command') def telnet(device): """telnet to the console port of device""" import __main__ telnetstring = __main__.telnetstring port = str(__main__.devices[device].console) host = str(__main__.devices[device].dynamips.host) if telnetstring and not __main__.notelnet: telnetstring = telnetstring.replace('%h', host) telnetstring = telnetstring.replace('%p', port) telnetstring = telnetstring.replace('%d', device) os.system(telnetstring) time.sleep(0.5) # Give the telnet client a chance to start def con_cmp(row1, row2): return cmp(row1[4], row2[4]) def getItems(s): """Uses the CSV module to split a string by whitespace, but respecting quotes""" input = StringIO.StringIO(s) try: items = csv.reader(input, delimiter=' ').next() except csv.Error, e: raise DynamipsError, e # csv.reader removes the quotes though. So we need to put them back in for items with spaces in them """ i = 0 while i < len(items): if ' ' in items[i]: items[i] = '"' + items[i] + '"' i += 1 """ return items def error(msg): """Print out an error message""" print '*** Error:', str(msg) def debug(string): """ Print string if debugging is true """ # Debug level 2, console debugs if globaldebug >= 2: print ' DEBUG: ' + str(string) if __name__ == '__main__': #console = Console() #console . cmdloop() pass m fFc@sOdZdkZdkZdkZdkZdkZdkZdkZdkl Z l Z l Z l Z l Z dklZeideiZeideiZdZyeWnej o eZnXeZy dkZWnej onXdeifdYZd Zd Zd Z d Z!d Z"e#djondS(sR dynamips_lib.py Copyright (C) 2006 Greg Anuzelli Derived from recipe on ASPN Cookbook Recipe Author: James Thiele, http://www.eskimo.com/~jet/python/examples/cmd/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. N(s DynamipsErrorsDynamipsWarnings IDLEPROPGETs IDLEPROPSHOWs IDLEPROPSET(s ConfigObjs3^(g|gi|f|fa|a|at|s|se|e|et|p|po)([0-9]+)\/([0-9]+)$s)^(g|gi|f|fa|a|at|s|se|e|et|p|po)([0-9]+)$itConsolecBs:tZdZdZdZdZdZdZdZdZ d Z d Z d Z d Z d ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ d Z!d!Z"d"Z#RS(#NcCsDtii|dk}||_|ii}d|_d|_dS(Ns=> sNDynagen management console for Dynamips Copyright (c) 2005-2007 Greg Anuzelli ( tcmdtCmdt__init__tselft__main__t namespacet debugleveltprompttintro(RRR((t/usr/bin/console.pyR1s     c Csg}ddGHx|iiiD]}g}|id|iyO|i }|djo |i }n|d jo d }n|id|Wn't j o|id|i nXy|id|i Wn$t j o|idd nXy5|iid t|ii}|id |Wn$t j o|id dnXy|id|iWn$t j o|iddnX|i|q"W|itx$|D]}x|D] }|GqWHqWdS(slist List all devicess%-10s %-10s %-10s %-15s %-10stNametTypetStatetServerRs%-10stc3600tc7200t7200s always ont:s%-15ssn/aN(R R R RsConsole(ttableRRtdevicestvaluestdevicetrowtappendtnametmodeltchassistAttributeErrortadaptertstatetdynamipsthosttstrtporttservertconsoletsorttcon_cmptlinetitem( RtargsR#R(RRRR'R((R tdo_list=sJ        cCsrd|jp|idjo|iiGHdSn|id}d|jox|iiiD]r}y&x|i D]}|iGHqxWWqbt j oqbt j oqbtj o}t|qbXqbWdSnx|D]}y#|ii|i diGHWqt j oqtt fj otd|qtj o}t|qXqWdS(sKsuspend {/all | router1 [router2] ...} suspend all or a specific router(s)t?tNt s/allisinvalid device: (R)tstripRt do_suspendt__doc__tsplitRRRRtsuspendR't IndexErrorRt DynamipsErrorteterrortKeyError(RR)RRR5R'((R R/as:    #cCs?d|jp|idjo|iiGHdSn|id}d|jox|iiiD]}y|i djoM|ii o0|i |ii jo|ii |i |_ qd|iGHnx|iD]}|iGHqWWqbtj oqbtj oqbtj o}t|qbXqbWdSnx|D]}y|ii|}|i djoM|ii o0|i |ii jo|ii |i |_ qd|iGHnx|iD]}|iGHqWWqDtj oqDttfj otd|qDtj o}t|qDXqDWdS(sGstart {/all | router1 [router2] ...} start all or a specific router(s)R+R,NR-s/alls+Warining: Starting %s with no idle-pc valuesinvalid device: (R)R.Rtdo_startR0R1RRRRtidlepctNonet useridledbt imagenameRtstartR'R3RR4R5R6tdevnameR7(RR)R>RRR5R'((R R8sP   # # cCsrd|jp|idjo|iiGHdSn|id}d|jox|iiiD]r}y&x|i D]}|iGHqxWWqbt j oqbt j oqbtj o}t|qbXqbWdSnx|D]}y#|ii|i diGHWqt j oqtt fj otd|qtj o}t|qXqWdS(sEstop {/all | router1 [router2] ...} stop all or a specific router(s)R+R,NR-s/allisinvalid device: (R)R.Rtdo_stopR0R1RRRRtstopR'R3RR4R5R6R7(RR)RRR5R'((R R?s:    #cCsrd|jp|idjo|iiGHdSn|id}d|jox|iiiD]r}y&x|i D]}|iGHqxWWqbt j oqbt j oqbtj o}t|qbXqbWdSnx|D]}y#|ii|i diGHWqt j oqtt fj otd|qtj o}t|qXqWdS(sIresume {/all | router1 [router2] ...} resume all or a specific router(s)R+R,NR-s/allisinvalid device: (R)R.Rt do_resumeR0R1RRRRtresumeR'R3RR4R5R6R7(RR)RRR5R'((R RAs:    #cCsd|jp|idjo|iiGHdSn|id}d|jox|iiiD]}yHx|i D]}|iGHqxWx|i D]}|iGHqWWqbt j oqbtj oqbtj o}t|qbXqbWdSnx|D]}yB|ii|i diGH|ii|i diGHWq t j oq ttfj otd|q tj o}t|q Xq WdS(sIreload {/all | router1 [router2] ...} reload all or a specific router(s)R+R,NR-s/allisinvalid device: (R)R.Rt do_reloadR0R1RRRRR@R'R=R3RR4R5R6R7(RR)RRR5R'((R RCsB     #cCsJd|iiGHdGHx/|iiiD]}d|i|ifGHq'WdS(sPrint the dynagen versionsdynagen sdynamips version(s):s %s: %sN(RRtVERSIONRRtdR tversion(RR)RE((R tdo_vers cCs |iGHdS(s/Print a list of commands that have been enteredN(Rt_hist(RR)((R tdo_hist scCsdS(sExits from the consoleiN((RR)((R tdo_exitscCsdS(sAExits from the console, but does not shut down the lab on DynageniN((RR)((R t do_disconnectscCsti|dS(s8Pass command to a system shell when line begins with '!'N(tostsystemR)(RR)((R tdo_shellscCsGd|jp|idjo|iiGHdSnti||dS(stelnet {/all | router1 [router2] ...} connect to the console(s) of all or a specific router(s) This is identical to the console command.R+R,N(R)R.Rt do_telnetR0Rt do_console(RR)((R ROs   cCsd|jp|idjo|iiGHdSn|id}d|idjo|iii}n`g}xV|idD]E}y|i |ii|Wqt j ot d|qXqWx|D]}yN|i pwn|idjod|i|ifGHwnt|iWqtj oqt tfj ot d |iqtj o}t |qXqWdS( saconsole {/all | router1 [router2] ...} connect to the console(s) of all or a specific router(s) R+R,NR-s/allsunknown device: trunningsSkipping %s device: %ssinvalid device: (R)R.RROR0R1RRRRRR7R6tisrouterRRttelnetR3RR4R5(RR)RRR5((R RP#s:   cCsBd|jp|idjo|iiGHdSn|id}|didjoyo|ii |di }xN|D]F}|iid}x(|D] }|d jo |d GHqqWq}WWq>tj otd q>ttfj otd |dq>tj o}t|q>Xn td dS(sNshow mac ethernet_switch_name show the mac address table of an ethernet switchR+R,NR-itmacis s100-OKismissing devicesinvalid device: sinvalid show command(R)R.Rtdo_showR0R1tparamstlowerRRtshow_mactresulttchunkstlinesR'R3R6R7RR4R5(RR)R[RVRYRZR5R'((R RUEs,   cCsd|jp|idjo|iiGHdSn|id}|didjoy'|ii |di diGHWqt j ot dqt tfj ot d |dqtj o}t |qXn t d dS( sPclear mac ethernet_switch_name clear the mac address table of an ethernet switchR+R,NR-iRTismissing devicesinvalid device: sinvalid clear command(R)R.Rtdo_clearR0R1RVRWRRt clear_macR3R6R7RR4R5(RR)RVR5((R R\\s  'c CsCd|jp|idjo|iiGHdSn|ii}d|idjo|ii i }n`g}xV|idD]E} y|i |ii | Wqt j otd| qXqWxh|D]`} y | i} Wn2tj o qntj o}|GHqnX| ii}| ii}|i|dt|o|dt|} n,|i|o |} ntd| ix|| iD]} y| i\}}Wntj o qnX|i d joE|| ijo5| || | d <| |ii!| it ValueErrorRWtconfigurationstwrite( RR)RiR>R5RR"RbR RfRRhRd((R R`osR       #cCsUd|jp|idjo|iiGHdSn|ii}d|idjo|iii }n`g}xV|idD]E}y|i |ii|Wqt j ot d|qXqWx|D]|}y||i|_WnStj o qn?t j od|iGHqntj o}|GHqnXd|iGHqWdS( sepush {/all | router1 [router2] ...} pushes router configs from the network file to the router's nvramR+R,Ns/allR-sunknown device: s)No saved configuration found for device: sPushed config to: (R)R.Rtdo_pushR0RRkR1RRRRR7R6RRcRR4R5(RR)R5RRRk((R Rms6    c Cs^d|jp|idjo|iiGHdSnyt|} Wn#tj o}t |dSnXt | djo|iiGHdSn| i } d| jo|i ii} n[g} xQ| D]I}y| i|i i|Wqtj ot d|dSqXqWyhti}tii|i i}tdti|djotd|ti|nWn0tj o$}t |ti|dSnXy%td t| ti| WnKtj o?td | }|i!d joti|dSq&nXx$| D]}y(t"i#|i$}|i&d d}WnXt'j o q-nDtj o}|GHq-n(t(j ot d |i)q-nXd|i)| ti*|i)dfGHy<t+| ti*|i)dd}|i-||i.Wq-t/j o$}t |ti|dSq-Xq-Wti|dS(sexport {/all | router1 [router2] ...} "directory" saves router configs individual files in "directory" Enclose the directory in quotes if there are spaces in the filespec.R+R,Nis/allsunknown device: scurrent dir is -> schanging dir to -> s making -> s:The directory "%s" already exists. Ok to overwrite (Y/N)? tys s#Unknown error exporting config for sExporting %s to "%s"s.cfgtw(0R)R.Rt do_exportR0tgetItemstitemsR4R5R6tlentpopt directoryRRRRRR7RLtgetcwdtnetdirtpathtdirnametFILENAMEtsubdirtdebugtchdirtOSErrorR!tmakedirst raw_inputRYRWtbase64t decodestringRcRdtreplaceRt TypeErrorRtseptopentfRltclosetIOError( RR)RYR{RdRwRR5RRrRRu((R Rps               $!    c Csd|jp|idjo|iiGHdSnt|} t| djo|iiGHdSn| i }yht i } t ii|ii}tdt i |djotd|t i|nWn#tj o} t| dSnXyt i|}Wn#tj o} t| dSnXx@|D]8}|didjo|d }d | jp || jod ||fGHyot|t i|d } | i }d |}| i"di#t$i%|i&}||ii(|_)Wqst*j o$} t| t i| dSqst+j otd |qst,j o} t| qsXqwq?q?Wt i| dS(simport {/all | router1 [router2] "directory" import all or individual configuration files Enclose the directory or filename in quotes if there are spaces in the filespec.R+R,Niscurrent dir is -> schanging dir to -> is.cfgs/allsImporting %s from "%s"trs ! sIgnoring unknown device: (-R)R.Rt do_importR0RqRrRsRpRtRuRLRvRwRxRyRRzR{R|R}R~R5R6tlistdirtcontentstfileRWRRRRtreadRdRtjoinRt encodestringR1tencodedRRcRR7R4( RR)RRR{RdRuRRR5RRrRw((R R s\                 c Csdddg}d|jp|idjo|iiGHdSnyit|iddjo%|idd\} }}}} n%|idd \} }}}d} Wn"tj o|iiGHdSnX| |iijod | GHdSn||jod |GHdSnti|}|pd |GHdSny4|id d \}}t|}t|}Wn tj od |GHdSnXy+|ii| i|i|||| WnCtj o} | GHdSn'tj od|| fGHdSnXdS(sfilter device interface filter_name direction [options] applies a connection filter Examples: filter R1 s1/0 freq_drop in 50 -- Drops 1 out of every 50 packets inbound to R1 s1/0 filter R1 s1/0 none in -- Removes all inbound filters from R1 s1/0t freq_droptcapturetnoneR+R,NR-iisUnknown device: sUnknown filter: s$Error parsing interface descriptor: is!No such interface %s on device %s(tfiltersR)R.Rt do_filterR0RsR1Rt interfacet filterNamet directiontoptionsR:RjRRt interface_retsearcht match_objtgrouptslotR"tinttfilterR4R5R3( RR)RRRRR"RRRR5R((R R[sL  %          +c Cs&hdd<dd<dd<dd<} d |jp|id jo|iiGHd Snyt|id d jo_|id d \}}}} y| i } | | } Wqt j od| GHd SqXn"|id d\}}}d } Wn"tj o|iiGHd SnX||iijod|GHd Snti|}|oay:|iddd \}}}t|}t|}Wqtj od|GHd SqXnFti|}|pd|GHd Sn|idd\}}d}| d job|iddddddgjo d} qq|iddgjo dGHd SqqdGHd Sn|di}y6|ii|i|i||dd| d |Wnhtj o} | GHd SnLtj od ||fGHd Sn't j od!||fGHd SnXd S("s^[no] capture device interface filename [link-type] Begins a capture of all packets in and out of "interface" on "device". Enclose the filename in quotes if there are spaces in the filespec. The capture file is written to the dynamips host. Link type is one of: ETH (Ethernet 10/100/1000) FR (Frame-Relay) HDLC (Cisco HDLC) PPP (PPP on serial) Captures of ethernet interfaces default to EN10MB, but for serial interfaces the link type must be specified. Examples: capture R1 f0/0 example.cap -- Capture packets in and out of f0/0 on R1 and write the output to example.cap capture R1 s0/0 example2.cap HDLC -- Capture and specify HDLC encapsulation no capture R1 s0/0 -- End the packet capturetETHtEN10MBtFRtFRELAYtHDLCtC_HDLCtPPPt PPP_SERIALR+R,NR-isInvalid linktype: isUnknown device: is$Error parsing interface descriptor: iR5tetRtfatgtgitstses8Error: Link type must be specified for serial interfacess=Error: Packet capture is not supported on this interface typeRtboths(Error: No such interface %s on device %ss1Error: Interface %s on device %s is not connected(!t linkTransformR)R.Rt do_captureR0RsR1RRtfilenametlinktypetupperR7R:RjRRRRRRtinttypeRR"Rtinterface_noport_reRWRR4R5R3R( RR)RRR"RRRRR5RR((R Rsr*              % 6c Cs+d|jp|idjo|iiGHdSnyt|idd\}} |idjoEt | iddjo| idd\}}qdGHdSnWnt j odGHdSnX||i ijod |GHdSnti|}|oay:|iddd \}}}t|}t|}Wqt j od |GHdSqXnFti|}|pd |GHdSn|idd\}}d }|d i}y+|i i|i|i||d dWnCtj o} | GHdSn'tj od||fGHdSnXdS(snegates a command R+R,NR-iRisError parsing commandsUnknown device: is$Error parsing interface descriptor: iRRs!No such interface %s on device %s(R)R.Rtdo_noR0R1tcommandRRWRsRRRjRRRRRRRRR"RRRR4R5R3( RR)RRR"RRRRRR5((R RsR         +c Cs#d|jp|idjo|iiGHdSny|idd\}}Wntj odGHdSnXt }xA|i i i D]-}|i|iijo t}PqqW|ptd|dSny|i|}Wntj o}|GHdSnXx|D] }|GHqWdS(ssend [host] commandstring send a raw hypervisor command to a dynamips server Examples: send bender hypervisor version -- Send the 'hypervisor version' command to the host named benderR+R,NR-isError parsing commands Unknown host (R)R.Rtdo_sendR0R1R RRjtFalsetfoundRRRR#RWtTrueR6tsend_rawRYR4R5R'( RR)R#R RRYRR'R5((R R&s4     cCsd|jp|idjo|iiGHdSny"|id}|i}|id} t | djo|iiGHdSn|djp |djo| d}|djoM|i i |i djod|GHdSnd GH|i i |it}n+|djo|i i |it}n|ih}d}x|D]}|id\}}t|dd !}d |jo d jno d } nd} d| |||fGH|||<|d7}qMWt |djo dGHqTdGHtdt |}|djo dGHdSnyt|}Wntj odGHdSnX|djp|t |jo dGHdSn|i i |it||d|||fGHn|djo9| \}}|i i |it|d||fGHnV|djoCt | djo| d}d} nTt | djo:| \}} | iddgjod| GHdSqnt|i i |i }|djod|GHdSn|i i!}|i i |i#i$}|i i |i#i%}|i&|o |} nE|i&|dt(|o|dt(|} nt)d|| idjom|i i |i*}|djp |d jo|i i |i+}qy|d}Wqd!|GHdSqXn/| idjo|i i-p(t.|i _-|i i/|i i-_0n||i i-|i i |i1t;j od1|GHdSnt<j o}|GHdSnXdS(2s9idlepc {get|set|show|save|idlemax|idlesleep|showdrift} device [value] idlepc save device [default] get, set, or show the online idlepc value(s) Examples: idlepc get r1 -- Get a list of the possible idlepc value(s) for router r1 idlepc show r1 -- Show the previously determined idlepc values for router r1 idlepc set r1 0x12345 -- Manually set r1's idlepc to 0x12345 idlepc save r1 -- Save r1's current idlepc value to the "router r1" section of your network file idlepc save r1 default -- Save r1's current idlepc value to the device defaults section of your network file (i.e. [[7200]]) idlepc save r1 db -- Save r1's current idlepc value to the idlepc database idlepc idlemax r1 1500 -- Commands for advanced manipulation of idlepc idlepc idlesleep r1 30 settings idlepc showdrift r1 R+R,Niitgettshows'%s already has an idlepc value applied.s)Please wait while gathering statistics...ii2i<t*R-s %s %2i: %s %ssNo idlepc values found s0Potentially better idlepc values marked with "*"sMEnter the number of the idlepc value to apply [1-%i] or ENTER for no change: sNo changes madesInvalid selectionsApplied idlepc value %s to %s tsettsaveitdefaulttdbs***Error: unknown keyword %ss0****Error: device %s has no idlepc value to saveRs&can't find server section for device: Rtc2600s9***Error: could not determine default section for device s ***Error: s3idlepc value for image "%s" written to the databaseR^sH***Error: section %s not found in network configuration file for host %sR9sidlepc value saved to section: t showdriftsCurrent idlemax value: %isCurrent idlesleep value: %iitidlemaxt idlesleeptOKs***Error: Unknown command s>***Error: Incorrect number of paramaters or invalid parameterss***Error: Unknown device: (=R)R.Rt do_idlepcR0R1RRWRVRsRRRR9R:tidlepropt IDLEPROPGETRYt IDLEPROPSHOWRttidlestiR'tvaluetcountRtiCounttflagRt selectionRjt IDLEPROPSETtlocationRaRbRR R"ReRfR!R6RRRhR;t ConfigObjtuseridledbfileRR<RlRR5RgRiR>RRt idlepcdriftR7R4(RR)RRiRRYRR"RbRVRRfR>RR9RR'RR5RR RRRRh((R RIs                                           cCsd|jp|idjo|iiGHdSn|id}|dd djo|i}d}n d GHdSd |jox~|i ii D]j}y|djo ||_nWqt j oqtj oqtj o}t|qXqWdSnx|D]w}y||i i|_Wqt j oqttfj otd |qtj o}t|qXqWdS( sLconfreg {/all | router1 [router2] <0x0-0xFFFF>} set the config register(s)R+R,NR-iit0xRs$***Error: No confreg value specifieds/allsinvalid device: (R)R.Rt do_confregR0R1RRttconfregRRRRR3RR4R5R6R7(RR)RRRR5R((R R sB      cCstii||dS(sGet help on commands 'help' or '?' with no arguments prints a list of commands for which help is available 'help ' or '? ' gives help on N(RRtdo_helpRR)(RR)((R RUscCs?tii|g|_h|_h|_|i|id Execute python statementsR+NR( R'Rtdo_pyR0RRt ExceptionR5t __class__(RR'R5((R Rs  cCstddS(sCalled on an input line when the command prefix is not recognized. In that case we execute the line as Python code. sunknown commandN(R6(RR'((R Rs($t__name__t __module__RR*R/R8R?RARCRGRIRJRKRNRORPRUR\R`RmRpRRRRRRRRRRRRRRR(((R R/sF $  )   !       "   8 % T ; 5 a 5 # F     cCsdk}|i}t|i|i}t|i|ii}|o_|i oT|i d|}|i d|}|i d|}t i |t idndS(s$telnet to the console port of deviceNs%hs%ps%df0.5(Rt telnetstringR!RRR$R"RR tnotelnetRRLRMttimetsleep(RRR RR"((R RSs   cCst|d|dS(Ni(tcmptrow1trow2(RR((R R&scCsVti|}yti|ddi}Wn!tij o}t |nX|S(sJUses the CSV module to split a string by whitespace, but respecting quotest delimiterR-N( tStringIORtinputtcsvtreadertnextRrtErrorR5R4(RR5RrR((R Rqs cCsdGt|GHdS(sPrint out an error messages *** Error:N(R!tmsg(R((R R6scCs$tdjodt|GHndS(s' Print string if debugging is true is DEBUG: N(t globaldebugR!tstring(R((R R|s R($R0RLRRtreRRRt dynamips_libR4tDynamipsWarningRRRt configobjRtcompilet IGNORECASERRRtDBGPHideChildrent NameErrorRtDEBUGGERRtreadlinet ImportErrorRRRSR&RqR6R|R(RRR4R&R6RRRRRRR RqRRSR RRRRRR|RRL((R R+s6?%   u      m fFc@sOdZdkZdkZdkZdkZdkZdkZdkZdkl Z l Z l Z l Z l Z dklZeideiZeideiZdZyeWnej o eZnXeZy dkZWnej onXdeifdYZd Zd Zd Z d Z!d Z"e#djondS(sR dynamips_lib.py Copyright (C) 2006 Greg Anuzelli Derived from recipe on ASPN Cookbook Recipe Author: James Thiele, http://www.eskimo.com/~jet/python/examples/cmd/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. N(s DynamipsErrorsDynamipsWarnings IDLEPROPGETs IDLEPROPSHOWs IDLEPROPSET(s ConfigObjs3^(g|gi|f|fa|a|at|s|se|e|et|p|po)([0-9]+)\/([0-9]+)$s)^(g|gi|f|fa|a|at|s|se|e|et|p|po)([0-9]+)$itConsolecBs:tZdZdZdZdZdZdZdZdZ d Z d Z d Z d Z d ZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZdZ d Z!d!Z"d"Z#RS(#NcCsDtii|dk}||_|ii}d|_d|_dS(Ns=> sNDynagen management console for Dynamips Copyright (c) 2005-2007 Greg Anuzelli ( tcmdtCmdt__init__tselft__main__t namespacet debugleveltprompttintro(RRR((t/usr/bin/console.pyR1s     c Csg}ddGHx|iiiD]}g}|id|iyO|i }|djo |i }n|d jo d }n|id|Wn't j o|id|i nXy|id|i Wn$t j o|idd nXy5|iid t|ii}|id |Wn$t j o|id dnXy|id|iWn$t j o|iddnX|i|q"W|itx$|D]}x|D] }|GqWHqWdS(slist List all devicess%-10s %-10s %-10s %-15s %-10stNametTypetStatetServerRs%-10stc3600tc7200t7200s always ont:s%-15ssn/aN(R R R RsConsole(ttableRRtdevicestvaluestdevicetrowtappendtnametmodeltchassistAttributeErrortadaptertstatetdynamipsthosttstrtporttservertconsoletsorttcon_cmptlinetitem( RtargsR#R(RRRR'R((R tdo_list=sJ        cCsrd|jp|idjo|iiGHdSn|id}d|jox|iiiD]r}y&x|i D]}|iGHqxWWqbt j oqbt j oqbtj o}t|qbXqbWdSnx|D]}y#|ii|i diGHWqt j oqtt fj otd|qtj o}t|qXqWdS(sKsuspend {/all | router1 [router2] ...} suspend all or a specific router(s)t?tNt s/allisinvalid device: (R)tstripRt do_suspendt__doc__tsplitRRRRtsuspendR't IndexErrorRt DynamipsErrorteterrortKeyError(RR)RRR5R'((R R/as:    #cCs?d|jp|idjo|iiGHdSn|id}d|jox|iiiD]}y|i djoM|ii o0|i |ii jo|ii |i |_ qd|iGHnx|iD]}|iGHqWWqbtj oqbtj oqbtj o}t|qbXqbWdSnx|D]}y|ii|}|i djoM|ii o0|i |ii jo|ii |i |_ qd|iGHnx|iD]}|iGHqWWqDtj oqDttfj otd|qDtj o}t|qDXqDWdS(sGstart {/all | router1 [router2] ...} start all or a specific router(s)R+R,NR-s/alls+Warining: Starting %s with no idle-pc valuesinvalid device: (R)R.Rtdo_startR0R1RRRRtidlepctNonet useridledbt imagenameRtstartR'R3RR4R5R6tdevnameR7(RR)R>RRR5R'((R R8sP   # # cCsrd|jp|idjo|iiGHdSn|id}d|jox|iiiD]r}y&x|i D]}|iGHqxWWqbt j oqbt j oqbtj o}t|qbXqbWdSnx|D]}y#|ii|i diGHWqt j oqtt fj otd|qtj o}t|qXqWdS(sEstop {/all | router1 [router2] ...} stop all or a specific router(s)R+R,NR-s/allisinvalid device: (R)R.Rtdo_stopR0R1RRRRtstopR'R3RR4R5R6R7(RR)RRR5R'((R R?s:    #cCsrd|jp|idjo|iiGHdSn|id}d|jox|iiiD]r}y&x|i D]}|iGHqxWWqbt j oqbt j oqbtj o}t|qbXqbWdSnx|D]}y#|ii|i diGHWqt j oqtt fj otd|qtj o}t|qXqWdS(sIresume {/all | router1 [router2] ...} resume all or a specific router(s)R+R,NR-s/allisinvalid device: (R)R.Rt do_resumeR0R1RRRRtresumeR'R3RR4R5R6R7(RR)RRR5R'((R RAs:    #cCsd|jp|idjo|iiGHdSn|id}d|jox|iiiD]}yHx|i D]}|iGHqxWx|i D]}|iGHqWWqbt j oqbtj oqbtj o}t|qbXqbWdSnx|D]}yB|ii|i diGH|ii|i diGHWq t j oq ttfj otd|q tj o}t|q Xq WdS(sIreload {/all | router1 [router2] ...} reload all or a specific router(s)R+R,NR-s/allisinvalid device: (R)R.Rt do_reloadR0R1RRRRR@R'R=R3RR4R5R6R7(RR)RRR5R'((R RCsB     #cCsJd|iiGHdGHx/|iiiD]}d|i|ifGHq'WdS(sPrint the dynagen versionsdynagen sdynamips version(s):s %s: %sN(RRtVERSIONRRtdR tversion(RR)RE((R tdo_vers cCs |iGHdS(s/Print a list of commands that have been enteredN(Rt_hist(RR)((R tdo_hist scCsdS(sExits from the consoleiN((RR)((R tdo_exitscCsdS(sAExits from the console, but does not shut down the lab on DynageniN((RR)((R t do_disconnectscCsti|dS(s8Pass command to a system shell when line begins with '!'N(tostsystemR)(RR)((R tdo_shellscCsGd|jp|idjo|iiGHdSnti||dS(stelnet {/all | router1 [router2] ...} connect to the console(s) of all or a specific router(s) This is identical to the console command.R+R,N(R)R.Rt do_telnetR0Rt do_console(RR)((R ROs   cCsd|jp|idjo|iiGHdSn|id}d|idjo|iii}n`g}xV|idD]E}y|i |ii|Wqt j ot d|qXqWx|D]}yN|i pwn|idjod|i|ifGHwnt|iWqtj oqt tfj ot d |iqtj o}t |qXqWdS( saconsole {/all | router1 [router2] ...} connect to the console(s) of all or a specific router(s) R+R,NR-s/allsunknown device: trunningsSkipping %s device: %ssinvalid device: (R)R.RROR0R1RRRRRR7R6tisrouterRRttelnetR3RR4R5(RR)RRR5((R RP#s:   cCsBd|jp|idjo|iiGHdSn|id}|didjoyo|ii |di }xN|D]F}|iid}x(|D] }|d jo |d GHqqWq}WWq>tj otd q>ttfj otd |dq>tj o}t|q>Xn td dS(sNshow mac ethernet_switch_name show the mac address table of an ethernet switchR+R,NR-itmacis s100-OKismissing devicesinvalid device: sinvalid show command(R)R.Rtdo_showR0R1tparamstlowerRRtshow_mactresulttchunkstlinesR'R3R6R7RR4R5(RR)R[RVRYRZR5R'((R RUEs,   cCsd|jp|idjo|iiGHdSn|id}|didjoy'|ii |di diGHWqt j ot dqt tfj ot d |dqtj o}t |qXn t d dS( sPclear mac ethernet_switch_name clear the mac address table of an ethernet switchR+R,NR-iRTismissing devicesinvalid device: sinvalid clear command(R)R.Rtdo_clearR0R1RVRWRRt clear_macR3R6R7RR4R5(RR)RVR5((R R\\s  'c CsCd|jp|idjo|iiGHdSn|ii}d|idjo|ii i }n`g}xV|idD]E} y|i |ii | Wqt j otd| qXqWxh|D]`} y | i} Wn2tj o qntj o}|GHqnX| ii}| ii}|i|dt|o|dt|} n,|i|o |} ntd| ix|| iD]} y| i\}}Wntj o qnX|i d joE|| ijo5| || | d <| |ii!| it ValueErrorRWtconfigurationstwrite( RR)RiR>R5RR"RbR RfRRhRd((R R`osR       #cCsUd|jp|idjo|iiGHdSn|ii}d|idjo|iii }n`g}xV|idD]E}y|i |ii|Wqt j ot d|qXqWx|D]|}y||i|_WnStj o qn?t j od|iGHqntj o}|GHqnXd|iGHqWdS( sepush {/all | router1 [router2] ...} pushes router configs from the network file to the router's nvramR+R,Ns/allR-sunknown device: s)No saved configuration found for device: sPushed config to: (R)R.Rtdo_pushR0RRkR1RRRRR7R6RRcRR4R5(RR)R5RRRk((R Rms6    c Cs^d|jp|idjo|iiGHdSnyt|} Wn#tj o}t |dSnXt | djo|iiGHdSn| i } d| jo|i ii} n[g} xQ| D]I}y| i|i i|Wqtj ot d|dSqXqWyhti}tii|i i}tdti|djotd|ti|nWn0tj o$}t |ti|dSnXy%td t| ti| WnKtj o?td | }|i!d joti|dSq&nXx$| D]}y(t"i#|i$}|i&d d}WnXt'j o q-nDtj o}|GHq-n(t(j ot d |i)q-nXd|i)| ti*|i)dfGHy<t+| ti*|i)dd}|i-||i.Wq-t/j o$}t |ti|dSq-Xq-Wti|dS(sexport {/all | router1 [router2] ...} "directory" saves router configs individual files in "directory" Enclose the directory in quotes if there are spaces in the filespec.R+R,Nis/allsunknown device: scurrent dir is -> schanging dir to -> s making -> s:The directory "%s" already exists. Ok to overwrite (Y/N)? tys s#Unknown error exporting config for sExporting %s to "%s"s.cfgtw(0R)R.Rt do_exportR0tgetItemstitemsR4R5R6tlentpopt directoryRRRRRR7RLtgetcwdtnetdirtpathtdirnametFILENAMEtsubdirtdebugtchdirtOSErrorR!tmakedirst raw_inputRYRWtbase64t decodestringRcRdtreplaceRt TypeErrorRtseptopentfRltclosetIOError( RR)RYR{RdRwRR5RRrRRu((R Rps               $!    c Csd|jp|idjo|iiGHdSnt|} t| djo|iiGHdSn| i }yht i } t ii|ii}tdt i |djotd|t i|nWn#tj o} t| dSnXyt i|}Wn#tj o} t| dSnXx@|D]8}|didjo|d }d | jp || jod ||fGHyot|t i|d } | i }d |}| i"di#t$i%|i&}||ii(|_)Wqst*j o$} t| t i| dSqst+j otd |qst,j o} t| qsXqwq?q?Wt i| dS(simport {/all | router1 [router2] "directory" import all or individual configuration files Enclose the directory or filename in quotes if there are spaces in the filespec.R+R,Niscurrent dir is -> schanging dir to -> is.cfgs/allsImporting %s from "%s"trs ! sIgnoring unknown device: (-R)R.Rt do_importR0RqRrRsRpRtRuRLRvRwRxRyRRzR{R|R}R~R5R6tlistdirtcontentstfileRWRRRRtreadRdRtjoinRt encodestringR1tencodedRRcRR7R4( RR)RRR{RdRuRRR5RRrRw((R R s\                 c Csdddg}d|jp|idjo|iiGHdSnyit|iddjo%|idd\} }}}} n%|idd \} }}}d} Wn"tj o|iiGHdSnX| |iijod | GHdSn||jod |GHdSnti|}|pd |GHdSny4|id d \}}t|}t|}Wn tj od |GHdSnXy+|ii| i|i|||| WnCtj o} | GHdSn'tj od|| fGHdSnXdS(sfilter device interface filter_name direction [options] applies a connection filter Examples: filter R1 s1/0 freq_drop in 50 -- Drops 1 out of every 50 packets inbound to R1 s1/0 filter R1 s1/0 none in -- Removes all inbound filters from R1 s1/0t freq_droptcapturetnoneR+R,NR-iisUnknown device: sUnknown filter: s$Error parsing interface descriptor: is!No such interface %s on device %s(tfiltersR)R.Rt do_filterR0RsR1Rt interfacet filterNamet directiontoptionsR:RjRRt interface_retsearcht match_objtgrouptslotR"tinttfilterR4R5R3( RR)RRRRR"RRRR5R((R R[sL  %          +c Cs&hdd<dd<dd<dd<} d |jp|id jo|iiGHd Snyt|id d jo_|id d \}}}} y| i } | | } Wqt j od| GHd SqXn"|id d\}}}d } Wn"tj o|iiGHd SnX||iijod|GHd Snti|}|oay:|iddd \}}}t|}t|}Wqtj od|GHd SqXnFti|}|pd|GHd Sn|idd\}}d}| d job|iddddddgjo d} qq|iddgjo dGHd SqqdGHd Sn|di}y6|ii|i|i||dd| d |Wnhtj o} | GHd SnLtj od ||fGHd Sn't j od!||fGHd SnXd S("s^[no] capture device interface filename [link-type] Begins a capture of all packets in and out of "interface" on "device". Enclose the filename in quotes if there are spaces in the filespec. The capture file is written to the dynamips host. Link type is one of: ETH (Ethernet 10/100/1000) FR (Frame-Relay) HDLC (Cisco HDLC) PPP (PPP on serial) Captures of ethernet interfaces default to EN10MB, but for serial interfaces the link type must be specified. Examples: capture R1 f0/0 example.cap -- Capture packets in and out of f0/0 on R1 and write the output to example.cap capture R1 s0/0 example2.cap HDLC -- Capture and specify HDLC encapsulation no capture R1 s0/0 -- End the packet capturetETHtEN10MBtFRtFRELAYtHDLCtC_HDLCtPPPt PPP_SERIALR+R,NR-isInvalid linktype: isUnknown device: is$Error parsing interface descriptor: iR5tetRtfatgtgitstses8Error: Link type must be specified for serial interfacess=Error: Packet capture is not supported on this interface typeRtboths(Error: No such interface %s on device %ss1Error: Interface %s on device %s is not connected(!t linkTransformR)R.Rt do_captureR0RsR1RRtfilenametlinktypetupperR7R:RjRRRRRRtinttypeRR"Rtinterface_noport_reRWRR4R5R3R( RR)RRR"RRRRR5RR((R Rsr*              % 6c Cs+d|jp|idjo|iiGHdSnyt|idd\}} |idjoEt | iddjo| idd\}}qdGHdSnWnt j odGHdSnX||i ijod |GHdSnti|}|oay:|iddd \}}}t|}t|}Wqt j od |GHdSqXnFti|}|pd |GHdSn|idd\}}d }|d i}y+|i i|i|i||d dWnCtj o} | GHdSn'tj od||fGHdSnXdS(snegates a command R+R,NR-iRisError parsing commandsUnknown device: is$Error parsing interface descriptor: iRRs!No such interface %s on device %s(R)R.Rtdo_noR0R1tcommandRRWRsRRRjRRRRRRRRR"RRRR4R5R3( RR)RRR"RRRRRR5((R RsR         +c Cs#d|jp|idjo|iiGHdSny|idd\}}Wntj odGHdSnXt }xA|i i i D]-}|i|iijo t}PqqW|ptd|dSny|i|}Wntj o}|GHdSnXx|D] }|GHqWdS(ssend [host] commandstring send a raw hypervisor command to a dynamips server Examples: send bender hypervisor version -- Send the 'hypervisor version' command to the host named benderR+R,NR-isError parsing commands Unknown host (R)R.Rtdo_sendR0R1R RRjtFalsetfoundRRRR#RWtTrueR6tsend_rawRYR4R5R'( RR)R#R RRYRR'R5((R R&s4     cCsd|jp|idjo|iiGHdSny"|id}|i}|id} t | djo|iiGHdSn|djp |djo| d}|djoM|i i |i djod|GHdSnd GH|i i |it}n+|djo|i i |it}n|ih}d}x|D]}|id\}}t|dd !}d |jo d jno d } nd} d| |||fGH|||<|d7}qMWt |djo dGHqTdGHtdt |}|djo dGHdSnyt|}Wntj odGHdSnX|djp|t |jo dGHdSn|i i |it||d|||fGHn|djo9| \}}|i i |it|d||fGHnV|djoCt | djo| d}d} nTt | djo:| \}} | iddgjod| GHdSqnt|i i |i }|djod|GHdSn|i i!}|i i |i#i$}|i i |i#i%}|i&|o |} nE|i&|dt(|o|dt(|} nt)d|| idjom|i i |i*}|djp |d jo|i i |i+}qy|d}Wqd!|GHdSqXn/| idjo|i i-p(t.|i _-|i i/|i i-_0n||i i-|i i |i1t;j od1|GHdSnt<j o}|GHdSnXdS(2s9idlepc {get|set|show|save|idlemax|idlesleep|showdrift} device [value] idlepc save device [default] get, set, or show the online idlepc value(s) Examples: idlepc get r1 -- Get a list of the possible idlepc value(s) for router r1 idlepc show r1 -- Show the previously determined idlepc values for router r1 idlepc set r1 0x12345 -- Manually set r1's idlepc to 0x12345 idlepc save r1 -- Save r1's current idlepc value to the "router r1" section of your network file idlepc save r1 default -- Save r1's current idlepc value to the device defaults section of your network file (i.e. [[7200]]) idlepc save r1 db -- Save r1's current idlepc value to the idlepc database idlepc idlemax r1 1500 -- Commands for advanced manipulation of idlepc idlepc idlesleep r1 30 settings idlepc showdrift r1 R+R,Niitgettshows'%s already has an idlepc value applied.s)Please wait while gathering statistics...ii2i<t*R-s %s %2i: %s %ssNo idlepc values found s0Potentially better idlepc values marked with "*"sMEnter the number of the idlepc value to apply [1-%i] or ENTER for no change: sNo changes madesInvalid selectionsApplied idlepc value %s to %s tsettsaveitdefaulttdbs***Error: unknown keyword %ss0****Error: device %s has no idlepc value to saveRs&can't find server section for device: Rtc2600s9***Error: could not determine default section for device s ***Error: s3idlepc value for image "%s" written to the databaseR^sH***Error: section %s not found in network configuration file for host %sR9sidlepc value saved to section: t showdriftsCurrent idlemax value: %isCurrent idlesleep value: %iitidlemaxt idlesleeptOKs***Error: Unknown command s>***Error: Incorrect number of paramaters or invalid parameterss***Error: Unknown device: (=R)R.Rt do_idlepcR0R1RRWRVRsRRRR9R:tidlepropt IDLEPROPGETRYt IDLEPROPSHOWRttidlestiR'tvaluetcountRtiCounttflagRt selectionRjt IDLEPROPSETtlocationRaRbRR R"ReRfR!R6RRRhR;t ConfigObjtuseridledbfileRR<RlRR5RgRiR>RRt idlepcdriftR7R4(RR)RRiRRYRR"RbRVRRfR>RR9RR'RR5RR RRRRh((R RIs                                           cCsd|jp|idjo|iiGHdSn|id}|dd djo|i}d}n d GHdSd |jox~|i ii D]j}y|djo ||_nWqt j oqtj oqtj o}t|qXqWdSnx|D]w}y||i i|_Wqt j oqttfj otd |qtj o}t|qXqWdS( sLconfreg {/all | router1 [router2] <0x0-0xFFFF>} set the config register(s)R+R,NR-iit0xRs$***Error: No confreg value specifieds/allsinvalid device: (R)R.Rt do_confregR0R1RRttconfregRRRRR3RR4R5R6R7(RR)RRRR5R((R R sB      cCstii||dS(sGet help on commands 'help' or '?' with no arguments prints a list of commands for which help is available 'help ' or '? ' gives help on N(RRtdo_helpRR)(RR)((R RUscCs?tii|g|_h|_h|_|i|id Execute python statementsR+NR( R'Rtdo_pyR0RRt ExceptionR5t __class__(RR'R5((R Rs  cCstddS(sCalled on an input line when the command prefix is not recognized. In that case we execute the line as Python code. sunknown commandN(R6(RR'((R Rs($t__name__t __module__RR*R/R8R?RARCRGRIRJRKRNRORPRUR\R`RmRpRRRRRRRRRRRRRRR(((R R/sF $  )   !       "   8 % T ; 5 a 5 # F     cCsdk}|i}t|i|i}t|i|ii}|o_|i oT|i d|}|i d|}|i d|}t i |t idndS(s$telnet to the console port of deviceNs%hs%ps%df0.5(Rt telnetstringR!RRR$R"RR tnotelnetRRLRMttimetsleep(RRR RR"((R RSs   cCst|d|dS(Ni(tcmptrow1trow2(RR((R R&scCsVti|}yti|ddi}Wn!tij o}t |nX|S(sJUses the CSV module to split a string by whitespace, but respecting quotest delimiterR-N( tStringIORtinputtcsvtreadertnextRrtErrorR5R4(RR5RrR((R Rqs cCsdGt|GHdS(sPrint out an error messages *** Error:N(R!tmsg(R((R R6scCs$tdjodt|GHndS(s' Print string if debugging is true is DEBUG: N(t globaldebugR!tstring(R((R R|s R($R0RLRRtreRRRt dynamips_libR4tDynamipsWarningRRRt configobjRtcompilet IGNORECASERRRtDBGPHideChildrent NameErrorRtDEBUGGERRtreadlinet ImportErrorRRRSR&RqR6R|R(RRR4R&R6RRRRRRR RqRRSR RRRRRR|RRL((R R+s6?%   u      #!/usr/bin/env python """ dynagen Copyright (C) 2006 Greg Anuzelli This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ import sys, os, re, traceback from console import Console from dynamips_lib import Dynamips, PA_C7200_IO_FE, PA_A1, PA_FE_TX, PA_4T, PA_8T, \ PA_4E, PA_8E, PA_POS_OC3, Router, C7200, C3600, Leopard_2FE, NM_1FE_TX, NM_1E, NM_4E, \ NM_16ESW, NM_4T, DynamipsError, DynamipsWarning, Bridge, FRSW, ATMSW, ETHSW, \ NIO_udp, NIO_linux_eth, NIO_gen_eth, NIO_tap, NIO_unix, NIO_vde, nosend, setdebug, \ IDLEPROPGET, IDLEPROPSHOW, IDLEPROPSET, C2691, C3725, C3745, GT96100_FE, C2600, \ CISCO2600_MB_1E, CISCO2600_MB_2E, CISCO2600_MB_1FE, CISCO2600_MB_2FE, PA_2FE_TX, \ PA_GE, PA_C7200_IO_2FE, PA_C7200_IO_GE_E, C1700, CISCO1710_MB_1FE_1E, C1700_MB_1ETH, \ DEVICETUPLE, DynamipsVerError, DynamipsErrorHandled, WICS, NM_CIDS, NM_NAM from validate import Validator from configobj import ConfigObj, flatten_errors from optparse import OptionParser # Constants VERSION = '0.10.1.090807' CONFIGSPECPATH = [ "/usr/share/dynagen", "/usr/local/share" ] CONFIGSPEC = 'configspec' INIPATH = [ "/etc", "/usr/local/etc" ] INIFILE = 'dynagen.ini' MODELTUPLE = (C1700, C2600, C2691, C3725, C3745, C3600, C7200) # A tuple of known model objects ADAPTER_TRANSFORM = { "PA-C7200-IO-FE" : PA_C7200_IO_FE, "PA-C7200-IO-2FE" : PA_C7200_IO_2FE, "PA-C7200-IO-GE-E" : PA_C7200_IO_GE_E, "PA-A1" : PA_A1, "PA-FE-TX" : PA_FE_TX, "PA-2FE-TX" : PA_2FE_TX, "PA-GE" : PA_GE, "PA-4T" : PA_4T, "PA-8T" : PA_8T, "PA-4E" : PA_4E, "PA-8E" : PA_8E, "PA-POS-OC3" : PA_POS_OC3, "NM-1FE-TX" : NM_1FE_TX, "NM-1E" : NM_1E, "NM-4E": NM_4E, "NM-4T": NM_4T, "NM-16ESW": NM_16ESW, "Leopard-2FE": Leopard_2FE, "GT96100-FE": GT96100_FE, "CISCO2600-MB-1E": CISCO2600_MB_1E, "CISCO2600-MB-2E": CISCO2600_MB_2E, "CISCO2600-MB-1FE": CISCO2600_MB_1FE, "CISCO2600-MB-2FE": CISCO2600_MB_2FE, "CISCO1710-MB-1FE-1E": CISCO1710_MB_1FE_1E, "C1700-MB-1ETH": C1700_MB_1ETH, "NM-CIDS": NM_CIDS, "NM-NAM": NM_NAM } # Globals debuglevel = 0 # The debug level globaludp = 10000 # The default base UDP port for NIO notelnet = False # Flag to disable telnet (for gDynagen) useridledbfile = '' # The filespec of the idle database useridledb = None # Dictionary of idle-pc values from the user database, indexed by image name handled = False # An exception has been handled already globalconfig = {} # A global copy of the config that console.py can access configurations = {} # A global copy of all b64 exported configurations from the network file indexed by devicename ghosteddevices = {} # A dict of devices that will use ghosted IOS indexed by device name ghostsizes = {} # A dict of the sizes of the ghosts dynamips = {} # A dictionary of dynamips objects, indexed by dynamips server name devices = {} # Dictionary of device objects, indexed by name bridges = {} # Dictionary of bridge objects, indexed by name autostart = {} # Dictionary that tracks autostart, indexed by router name interface_re = re.compile(r"""^(g|gi|f|fa|a|at|s|se|e|et|p|po|i|id|IDS-Sensor|an|Analysis-Module)([0-9]+)\/([0-9]+)$""", re.IGNORECASE) # Regex matching intefaces interface_noport_re = re.compile(r"""^(g|gi|f|fa|a|at|s|se|e|et|p|po)([0-9]+)$""", re.IGNORECASE) # Regex matching intefaces with out a port (e.g. "f0") number_re = re.compile(r"""^[0-9]*$""") # Regex matching numbers mapint_re = re.compile(r"""^([0-9]*):([0-9]*)$""") # Regex matching Frame Relay mappings or ATM vpi mappings mapvci_re = re.compile(r"""^([0-9]*):([0-9]*):([0-9]*)$""") # Regex matching ATM vci mappings ethswint_re = re.compile(r"""^([0-9]+)""") # Regex mating a number (means an Ethernet switchport config) # determine if we are in the debugger try: DBGPHideChildren except NameError: DEBUGGER = False else: DEBUGGER = True def setdefaults(router, defaults): """ Apply the global defaults to this router instance """ for option in defaults: setproperty(router, option, defaults[option]) def setproperty(device, option, value): """ If it is valid, set the option and return True. Otherwise return False """ global configurations, ghosteddevices, globalconfig if type(device) in MODELTUPLE: # Is it a "simple" property? If so set it and forget it. if option in ('rom', 'clock', 'npe', 'ram', 'nvram', 'confreg', 'midplane', 'console', 'aux', 'mac', 'mmap', 'idlepc', 'exec_area', 'disk0', 'disk1', 'iomem', 'idlemax', 'idlesleep', 'oldidle', 'sparsemem'): setattr(device, option, value) return True # Is it a filespec? If so encase it in quotes to protect spaces if option in ('image', 'cnfg'): value = '"' + value + '"' setattr(device, option, value) return True # Is it a config? If so save it for later if option == 'configuration': configurations[device.name] = value if option == 'ghostios': ghosteddevices[device.name] = value if option == 'ghostsize': ghostsizes[device.name] = value # is it a slot designation? if option[:4].lower() == 'slot': try: slot = int(option.split('=')[0][4:]) except ValueError: print "warning: ignoring unknown config item: " + option return False # Attempt to insert the requested adapter in the requested slot # BaseAdapter will throw a DynamipsError if the adapter is not # supported in this slot, or if it is an invalid slot for this # device if value in ADAPTER_TRANSFORM: device.slot[slot] = ADAPTER_TRANSFORM[value](device, slot) else: doerror('Unknown adapter %s specified for slot %i on router: %s' % (value, slot, device.name)) return True # is it a wic designation? if option[:3].lower() == 'wic': try: (slot,subslot) = (int(option.split('/')[0][-1]), int(option.split('/')[1])) except IndexError: print "warning: ignoring unknown config item: %s = %s" % (option, value) return False except ValueError: print "warning: ignoring unknown config item: %s = %s" % (option, value) return False device.installwic(value, slot, subslot) return True return False def connect(router, source, dest): """ Connect a router to something router: a router object source: a string specifying the local interface dest: a string specifying a device and a remote interface, LAN, a raw NIO """ match_obj = interface_re.search(source) if not match_obj: # is this an interface without a port designation (e.g. "f0")? match_obj = interface_noport_re.search(source) if not match_obj: return False else: (pa1, port1) = match_obj.group(1,2) slot1 = 0 else: (pa1, slot1, port1) = match_obj.group(1,2,3) if pa1[:2].lower() == 'an': # need to use two chars for Analysis-Module pa1 = pa1[:2].lower() else: pa1 = pa1.lower()[0] # Only care about first character slot1 = int(slot1) port1 = int(port1) try: (devname, interface) = dest.split(' ') except ValueError: # Must be either a NIO or malformed if not dest[:4].lower() == 'nio_': debug('Malformed destination:' + str(dest)) return False try: debug('A NETIO: ' + str(dest)) (niotype, niostring) = dest.split(':',1) except ValueError: debug('Malformed NETIO:' + str(dest)) return False # Process the netio if niotype.lower() == 'nio_linux_eth': debug('NIO_linux_eth ' + str(dest)) smartslot(router, pa1, slot1, port1) router.slot[slot1].nio(port1, nio=NIO_linux_eth(router.dynamips, interface=niostring)) elif niotype.lower() == 'nio_gen_eth': debug('gen_eth ' + str(dest)) smartslot(router, pa1, slot1, port1) router.slot[slot1].nio(port1, nio=NIO_gen_eth(router.dynamips, interface=niostring)) elif niotype.lower() == 'nio_udp': debug('udp ' + str(dest)) (udplocal, remotehost, udpremote) = niostring.split(':',2) smartslot(router, pa1, slot1, port1) router.slot[slot1].nio(port1, nio=NIO_udp(router.dynamips, int(udplocal), str(remotehost), int(udpremote))) elif niotype.lower() == 'nio_null': debug('nio null') smartslot(router, pa1, slot1, port1) router.slot[slot1].nio(port1, nio=NIO_null(router.dynamips)) elif niotype.lower() == 'nio_tap': debug('nio tap ' + str(dest)) smartslot(router, pa1, slot1, port1) router.slot[slot1].nio(port1, nio=NIO_tap(router.dynamips, niostring)) elif niotype.lower() == 'nio_unix': debug('unix ' + str(dest)) (unixlocal, unixremote) = niostring.split(':',1) smartslot(router, pa1, slot1, port1) router.slot[slot1].nio(port1, nio=NIO_unix(router.dynamips, unixlocal, unixremote)) elif niotype.lower() == 'nio_vde': debug('vde ' + str(dest)) (controlsock, localsock) = niostring.split(':',1) smartslot(router, pa1, slot1, port1) router.slot[slot1].nio(port1, nio=NIO_vde(router.dynamips, controlsock, localsock)) else: # Bad NIO return False return True match_obj = interface_re.search(interface) if match_obj: # Connecting to another interface (pa2, slot2, port2) = match_obj.group(1,2,3) else: match_obj = interface_noport_re.search(interface) if match_obj: # Connecting to another "portless" interface e.g. "f0" (pa2, port2) = match_obj.group(1,2) slot2 = 0 # If either of the interface formats matched... if match_obj: if pa2[:2].lower() == 'an': # need to use two chars for Analysis-Module pa2 = pa2[:2].lower() else: pa2 = pa2.lower()[0] # Only care about first character slot2 = int(slot2) port2 = int(port2) # Does the device we are trying to connect to actually exist? if not devices.has_key(devname): line = router.name + ' ' + source + ' = ' + dest doerror('Nonexistent device "' + devname + '" in line: \n ' + line) # If interfaces don't exist, create them smartslot(router, pa1, slot1, port1) smartslot(devices[devname], pa2, slot2, port2) router.slot[slot1].connect(pa1, port1, devices[devname].dynamips, devices[devname].slot[slot2], pa2, port2) return True if devname.lower() == 'lan': debug('a LAN interface ' + str(dest)) # If interface doesn't exist, create it smartslot(router, pa1, slot1, port1) if not bridges.has_key(interface): # If this LAN doesn't already exist, create it bridges[interface] = Bridge(router.dynamips, name=interface) router.slot[slot1].connect(pa1, port1, bridges[interface].dynamips, bridges[interface], 'f') return True match_obj = number_re.search(interface) if match_obj: port2 = int(interface) # Should be a swtich port if devname not in devices: debug('Unknown device ' + str(devname)) return False debug('a switch port: ' + str(dest)) # If interface doesn't exist, create it smartslot(router, pa1, slot1, port1) if devices[devname].adapter == 'ETHSW': pa2 = 'f' # Ethernet switches are FastEthernets (for our purposes anyway) elif devices[devname].adapter == 'FRSW': pa2 = 's' # Frame Relays switches are Serials elif devices[devname].adapter == 'ATMSW': pa2 = 'a' # And ATM switches are, well, ATM interfaces else: return False router.slot[slot1].connect(pa1, port1, devices[devname].dynamips, devices[devname], pa2 , port2) return True else: # Malformed debug('Malformed destination interface: ' + str(dest)) return False def smartslot(router, pa, slot, port): """ Pick the right adapter for the desired interface type, and insert it router: a router object pa: a one or two character string 'gi', 'fa', 'et', 'se', 'at', or 'po' slot: slot number port: port number """ if pa[:2].lower() == 'an': # Need to handle the Analysis-Module with two chars, because 'a' is an pa = pa[:2].lower() else: pa = pa[0].lower() try: if router.slot[slot] != None: # Already a PA in this slot. Does this adapter already provide the # interface we need? try: router.slot[slot].interfaces[pa][port] except (KeyError, IndexError): # No it is not. Does this adapter provide WIC slots? try: router.slot[slot].wics[0] except KeyError: # No wic slots. Must be an error doerror("Invalid slot %i specified for device %s" % (slot, router.name)) except IndexError: doerror("Attempt to connect to non-existent interface in slot %i on device %s" % (slot, router.name)) else: # Can the requested interface be provided by a WIC? if (router.model == 'c2600' or router.model in ['c3725', 'c3745', 'c2691'] or (router.model == 'c1700' and router.chassis in ['1720', '1721', '1750', '1751', '1760'])) and (pa == 's' or pa == 'e'): if pa == 'e' and (router.model != 'c1700' or router.chassis not in ['1720', '1721', '1750', '1751', '1760']): # Ethernet WIC only supported in these 1700 models doerror("Ethernet adapter not supported on port %i for device %s" % (port, router.name)) if pa == 'e': chosenwic = 'WIC-1ENET' elif pa == 's': chosenwic = 'WIC-2T' if router.model == 'c1700' and router.chassis in ['1751', '1760']: # WIC selection is pretty straight-forward here pass else: # Less obvious here. # If you want an interface of a given type on port n, # there either needs to already be interfaces of that same type # in ports 0 - (n-1) # If not, you need to have enough empty WIC slots to get you there # What a mess. # Since the number of cases is simple for now, I'll use a bunch of # if ... then stuff. But ss the number of WICs supported increases # I'll need to come up with some loftier logic. if pa == 'e': for i in range(0, port+1): # install WIC-1ENETs until we've added enough to get he port we need router.installwic(chosenwic, slot) return True if pa == 's': # just fill it up with WIC-2Ts until I come up a # better solution for i in range(0, (port/2)+1): router.installwic(chosenwic, slot) return True else: return True except KeyError: doerror("Invalid slot %i specified for device %s" % (slot, router.name)) """ Note to self: One of these days you should do this section right. Programatically build a matrix of default adapters for a given Adapter, model, slot, and chassis using this structure: smartslotmatrix = { 'e' : { # Adapter '2600' : { # Router Model { '0' : { # Slot '2620':'1FE', # Chassis (if applicable) '2621':'2FE' } } } } This would be a good idiom to use elsewhere within the app as well """ if pa == 'g': if slot == 0: if port == 0: router.slot[slot] = PA_C7200_IO_GE_E(router, slot) elif port >= 1 and port <= 3 and router.npe == 'npe-g2': pass else: doerror('Use of Gi0/1-3 requires use of an NPE-G2 on router: ' + router.name) else: router.slot[slot] = PA_GE(router, slot) if pa == 'f': if router.model == 'c3600': if router.chassis == '3660' and slot == 0: router.slot[slot] = Leopard_2FE(router,slot) else: router.slot[slot] = NM_1FE_TX(router, slot) elif router.model in ['c2691', 'c3725', 'c3745']: if slot == 0: router.slot[slot] = GT96100_FE(router,slot) else: router.slot[slot] = NM_1FE_TX(router, slot) elif router.model in ['c2600']: if slot == 0: chassis2600transform = { "2620" : CISCO2600_MB_1FE, "2621" : CISCO2600_MB_2FE, "2610XM": CISCO2600_MB_1FE, "2611XM": CISCO2600_MB_2FE, "2620XM": CISCO2600_MB_1FE, "2621XM": CISCO2600_MB_2FE, "2650XM": CISCO2600_MB_1FE, "2651XM": CISCO2600_MB_2FE } try: router.slot[slot] = chassis2600transform[router.chassis](router, slot) except KeyError: doerror("Chassis %s does not support FastEthernet adapter in slot 0 for device %s." % (router.chassis, router.name)) else: router.slot[slot] = NM_1FE_TX(router, slot) else: if slot == 0: router.slot[slot] = PA_C7200_IO_FE(router, slot) else: router.slot[slot] = PA_2FE_TX(router, slot) return True if pa == 'e': if router.model == 'c2600': if slot == 0: chassis2600transform = { "2610" : CISCO2600_MB_1E, "2611" : CISCO2600_MB_2E } try: router.slot[slot] = chassis2600transform[router.chassis](router, slot) except KeyError: doerror("Chassis %s does not support Ethernet adapter in slot 0 for device %s." % (router.chassis, router.name)) else: router.slot[slot] = NM_4E(router, slot) elif router.model == 'c3600': router.slot[slot] = NM_4E(router, slot) elif router.model in ['c2691', 'c3725', 'c3745']: doerror("Unsuppported interface %s%i/%i specified for device: %s" % (pa, slot, port, router.name)) elif router.model == 'c7200': router.slot[slot] = PA_8E(router, slot) elif router.model == 'c1700' and slot == 0: doerror("Unsuppported interface %s%i/%i specified for device: %s\nIf you are trying to use an Ethernet WIC, it must be manually specified in your NET file (e.g. 'WIC0/0 = WIC-1ENET')." % (pa, slot, port, router.name)) else: doerror("Unsuppported interface %s%i/%i specified for device: %s" % (pa, slot, port, router.name)) return True if pa == 's': if router.model in ['c2600']: doerror("Unsuppported interface %s%i/%i specified for device: %s" % (pa, slot, port, router.name)) elif router.model in ['c2691', 'c3725', 'c3745', 'c3600']: router.slot[slot] = NM_4T(router, slot) elif router.model == 'c7200': router.slot[slot] = PA_8T(router, slot) elif router.model in ['c2691', 'c3725', 'c3745', 'c1700', 'c2600'] and slot == 0: doerror("Unsuppported interface %s%i/%i specified for device: %s\nIf you are trying to use a Serial WIC, it must be manually specified in your NET file (e.g. 'WIC0/0 = WIC-2T')." % (pa, slot, port, router.name)) else: doerror("Unsuppported interface %s%i/%i specified for device: %s" % (pa, slot, port, router.name)) return True if pa == 'a': if router.model in ['c2600', 'c2691', 'c3725', 'c3745', 'c3600']: doerror("Unsuppported interface %s%i/%i specified for device: %s" % (pa, slot, port, router.name)) router.slot[slot] = PA_A1(router, slot) return True if pa == 'p': if router.model in ['c2600', 'c2691', 'c3725', 'c3745', 'c3600']: doerror("Unsuppported interface %s%i/%i specified for device: %s" % (pa, slot, port, router.name)) router.slot[slot] = PA_POS_OC3(router, slot) return True if pa == 'i': router.slot[slot] = NM_CIDS(router, slot) if pa == 'an': router.slot[slot] = NM_NAM(router, slot) # Bad pa passed return False def switch_map(switch, source, dest): """ Apply a Frame Relay or ATM switch mapping switch: a FRSW or ATMSW instance source: a string specifying the source mapping dest: a string sepcifying the dest mapping """ # Is this a FR / ATM vpi mapping? matchobj = mapint_re.search(source) if matchobj: (port1, map1) = map(int, matchobj.group(1,2)) matchobj = mapint_re.search(dest) if not matchobj: print('*** Warning: ignoring invalid switch mapping entry %s = %s' % (source, dest)) return False (port2, map2) = map(int, matchobj.group(1,2)) if type(switch) == FRSW: # Forward switch.map(port1, map1, port2, map2) # And map the reverse switch.map(port2, map2, port1, map1) return True elif type(switch) == ATMSW: switch.mapvp(port1, map1, port2, map2) switch.mapvp(port2, map2, port1, map1) return True else: print('*** Warning: ignoring attempt to apply switch mapping to invalid device type: %s = %s' % (source, dest)) return False # Is this an ATM VCI mapping? matchobj = mapvci_re.search(source) if matchobj: if type(switch) != ATMSW: print('*** Warning: ignoring invalid switch mapping entry %s = %s' % (source, dest)) return False (port1, vp1, vc1) = map(int, matchobj.group(1,2,3)) matchobj = mapvci_re.search(dest) if not matchobj: print('*** Warning: ignoring invalid switch mapping entry %s = %s' % (source, dest)) return False (port2, vp2, vc2) = map(int, matchobj.group(1,2,3)) if not matchobj: print('*** Warning: ignoring invalid switch mapping entry %s = %s' % (source, dest)) return False switch.mapvc(port1, vp1, vc1, port2, vp2, vc2) switch.mapvc(port2, vp2, vc2, port1, vp1, vc1) return True print('*** Warning: ignoring invalid switch mapping entry %s = %s' % (source, dest)) return False def import_config(FILENAME): """ Read in the config file and set up the network """ global globalconfig, globaludp, handled, debuglevel connectionlist = [] # A list of router connections maplist = [] # A list of Frame Relay and ATM switch mappings ethswintlist = [] # A list of Ethernet Switch vlan mappings # look for configspec in CONFIGSPECPATH and the same directory as dynagen realpath = os.path.realpath(sys.argv[0]) debug('realpath ' + realpath) pathname = os.path.dirname(realpath) debug('pathname -> ' + pathname) CONFIGSPECPATH.append(pathname) for dir in CONFIGSPECPATH: configspec = dir +'/' + CONFIGSPEC debug('configspec -> ' + configspec) # Check to see if configuration file exists try: h=open(FILENAME) h.close() try: config = ConfigObj(FILENAME, configspec=configspec, raise_errors=True) except SyntaxError, e: print "\nError:" print e print e.line, '\n' raw_input("Press ENTER to continue") handled = True sys.exit(1) except IOError: #doerror("Can't open configuration file") continue vtor = Validator() res = config.validate(vtor, preserve_errors=True) if res == True: debug('Passed validation') else: for entry in flatten_errors(config, res): # each entry is a tuple section_list, key, error = entry if key is not None: section_list.append(key) else: section_list.append('[missing section]') section_string = ', '.join(section_list) if error == False: error = 'Missing value or section.' print section_string, ' = ', error raw_input("Press ENTER to continue") handled = True sys.exit(1) debuglevel = config['debug'] if debuglevel > 0: setdebug(True) globalconfig = config # Store the config in a global for access by console.py if debuglevel >= 3: debug("Top-level items:") for item in config.scalars: debug(item + ' = ' + str(config[item])) debug("Dynamips Servers:") for section in config.sections: server = config[section] server.host = server.name controlPort = None if ':' in server.host: # unpack the server and port (server.host, controlPort) = server.host.split(':') if debuglevel >= 3: debug("Server = " + server.name) for item in server.scalars: debug(' ' + str(item) + ' = ' + str(server[item])) try: if server['port'] != None: controlPort = server['port'] if controlPort == None: controlPort = 7200 dynamips[server.name] = Dynamips(server.host, int(controlPort)) # Reset each server dynamips[server.name].reset() except DynamipsVerError: exctype, value, trace = sys.exc_info() doerror(value[0]) except DynamipsError: doerror('Could not connect to server: %s' % server.name) if server['udp'] != None: udp = server['udp'] else: udp = globaludp # Modify the default base UDP NIO port for this server try: dynamips[server.name].udp = udp except DynamipsError: doerror('Could not set base UDP NIO port to: "%s" on server: %s' % (server['udp'], server.name)) if server['workingdir'] == None: # If workingdir is not specified, set it to the same directory # as the network file realpath = os.path.realpath(FILENAME) workingdir = os.path.dirname(realpath) else: workingdir = server['workingdir'] try: # Encase workingdir in quotes to protect spaces workingdir = '"' + workingdir + '"' dynamips[server.name].workingdir = workingdir except DynamipsError: doerror('Could not set working directory to: "%s" on server: %s' % (server['workingdir'], server.name)) # Has the base console port been overridden? if server['console'] != None: dynamips[server.name].baseconsole = server['console'] # Initialize device default dictionaries for every router type supported devdefaults = {} for key in DEVICETUPLE: devdefaults[key] = {} # Apply lab global defaults to device defaults for model in devdefaults: devdefaults[model]['ghostios'] = config['ghostios'] devdefaults[model]['ghostsize'] = config['ghostsize'] devdefaults[model]['sparsemem'] = config['sparsemem'] devdefaults[model]['oldidle'] = config['oldidle'] if config['idlemax'] != None: devdefaults[model]['idlemax'] = config['idlemax'] if config['idlesleep'] != None: devdefaults[model]['idlesleep'] = config['idlesleep'] for subsection in server.sections: device = server[subsection] # Create the device if device.name in DEVICETUPLE: debug('Router defaults:') # Populate the appropriate dictionary for scalar in device.scalars: if device[scalar] != None: devdefaults[device.name][scalar] = device[scalar] continue debug(device.name) # Create the device try: (devtype, name) = device.name.split(' ') except ValueError: doerror('Unable to interpret line: "[[' + device.name + ']]"') if devtype.lower() == 'router': # if model not specifically defined for this router, set it to the default defined in the top level config if device['model'] == None: device['model'] = config['model'] if device['model'] == '7200': dev = C7200(dynamips[server.name], name=name) elif device['model'] in ['3620', '3640', '3660']: dev = C3600(dynamips[server.name], chassis = device['model'], name=name) elif device['model'] == '2691': dev = C2691(dynamips[server.name], name=name) elif device['model'] in ['2610', '2611', '2620', '2621', '2610XM', '2611XM', '2620XM', '2621XM', '2650XM', '2651XM']: dev = C2600(dynamips[server.name], chassis = device['model'], name=name) elif device['model'] == '3725': dev = C3725(dynamips[server.name], name=name) elif device['model'] == '3745': dev = C3745(dynamips[server.name], name=name) elif device['model'] in ['1710', '1720', '1721', '1750', '1751', '1760']: dev = C1700(dynamips[server.name], chassis = device['model'], name=name) # Apply the router defaults to this router setdefaults(dev, devdefaults[device['model']]) if device['autostart'] == None: autostart[name] = config['autostart'] else: autostart[name] = device['autostart'] elif devtype.lower() == 'frsw': dev = FRSW(dynamips[server.name], name=name) elif devtype.lower() == 'atmsw': dev = ATMSW(dynamips[server.name], name=name) elif devtype.lower() == 'ethsw': dev = ETHSW(dynamips[server.name], name=name) else: print '\n***Error: unknown device type:', devtype, '\n' raw_input("Press ENTER to continue") handled = True sys.exit(1) devices[name] = dev for subitem in device.scalars: if device[subitem] != None: debug(' ' + subitem + ' = ' + str(device[subitem])) if setproperty(dev, subitem, device[subitem]): # This was a property that was set. continue else: # Should be either an interface connection or a switch mapping # is it an interface? if interface_re.search(subitem): # Add the tuple to the list of connections to deal with later connectionlist.append((dev, subitem, device[subitem])) # is it an interface with no port? (e.g. "f0") elif interface_noport_re.search(subitem): connectionlist.append((dev, subitem, device[subitem])) # is it a frame relay or ATM vpi mapping? elif mapint_re.search(subitem) or mapvci_re.search(subitem): # Add the tupple to the list of mappings to deal with later maplist.append((dev, subitem, device[subitem])) # is it an Ethernet switch port configuration? elif ethswint_re.search(subitem): ethswintlist.append((dev, subitem, device[subitem])) elif subitem in ['model', 'configuration', 'autostart']: # These options are already handled elsewhere continue else: print('Warning: ignoring unknown config item: %s = %s' % (str(subitem), str(device[subitem]))) # Establish the connections we collected earlier for connection in connectionlist: debug('connection: ' + str(connection)) (router, source, dest) = connection try: result = connect(router, source, dest) except DynamipsError, e: err = e[0] doerror('Connecting %s %s to %s resulted in \n %s' % (router.name, source, dest, err)) if result == False: doerror('Attempt to connect %s %s to unknown device: "%s"' % (router.name, source, dest)) # Apply the switch configuration we collected earlier for mapping in maplist: debug('mapping: ' + str(mapping)) (switch, source, dest) = mapping switch_map(switch, source, dest) for ethswint in ethswintlist: debug('ethernet switchport configing: ' + str(ethswint)) (switch, source, dest) = ethswint parameters = len(dest.split(' ')) if parameters == 2: # should be a porttype and a vlan (porttype, vlan) = dest.split(' ') try: switch.set_port(int(source), porttype, int(vlan)) except DynamipsError, e: doerror(e) except AttributeError, e: print "\n[[%s]]" % switch.name print source + " = " + dest + "\t <==== *Error*" doerror(e) except DynamipsWarning, e: #dowarning(e) # Now silently ignoring unused switchports pass elif parameters == 3: # Should be a porttype, vlan, and an nio (porttype, vlan, nio) = dest.split(' ') try: (niotype, niostring) = nio.split(':',1) except ValueError: doerror('Malformed NETIO in line: ' + str(source) + ' = ' + str(dest)) return False debug('A NETIO: ' + str(nio)) try: #Process the netio if niotype.lower() == 'nio_linux_eth': debug('NIO_linux_eth ' + str(dest)) switch.nio(int(source), nio=NIO_linux_eth(switch.dynamips, interface=niostring), porttype=porttype, vlan=vlan) elif niotype.lower() == 'nio_gen_eth': debug('gen_eth ' + str(dest)) switch.nio(int(source), nio=NIO_gen_eth(switch.dynamips, interface=niostring), porttype=porttype, vlan=vlan) elif niotype.lower() == 'nio_udp': debug('udp ' + str(dest)) (udplocal, remotehost, udpremote) = niostring.split(':',2) switch.nio(int(source), nio=NIO_udp(switch.dynamips, int(udplocal), str(remotehost), int(udpremote)), porttype=porttype, vlan=vlan) elif niotype.lower() == 'nio_null': debug('nio null') switch.nio(int(source), nio=NIO_null(switch.dynamips), porttype=porttype, vlan=vlan) elif niotype.lower() == 'nio_tap': debug('nio tap ' + str(dest)) switch.nio(int(source), nio=NIO_tap(switch.dynamips, niostring), porttype=porttype, vlan=vlan) elif niotype.lower() == 'nio_unix': debug('unix ' + str(dest)) (unixlocal, unixremote) = niostring.split(':',1) switch.nio(int(source), nio=NIO_unix(switch.dynamips, unixlocal, unixremote), porttype=porttype, vlan=vlan) elif niotype.lower() == 'nio_vde': debug('vde ' + str(dest)) (controlsock, localsock) = niostring.split(':',1) switch.nio(int(source), nio=NIO_vde(switch.dynamips, controlsock, localsock), porttype=porttype, vlan=vlan) else: # Bad NIO doerror('Invalid NIO in Ethernet switchport config: %s = %s' % (source, dest)) except DynamipsError, e: doerror(e) else: doerror('Invalid Ethernet switchport config: %s = %s' % (source, dest)) def import_ini(FILENAME): """ Read in the INI file """ global telnetstring, globaludp, useridledbfile, handled # look for the INI file in the same directory as dynagen realpath = os.path.realpath(sys.argv[0]) pathname = os.path.dirname(realpath) debug('pathname -> ' + realpath) INIPATH.append(pathname) for dir in INIPATH: inifile = dir +'/' + FILENAME # Check to see if configuration file exists try: debug('INI -> ' + inifile) h=open(inifile) h.close() break except IOError: continue else: doerror("Can't open INI file") try: config = ConfigObj(inifile, raise_errors=True) except SyntaxError, e: print "\nError:" print e print e.line, '\n' raw_input("Press ENTER to continue") handled = True sys.exit(1) try: telnetstring = config['telnet'] except KeyError: telnetstring = None dowarning("No telnet option found in INI file.") try: globaludp = int(config['udp']) except KeyError: pass except ValueError: dowarning("Ignoring invalid udp value in dynagen.ini") try: useridledbfile = config['idledb'] except KeyError: # Set default to the home directory useridledbfile = os.path.expanduser('~' + os.path.sep + 'dynagenidledb.ini') def import_generic_ini(inifile): """ Import a generic ini file and return it as a dictionary, if it exists Returns None if the file doesn't exit, or raises an error that can be handled """ try: h=open(inifile, 'r') h.close() except IOError: # File does not exist, or is not readable return None try: config = ConfigObj(inifile, raise_errors=True) except SyntaxError, e: print "\nError in user idlepc database:" print e print e.line, '\n' raw_input("Press ENTER to continue") handled = True sys.exit(1) return config def debug(string): """ Print string if debugging is true """ global debuglevel # Level 3, dynagen debugs. if debuglevel >= 3: print ' DEBUG: ' + str(string) def doerror(msg): global handled """Print out an error message""" print '\n*** Error:', str(msg) handled = True doreset() raw_input("Press ENTER to continue") sys.exit(1) def dowarning(msg): """Print out minor warning messages""" print 'Warning:', str(msg) def doreset(): """reset all hypervisors""" for d in dynamips.values(): d.reset() if __name__ == "__main__": # Catch and display any unhandled tracebacks for bug reporting. try: # Get command line options usage = "usage: %prog [options] " parser = OptionParser(usage=usage, version="%prog " + VERSION) parser.add_option("-d", "--debug", action="store_true", dest="debug", help="output debug info") parser.add_option("-n", "--nosend", action="store_true", dest="nosend", help="do not send any command to dynamips") parser.add_option("--notelnet", action="store_true", dest="notelnet", help="ignore telnet commands (for use with gDynagen)") try: (options, args) = parser.parse_args() except SystemExit: handled = True sys.exit(0) if len(args) != 1: parser.print_help() handled = True sys.exit(1) FILENAME = args[0] if options.debug: setdebug(True) print "\nPython version: %s" % sys.version if options.nosend: nosend(True) if options.notelnet: notelnet = True # Check to see if the network file exists and is readable try: h = open(FILENAME, 'r') h.close() except IOError: doerror('Could not open file: ' + FILENAME) # Import INI file try: import_ini(INIFILE) except DynamipsError, e: doerror(e) print "\nReading configuration file...\n" try: import_config(FILENAME) except DynamipsError, e: # Strip leading error code if present e = str(e) if e[3] == '-': # Are the first three characters an error code? try: if e[:3] == str(int(e[:3])): e = e[4:] + "\nSee dynamips output for more info.\n" except ValueError: pass doerror(e) except DynamipsWarning, e: dowarning(e) # Read in the user idlepc database, if it exists useridledb = import_generic_ini(useridledbfile) # Push configurations stored in the network file if configurations != {}: result = raw_input("There are saved configurations in your network file. \nDo you wish to import them (Y/N)? ") if result.lower() == 'y': for routerName in configurations: device = devices[routerName] device.config_b64 = configurations[routerName] # Implement IOS Ghosting ghosts = {} # a dictionary of ghost instances which will match the image name+hostname+port try: # If using mmap, create ghost IOS instances and apply it to instances that use them for device in devices.values(): try: if device.mmap == False: continue except AttributeError: # This device doesn't have an mmap property continue if not ghosteddevices[device.name]: continue if device.imagename == None: doerror("No IOS image specified for device: " + device.name) ghostinstance = device.imagename + '-' + device.dynamips.host ghost_file = device.imagename + '.ghost' if ghostinstance not in ghosts: # Only create a ghost if at least two instances on this server use this image ioscount = 0 maxram = 0 for router in devices.values(): try: if (router.dynamips.host == device.dynamips.host) and (router.imagename == device.imagename): if ghosteddevices[router.name]: ioscount += 1 if router.ram > maxram: maxram = router.ram except AttributeError: continue if ioscount < 2: ghosts[ghostinstance] = False else: # Create a new ghost ghosts[ghostinstance] = True ghost = Router(device.dynamips, device.model, 'ghost-'+ ghostinstance, consoleFlag = False) ghost.image = device.image # For 7200s, the NPE must be set when using an NPE-G2. if device.model == 'c7200': ghost.npe = device.npe # test #ghost.sparsemem = True ghost.ghost_status = 1 ghost.ghost_file = ghost_file if ghostsizes[device.name] == None: ghost.ram = maxram else: ghost.ram = ghostsizes[device.name] ghost.start() ghost.stop() ghost.delete() # Reference the appropriate ghost for the image and dynamips server, if the multiple IOSs flag is true if ghosts[ghostinstance]: device.ghost_status = 2 device.ghost_file = ghost_file except DynamipsError, e: doerror(e) # Apply idlepc values, and if necessary start the instances for device in devices.values(): try: if device.idlepc == None: if useridledb and device.imagename in useridledb: device.idlepc = useridledb[device.imagename] except AttributeError: pass if autostart.has_key(device.name): if autostart[device.name]: try: if device.idlepc == None: dowarning("Starting %s with no idle-pc value" % device.name) device.start() except DynamipsError, e: # Strip leading error code if present e = str(e) if e[3] == '-': e = e[4:] + "\nSee dynamips output for more info.\n" doerror(e) print "Network successfully loaded\n" console = Console() try: console.cmdloop() except KeyboardInterrupt: print "Exiting..." doreset() except DynamipsErrorHandled: raw_input("Press ENTER to exit") sys.exit(1) except: exctype, value, trace = sys.exc_info() # Display the unhandled exception, and pause so it can be observed if not handled: print """*** Dynagen has crashed **** Please open a bug report against Dynagen at http://www.ipflow.utc.fr/bts/ Include a description of what you were doing when the error occured, your network file, any errors output by dynamips, and the following traceback data: """ traceback.print_exc() raw_input("Press ENTER to exit") if debuglevel >=2: print "\nDumping namespace..." print 'Globals:' print trace.tb_frame.f_globals print 'Locals:' print trace.tb_frame.f_locals sys.exit(1) # ----------------------------------------------------------------------------- # idledb option # Specify the file that stores the idle-pc database # Defaults to the user's home directory # Usage: # idledb = /usr/local/etc/dynagenidledb.ini # ----------------------------------------------------------------------------- # udp option # Changes the base UDP NIO port for all labs. Default is 10000 # Usage: # udp = 11000 # ----------------------------------------------------------------------------- # telnet option # Specify the command to execute when using the telnet command from the CLI # The following substitutions are performed: # %h = host # %p = port # %d = device name # Uncomment below for Windows #telnet = start telnet %h %p # Or better yet for Terra Term SSH users: #telnet = C:\progra~1\TTERMPRO\ttssh.exe %h %p /W=%d /T=1 # For PuTTY users: #telnet = start C:\progra~1\PuTTY\putty.exe -telnet %h %p # For SecureCRT #telnet = start C:\progra~1\SecureCRT\SecureCRT.EXE /script c:\progra~1\dynamips\securecrt.vbs /arg %d /T /telnet %h %p & sleep 1 # Uncomment below for Linux telnet = xterm -T %d -e telnet %h %p > /dev/null 2>&1 & # Uncomment below for OS X with Terminal #telnet = /usr/bin/osascript -e 'tell application "Terminal" to do script with command "telnet %h %p ; exit"' -e 'tell application "Terminal" to tell window 1 to set custom title to "%d"' # Uncomment below for OS X with iTerm with named tabs #telnet = /usr/bin/osascript -e 'tell app "iTerm"' -e 'activate' -e 'set myterm to the first terminal' -e 'tell myterm' -e 'set mysession to (make new session at the end of sessions)' -e 'tell mysession' -e 'exec command "telnet %h %p"' -e 'set name to "%d"' -e 'end tell' -e 'end tell' -e 'end tell' ELF@4`4 (444444l? l? @ d,C ,,HHH Ptd> Qtd/lib/ld-linux.so.2GNU$)Fj8kpZynE,fxVR -l]<?q*md3B~ `ou%& IAP4O|Th #!="1G/+QDX6S\_Nc [aH;i>Lb5etM0r :7sKv9U{zwY(}^JW2C'.g@4 nM Y4Jpglc2v\.1LtkWYD $;7(D2(7$C  L, W: 75k0Agl:mpl7<Bqq4X2REr2|!4OHPp0>5 8H>I6\MKGIl/2:D7v<~woo2vK|6 eIDFfQ8a2VU!#4<g {R$/d$947t8LeY$9ox54@Dd #E#j7Rl b-E?`m d7V4ķsC:8&ȷ7F5EP ;nP"flTBHWfp`libdl.so.2__gmon_start___Jv_RegisterClassesdlopendlsymdlclosedlerrorlibpthread.so.0sigactionrecvfrompthread_mutex_unlockpthread_joinpthread_createsendtopthread_setcancelstate__errno_locationpthread_sigmasklseekconnectsendpthread_cond_signalpthread_mutex_lockpread64pthread_mutex_destroypthread_cond_waitacceptpthread_mutexattr_initpthread_cond_destroypthread_cond_timedwaitpthread_setcanceltypepthread_exitmsyncrecvpthread_mutexattr_settypelongjmppthread_cond_initpthread_cond_broadcastfsyncfcntlpthread_mutex_initlibc.so.6_IO_stdin_usedsocketfflushstrcpysprintffopengai_strerrorftruncateinet_atonoptindstrrchrposix_memalign__strdupcfmakerawperrordcgettextmmap64ftellinet_ntopstrncpyputsunlinkputcharlistenselectreallocabortstdinmemchrstrpbrkgetpidstrftimeinet_pton__assert_failgetnetbynamelocaltime_risattymmapfeofmemccpycfsetispeedfgetscallocstrlensigemptysetgetaddrinfomemsetbindtcsetattrfseekchdirgetsockoptgetoptclearerr__fxstat64shutdown_setjmpvsnprintfsigaddsetstdoutfputcinet_addrmemcpyfclose__strtol_internalsetsockoptmalloc__ctype_b_locsscanfoptarggetservbynamestderrioctlmunmapgethostbynamegetopt_longfreeifaddrsgetifaddrs__fxstatfilenousleepfwritefreadgettimeofdayether_hosttonsetlinebuftcflushlocaltimestrchrfdopentcgetattrfreeaddrinfocfsetospeedgetprotobynameunamememmovefopen64_IO_getcopterrstrcmp__strtoull_internal__libc_start_mainferrorvfprintf__strtoul_internalfree__cxa_atexitn_errorspcap_charpcap_linenopcap_textvmapno_optimizepcap_outvnode_baseinstall_bpf_programspacenext_vnodeeproto_dblevelsblockspcap__flex_debugedgespcap_setnonblock_fdpcap_inpcap_offline_readpcap_lvalpcap_getnonblock_fdpcap_lengpcap_nerrsGLIBC_2.1GLIBC_2.0GLIBC_2.2GLIBC_2.3.2GLIBC_2.3GLIBC_2.1.3     0ii ii LPii ii ri *ii +ii ii 6ii  si @ii   $(!,#004W8[[<_@dHnL|P~TX\`dhlpEķȷ      "$%&'()*+,-. /1234 5$6(7,8094:8;<<@=D>H?LAPBTCXD\F`GdHhIlJpKtLxM|NOPQRSTUVXYZ\]^`abcefghijklmopqrstuv wxyz{ }$(,048<@DHLPTX\`dhlptx|US[è# t^  X[5x%|%h%h%h%h%h %h(%h0%h8p%h@`%hHP%hP@%hX0%h` %hh%hp%hx%h%h%h%h%h%h%h%hp%h`%hP%h@%h0%h %h%h%h%h%h%h% h%h %h(%h0%h8p% h@`%$hHP%(hP@%,hX0%0h` %4hh%8hp%<hx%@h%Dh%Hh%Lh%Ph%Th%Xh%\hp%`h`%dhP%hh@%lh0%ph %th%xh%|h%h%h%h%h%h %h(%h0%h8p%h@`%hHP%hP@%hX0%h` %hh%hp%hx%h%h%h%h%h%h%h%hp%h`%hP%h@%h0%h %h%h%h%h%h%h% h%h %h(%h0%h8p% h@`%$hHP%(hP@%,hX0%0h` %4hh%8hp%<hx%@h%Dh%Hh%Lh%Ph%Th%Xh%\hp%`h`%dhP%hh@%lh0%ph %th%xh%|h%h%h%h%h%h %h(%h0%h8p%h@`%hHP%hP@%hX0%h` %hh%hp%hx%h%h%h%h1^PTRhвhQVhU=̷t ҡu̷ÐUtt $Ð1\$\$ |$1D$C$u"D$$C C؋\$|$1ۋ|$؋\$Í&'WVSt$ ~<$ tt&X$ۉuF$F(|$ [^_D$ \$t$|$xᆳލXs~<$S N$C)F(tgCBStC B C C<$.CCC C$\$1t$|$fC똻+\$ L$T$$bfT$ t$1øD$ D$D$$ &l$l$(\$ t$t$ |$1E$Xtfᆳލ~h@@ p<$=F$C CF(CtX <$tD$$l$<$D$L\$ t$|$l$ÍWS$0t!1 1D$C$,t$1[_ÍD$ C C[_Ít&t$t$$\$ l$l$ |$4$:1߉vtT$${1}up&D$$uᆳCC Ck4$E$C CE(ECtX ]4$C\$ t$|$l$듍vftv捴&',D$0|$$\$t$ l$(xxᆳwn,$;W N$G)F(GBWtG B G G,$D$4<$D$tVD$4,$CF$C CF(CtX ,$C\$t$ |$$l$(,ËGn,$F$G GF(Gtx >,$A1밸w3D$T$ D$$WVSt$ ~<$uv؋X$uF$F(<$F t[^_Ét$ [^_&|$|$$\$t$t$ G$1tN{~ᆳCC s<$qF$C CF(CtX <$+C\$t$|$Ð&D$$\$ t$l$|$$PƍhT$,$lj1v'T$ D$ᆳC։SCC 4$D$ T$ C @$CB(CtX D$ 4$?؃txT$$É$T$V؋t$\$ |$l$hfW名t&"Vэx1뿍&1떐WVSз$$>a$UзpH~[1&XPދ^9t; C D$ CD$$ԴD$[9u١зG9xH$MзHL~m1t&|$$j[зPT֋^9t*v'C D$$yD$'[9u$ GCз9xL$[^_Ív'UWVSзt$0l$4\$<$зzT1F9tut&@G9u$0[^_]1PG$\$T$T$8T$ՋD$9uߋзÍt&'UWVS l$ з$,$=з1wHGPƋ^9t-&l$$u D$$;C[9uڸ D$G$T$$D$(+C SC,$- з1ҋqPqHBSCBZXCQTЋPCSPXZ $1 [^_]É<$ [^_]áз$ϋD$HPQPJHPQPJD$t&S($Xз\$$$g$D$vз\$$D$з$зCHCLD$C$CPзCPCH~KH1ҍt&BCP9щ@@CLD$C$h зCTATtYYL~$YL1ҍBAT9Ӊ@@(1[ù0L$ T$D$$IL$ T$D$$?L$ T$D$$U1WVSз$ з|$0PT׋_9uPD$4tD$8D$C$T$4t'KSECBCPSJCP$9t:C stD$D$0D$ @\$D$$<9uơз$;[^_]ÐUWVS |$ tkз$/<$-з1uHEPƋ^9t-t&'|$$Ru D$$;Ct[9u޾,$ [^_]ËD$(19C t$0t#D$4D$C$T$0u -з븋L$,tSCBCPSCBCP$ÐD$,D$D$(D$D$ 1D$D$$D$D$ $ÍUWVS|$0tkз$<$-з1uHEPƋ^9t-t&'|$$"u D$4;Ct[9u޻,$[^_]ËC HC 1ۅyḌT$4D$|$T$ $3-з벍t&'UWVS1ۃ |$ tkз$2<$-з1uHEPƋ^9t0&'|$$Ru D$$;Ct[9u1ۉ,$ [^_]Ë[鐍t&UWVS1ۃ |$ tkз$<$j-з1uH֋UP֋^9t0&'|$$u D$$;Ct[9u1ۉ,$$ [^_]C [fUWVS |$ tkз$<$-з1ҋMPuH΋^9t-t&'|$$2u D$$;Ct[9uމ,$ [^_]ËC HC ~,$v 1[^_]ËSCBCPSCBCP$з$91뤐D$É't$p49։\$Ӊ|$tt1\$t$|$ËS9tu+S 9t܅t؋GTD$D$$WPx1뺋GTD$D$$WP~Sw@ufS f@uv뽍&'D$PLDt&S\$tC$9\$[L[Í&S1ۃ$X.tu1ҹXÉL$T$$εD$C$}tKCHC4C4C8C<C@CDT$ fCHCLSPT$$ST[É$1fS\$C$}C4CHC4C8C<C@CDfCHCL[Í,l$(l$0t$ |$$|$4\$]Lu49t+t'ETD$<$D$UPt4~-[ 9uۍ1ۉ\$D$\$t$ |$$l$(,f[묋CS\$9T$C 9ƉD$u{D$T$B9tuu9D$titeT$D$JHB9t]tYT$;PT$P ;\$tT$BCD$fxt/$uE3C\$돋D$@ D$뎋T$UL벋D$;ELfxT$JQ9T$fzuRB fBfA9ƉAttHABA9;HP J QT$JQz fZf{eAfBQfAfCB 9ƉAttHABA9t;t7;H~P J QUL;ELT$T$D$fBULЋZf{ufBL$Q fzuRBfBfA9ƉA ttHABA9;HP D$QJHQ zfZ f{AfBQ fAfCB9ƉA ttHABA9;HP JQELD$GfGfB9ƉB ttPBGB9t@t<;Px D$zWHQZIULP}ULv넉}LˋZ f{$PfT$Pt&G fGfB9ƉBttPBGB9tS 9։t>t:9Չ}@$t$|$l$ Ðt&S 19uɍ&11А&UWVSD$49ЉD$RJ~;|$_9\$tDt@D$0S$D$D$0D$CD$$ՋD$0S $D$xD$0D$GD$$Ջ_ 9\$tDt@D$0S$D$@D$0D$CD$$ՋD$0S $D$D$0D$FD$$Ջv ;t$bZ^;\$t|txD$0S$D$D$0D$CD$$Ջ[ 9\$tDt@D$0S$D$D$0D$CD$$ՋD$0S $D$eD$0D$FD$$Ջv ;t$^9\$tDt@D$0S$D$D$0D$CD$$ՋD$0S $D$D$0D$FD$$Ջ^ 9\$t>t:D$0S$D$D$0D$CD$$Ջs 9t$f[^_]Ð&t$t$ |$|$(l$l$$\$ t@^LF49t4t0S<$;|$CD$$ՋS <$1\$ t$|$l$ÐS1ۋL$t+fځt ؉11AAu׉[ÍvD$;D$ÐD$1Ít&t$D$t$ $XVt$1ڋ$1 Í'T$B 1Ít&D$9D$ÐS1ҋD$Ӊ1[Í&UWVSD$0l$4t$8tUD$01~?'T$0Btft$CD$$Ջ[uD$0G98΃1[^_]ÿݵ|$ t$\$$='VS\$ t$$t24$S 13Cu @t ;0u@[^Ã1[^ø0D$ D$ݵD$$WVSt$ |$$t@<$V 16Fu ![t|$$VtC[^_Ã1[^_ùGݵL$ T$D$$G&D$tv WVSt$ |$$t_<$V 16FËu 6t+|$$VtPp$3[^_Ã1[^_øYD$ D$ݵD$$&UWVSt$0|$4<$V 16F,(u ([t!|$$VtD$8C1[^_]$ tR8D$8AFAF‹A1 [^_]ÿkݵ|$ t$\$$}`ݵL$ T$D$$'|$|$ t$t$(\$tZ~V$tJ@@x D$$3CD$4$Ct=؋t$\$|$1qD$ݵT$ D$$D$ xD$ݵD$$' D$D$D$$ ÐWVSD$|$t91ۍЉ%   ʉC9u[^_ÐT$Ѓ$t @t t t  t @t y É'S1ۋT$ L$vfÃwt vÍu[f%߉'1ɋD$ L$T$ $D$D$D$$D$Ðt&1D$D$ $D$D$ D$D$$D$Ðt&S1\$ D$D$$q~ D$D$$Nƒ[Ðt&S\$$$$D$z1҉\$T$$Ę[ÍS\$$$$D$*1ɉ\$L$$Ę[ÍS(D$4\$0D$D$$\$$uT$$Cu([Ã(1[øwD$ :D$\$$4v'U-WVS$4$0L$$D$T$11D$u[^_]É,$4(뭋D$<~'1 T$8C$9\$v'F V$^4D$ D$ D$T$$$:4$u̍_,$衸$詵1D$D$$$说,$7<$|$S$W,[^_] VS1ۃ$`=tJ@P@X1D$F$蠹u1D$F$[t4$1[^Ðt&1ҹ`FLt$ L$T$$uύWVS|$ ~F1+$F衹0C\0$g9tuʃ[^_Ã1[^_Ív<\$,|$4|$@l$8l$Dt$0$9D$ D$|$ l$$$p,FD$$S0C4B4S4tC0B0NTC0C()FXD$C4$藶D$ D$|$ l$$$$肵$fF$k1\$,t$0|$4l$8<Ðt&D$ D$|$ l$$$$+$1벋C4:$땍&'U1WVS|$D$$谺1D$$莺$$$GWD$ T$$$舷C1Sl$t$ $T$ S1ɉD$lCL$ \$T$$ @BT$ D$pD$lD$D$$T$$QGP1D$D$d$ij/\$dL$htF $ÉָD$1D$ T$I ;Uwpr;Esi'D$ $tD$ $舶T$ D$$T$$ڶGPYT$ $3$&U0E4B4U4tE0B0OTE0E()GXE4Ml$E$Ut[EEEU1ۃetM9HUrKw9PvD1ۅE4]0},th0E0nh4GTE(GXT$ $oD$ Ë@4t9Hwfr9Pw'ދE4%T$d1$t$D$dD$tD$8D$D$t$VL$d\$\L$dD$(1D$ D$hT$,T$$T$y D$(T$,1D$D$d$蟱ED$0D$1D$ D$hT$4$T$3 øl$dD$E D$D$0T$UT$T$4D$D$(\$T$ T$,$t$T$4 )D$0T$4\$0t$4]uW/fVS1L$T$$tjft4$F0C\0$讱 u1[^á$D$ :D$D$Zϡ$D$ (D$D$1룍v'UWVS|$K D$$uء E E U$D$l$$@=0G\OXtPX9~ljы@\uGD$,$迲EEEU1ۃetM;HUviË@4t;HshE4]0},th0E0wh4GTT$,E(GX$3$'E,$)E U$|[^_]r;Ps1fw;Pr&w1\$l$D$ĮD$lD$tD$@D$D$t$L$lD$dL$lD$ D$1D$ D$pT$$$T$+ $D$ T$$11ۉD$SEt$\$ D$0D$pT$4$T$ øl$lD$E D$D$0T$UT$T$4D$D$ \$T$ T$$$t$T$ )D$0T$4\$0t$4]uI/$,$ɭ|1[1^_]Í'D$0\$ \$ |$|$4l$l$8t$D$$8}t51991t&1Ȩ1Ȩ1Ȩ1بщ1Ш15f6F΃ځ1Ȩ_1ȨV1ȨP1ȨJˁ1بDщ1Ш>51991J&uMuRuWu\uauftk5 Btft5 t5 t5 t5 t5 t5 t5 uBu[^ÐVSt$\$ L$~}'A0 CQA< CA?C~S€0Nt9ASCA<ZB=[^SC= \$ \$$t$t$ |$l$;+1; 1C<S=T$ S=T$ t€tvT$(E„t;l$(bF|$ =u1t< t |$ =Sf\$ t$|$l$EtG9l$(}A ɀ{ €uހ9L$ $ဉL$D$tLF|$ =\Et9l$(|T$u $T$ €u F $랐<\$,\$@t$0|$4l$8ދl$Dt\$,t$0|$4l$8<C fp 9wׅC~i1ҍDB1%<19uЉ‰T$ˆD$+\$X\$HPXf11D$D$ҍv'WV1SD$D$$:fB@~G5)V~G~˃[^_Ít&UWVS\t$|$D$T~1 D@9u\$ 11D$$|$@<$D$xD$(D$ D$tD$ D$D$&D$ptyT$p:tpD$XD$ \$|$$=D$X1҉T$Wt. t)t9t$|D$X$聞D$\[^_]1댋G D$G$D$k‰xD$D$TD$ D$$D$xGWD$T$$x5|$xtD$_1ɉL$eD$$yҋ$($t$D$$ۢ\$fU1WVS$$1$$$$$D$ D$D$[$D$ $t$\$$y$tt$$ t[tfSuC |$$D$͟1ҹL$T$4$Ct9 <$螡[u$$h[^_]ÉfD$$ffD$&Ct$<$D$uCS<$D$T$講u럍$ϻfD$$ ffD$&뢉$J l$D$$W S (D$8\$0T$4uGBD$BD$BD$BD$BD$ $L$D$輚([Ðt&0벉'SD$'\$ D$D$&$D$D$%D$ D$$D$D$c[Í\D$HD$D$DD$D$@D$D$dt$Pt$8|$T|$D$|$$~ދFD$FT$|$$D$ V Fuƒ [^_Ít&\$\$ t$t$(|$|$$C u>uTt$(t$|$$|$CD$ \$t$C$D$t$|$$딋t$|$$D$ R u&'\$t$|$Ët$|$$D$ R Cɉ'S1\$ D$ "D$$\$i\$$ [Ít& 1Ҹ T$D$$貢 Í&'1D$ D$D$ L$$9Ðt& D$D$$X Ít& D$D$$蘥 Ít& $2$$ID$ D$s,$ID$(D$U4$ID$0D$7<$ID$8D$D$ID$@D$L$ID$HD$ݐT$ID$PD$运\$ID$XD$衐d$ID$`D$胐l$ID$hD$e$ 艌 Ðt&S \$D$$G1҅($D$,0$D$8$D$@$D$ҒH$D$贒thP$D$蚒tNX$D$耒t4`$D$fth$D$L҃ J[ÍWVSt$ $@躏$$螏1 CC3D$$>C D$(CD$,Cv^1ɾC\$ t$L$$耏uh\$\C @D$虏$@1[^_Ít&$|@u덋FdF0Fh$@踌1T$$D$ D$q$虋$@q|$$D$ +D$/Jt&UWVSl$$$`F$@:\tOxC ң\9 u -;#@ uCS Zx\uXts=xXu ߋ t;uGHGuɋW tGBGP :wt$@tb<$^Xu$膏$@* x:wt$@u1GT$G$\넋BdyB0qBhiB$ʼnt9}ӉЃT$I zC$`z1$ N$$D$1D$ 1D$l$$@$`OxtY;?wK$м`RdXR0PRhHtЃD$u=[ u$`WdʋW0v‹뺋Wh뵉x'D$t$<$~CD$CT$t$<$D$ S CC st&8$Yt$t$ \$ |$l$td1l$4$]!|$4$Q!\$4$E! vFD$DL$$褊F$蹇4$豇\$ t$|$l$$t$>F$t$/F$$d랍n$}`t_H$]G`$.Edu t&؋$$uEhE0EdEl$谈,$/Fd$( Fh$t&苉F0u^$Ct$视CC uFdu^$Cxt$3Ctf$|$$1$$$Ȁ)ǸȀD$1D$,$$E $耋EE|u$D$1D$4$軄FxFt$5kw$$!kv\|$$hD$ *D$E11T$,$5$|$$$ČË$$G$1ɺL$T$$軅FtnD$1D$$$҃f$$\$$nD$$D$Ft$Ӂxf$$$D$$$荆1D$L$$Fx5nT$\$$貆)||D$1D$D$$$$fD$0D$D$2$ D$$D$(1D$,D$$\$D$Ft$]|tS$\2&,$1薃,&t$\$$D$ :nG(L$D$Ft$ntU$$؂$ǂ$趂$r襂{`p D$EEul$$譒@A,\$ \$ t$D$$|$l$;t\$ t$|$l$Ã8u{$p$kTClD$$Z,$RGdw`u ؋$$uGhGdGl,$n0D$$FHD$$,$Fd~`u؋$āuFhFdFl,$蓂D$$臂1D$@tD$Ð&$$$1$$$Ȁ91ƸȀD$|$,$$E $萆Ex}$D$1D$<$Gt$Lkw$$8kvc<L$T$$$D$ \11D$,$L$$$$ĜÍ&$؅F$t1ɺL$T$$րGt@n\$D$1D$$~F$fD$D$D$ $nD$\$Gt$O@t2$fGD$F*$轁 ~t$\$F$`@t&,$1F$~$~ S1ۃ$Ȁt{1ҹȀÉL$T$$}D$  $_CtP  p  C\$D$C$肎@t[É$1n~[1$1ۉD$'֐t&V1S$Ȁ=1ҹȀƉL$T$$ }D$  $蚃Ftu1D$FT$^$1D$Fl$n1$D$0~@ ^t$\$F$虍@t[^É4$1}[^14$1D$<ԍv'WVS1ۃ|$$$ȀH1ҹȀL$ÉT$$|D$  $裂F<$~?s$|$4$<$0 F@@0 s\$|$C$蓌@t\[^_Í&4$1v|[^_á1$dD$ @D$D$1D$4$1$1ۉt$fWV1S|$$$Ȁ1ɉƸȀL$D$$zD$  $cC<$@}?^$|$$}<$@ CD<$E C@CD`P ^t$|$F$E@tU[^_É$1/{[^_á@1T$$D$ D$}1D$$1ۉ4$1\$뙍t&',\$1ۉ|$$l$(l$,Ð 1ҸcT$D$$W Í&'1D$ cD$D$ L$$YÐt&VS\$s4$\GtHCt$ C@$諴C t$C @$莴C C4$D1Z[^f\$\$ t$|$s4$FCuC t4$D\$t$|$ËD$$$;NjD$($-tÅtC D$,{C$D$0C(1D$ a\$D$$蔶@t1@a|$ \$L$C$s@h4$D1fdt&'D$(T$,D$D$$D$ B(D$B$D$B $Í,|$85\$\$4t$ |$$l$(t\$t$ |$$l$(,Í&l$<,$ECK C ыT$<;B$t 1,$;C뜁;J(u,T$\$$tyʋ|$<$~빋L$<0@ wL$1 $_뚋t$ ljuٍCT$D$$Bt7Bt0,$L$`$L$D$L[^_]É$s,$$ _D$ŹD$1D$dED$dED$hED$lE T$pUT$p L$Q AD$0l$EEU4^T$4$>lj1L$T$4AL$0EB Q D$ T$4L$0Z H11҉L$,T$(L$0A D$(1|$$D$8t&T$0L$$BT$44BL$8<~&#DA9D$ tL$$T$,@D$$ʋL$ DL$0BT$$9Q D$,D$(T$4D$(9B F,$L$ T$qJ~ji1ۋ:L$ \$l$T$l$D\~(1ҾCtщЃlu B9uD$L$ T@9AD$l$`$l$D$I5h1L$$lD$\D$D$@T$l$@t$ $lD$D$Ct$ $KD$D$C t$ $*t$ CD$D$C$ E_4$I<$!@ L|$ t$\$$~;}E*$`@Ll$ |$t$$4D$ D$LD$$ kLt$ \$L$$ZLD$ l$|$$S\$L$ A ҉QtAB [ÍvSL$ \$QtA B A A\$D$ [It&D$@ÍD$@H$tÍv'ST$ \$u[ËJ0tB,tH0J01f@@t; u1ɉ B,1B0[ÍD$PJt&D$PJt&D$PJt&1D$ D$ $D$D$J1Ít& 1D$ D$$ Í&' D$11҉D$D$ T$ $, Ð&V1ST$ t$$@@tk u Ft N ;H Vs0F,tF,B0^013[^;PrߍX,@,t;H rw&B LL$D$$[^ÍD$@@@ @É'S\$CXt$yCX[Í' D$\$t$t$$øtFTt$+FT^T1\$t$ ÍvWVSй|$ u%tsF|$$Ru[^_Ã1[^_Ív'WVSй|$ u$ts|$$u[^_Ã1[^_Ít&'VSD$ t$$u &[tt$$u[^ VS\$ t$$CD$C D$ 4$D$D$CTtD$ L$4$D$CD$ T$4$D$C(D$ 4$D$D$nC@D$ 4$D$D$PCtt$$\$ [^XD$ 4$D$ED$ˋD$ 4$D$*D$럍v'D$ t$t$$\$Xt$$~CH(tt$$t$\$ \$\$t$ÍvS(\$0C@ u ([ÍD$$D$D$4$&~ڋL$$tҋC$T$L$P ËD$$$ S\$Cht$ C$1CCh[É'ST$\$tD$$D$t$S1[Ít$t$ \$t'C;Ct @ Cʋ\$Ћt$Ít&$41҅t܉øD$$$t!CCC 1둉$1뒍t&S\${tf$@ {u[É'S\$$1C[ÍS\${t1[Ë$m1C[ S\${t1[Ë$D$$1C[Ð&S\$ $*$11 [Í&S\$ D$D$ $D$`D$ D$D$ $D$mD$贅1[Í&VS$\$0T$4L$8CtNT$D$ L$CtD$D$1D$ C@$T$D$蝟$[^Í&L$D$T$D$ Ct$L$D$$[^Í 1D$D$$Y Ðt& 1D$D$$ Í&VS$$8$0$ t$ D$ $44$D$D$?C@t+D$yD$t$T$ $$[^øvΐ<\$,\$@t$0t$D|$4l$8CPu\$,t$0|$4l$8<ÍD$(D$$҅xԋL$(t̺0T$4$t5D$ D$D$(|$$,$KD$($1노D$t$$D$($ZSD$@ht D$[*"[Ð&S\$Cdt$CdCtT$u$C[É$GCfST$ =̹\$$Bt&\$ L$$D$'t%[Ív\$ B L$$D$u'׸D$ \$L$$S\$ C D$$D$/t%t&CD$$D$[u D$ [&',D$0Pht+PhL$nD$ D$D$$yt&UWVSt$0|$4l$8$ԹuBt&[t6t$$KuCCCE$Թ1[^_]øD$$C4$‰C D$C$D$3 ‰CC L$D$CT$ dD$T$$D$/CCCEC$Թ1[^_]ËCt$StC $D$3$$$ԹD$t$$k[^_]Í&'VS\$ =̹CtID$ T$$D$ƅtHt$$h4$[^ÍD$ C T$$D$@봾t$ \$L$$Ut&VSD\$P=̹CrD$ T$$D$hC0t$$Cdp11ɉT$41҉L$@1ɉT$8t$4L$D$ T$$D$vG|G|$j<$@<$@1ɉ|$L$$B@taG<$P @t&uF 1ۉD$|$ l$$lD$l$$$1[^_]Ë<T$D$$Ght$G$GGhG$G|$$z<$1p_L$ D$T$$1ۉD$l$$ l$\$$뒿|$ t$\$$uT$1L$uÐBt;Hu9Ht勀uÍt&'D$uf@uD$1ÍSD$Xt$u1[ÍD$T$@tPufD$Ptt&BB uÍv'D$Ptt&B BuÍv'S\$$1҉[Í'<1D$D$\$,1ۉt$0|$4l$8$ID$@Bl$@鋍ƋD$ יׁ,$@B@@BD$14$|$D$ 1ɉ\$L$ 4$|$D$$ l$D$(D$$D$D$@$#,$\$,t$0|$4l$8<Í& $ 1҅t‹D$BЃ Í,\$t$ 1|$$|$4l$(l$0$,WƸ,D$1D$$$D$8;CCt)D$|$$  <$5@pt<$|1D$C\$ l$$t3D$81D$$D$$C$[t&'\$t$ |$$l$(,ù4 |0 <$`CPp_pk<$}M',$<$ $4$($0$$\$ D$F$D$ D$D$W$ \$D$ $8D$$o$$$(,Ív'S\$ t(CTL$T$$D$ 3C[Í&S\$ t(C$D$ tD$D$C[Í&VS\$ t$$t4KVt;Qu'&;Ptu1s[^øD$T$$6[^Ít&'UWVS1ۃ,D$ \$$D$ L$D$D$$T$1҉T$ $T$ \$@ՋSDž҉tv@@u҉t&fAtAt AQ tu܃,1[^_]1D$D$ $`D$ øD$1։D$ D$$$T$ L$؋\$'9s$PD$@PTv ,[^_]9v퍴&SD$ Xt3C$D$ tD$D$Cu΃[É'SD$ Xt3C$D$ TD$D$Cu΃[É'S\$ ttCTT$$D$ D$S1CD$C$tt4\$ [f$\$ [t&[Í$8\$ [WVS|$ _u f$ftgC$D$ TD$D$1CL$C$u$$)ut&|$ [^_$8f[^_ÐWV1S|$ t& tt&X$ۉu1 FuЃ[^_É'W|$T$$t 11_É'SL$$\$ Qw A [ø,;D$ \$L$$ S\$$L$ x tP9ZB D$(BB BB(B$BBB[Ë($rtU‰X릸8 D$ \$L$$$8D$T$ D$$ 8D$ +D$D$$fVST$$t$ t6BJv/fAʋYw ً ɉBB uك[^ø,D$ ;D$D$$ D$ËD$1ɋT$=!' $t=tø@ D$T$ L$ Í&1҉l$ l$щ|$$t$G` u>E1U_hGpD$WtډD$Ol ЉGhGh1ҋL$Wl% OhG`WdWd1҉G`%@ t(EEE $t$|$l$ EE։1Ɂs@ÍS \$L [Í&$t$\ t$ $t$Ðt&T 1҉ Ít&'V1ST$ \$t$”     tn  t[  tH  t5  t" t[^ùt&ʨ ʬ  1[^UWV1S D$ T$$L$(<$L$FtTT$ $ 11 uڃMCQAQu1F 1 u uj u\ uN u@ u2 u$ u u1ۉ [^_]ÍvS\$ T$L$wD$شظ[Ív'SD$XD$ P9r)v[9w9wr9t&s&'[[1Ðt& 1D$$T$  Ð&D$ t$t$(|$|$,\$ l$ u1ۉ؋t$\$ |$l$ËT$$$#ō@ $tˉÍPED$D$$$D$T$ 3{\$\$ $@u$1J냐&D$$D$D$(D$D$D$D$ $ UWVS,t$D1D$4$$X:1D$D$$4uD$ $ yD$Jt$$Xt$$SD$(\$HXT$fz0Y1ɉL$$T$ D$$$D$x$TyT$ËD$B2D$D$ $D|kCNF1҉T$T$(C$D$C T$@ljƋ\ @l~r1҉l$ t$T$$Vv%)9vӋD$(\$ $D$ D$)1׋D$@t$|$$u`D$t$|$ $,[^_]$T$B$D$0D$Lt T$BT$LD$ $tT$($,1[^_]ËT$D$$B0;D$$S랡$D$ $D$D$*U$C?!l$|$$D$ V$VD$D$$$r|fUWV-S|$$$t$$#D$$/T$$T$$D$@t$P|$l$ \$t$$uY&v%)9vӋD$T$\$ $D$ HuS)tO1Ջ$|$l$$u|$l$ L$$|[^_]ËT$$1|[^_]$($-ҍ&'VS1ۃt$ vC tt$$u[^û[^Í&'U0WVSD$D$4l$0$pEU4$D$T$ D$$ |$4$T$ D$m(,\$1ۉ4$D$T$ Kt&'D T$L$4$D$ CT$D$ u$ 1ݨݬ4$D$ @CT$T$D$ u$ 1jv' \$C4$D$ T$D$ u$ # 1|$4$D$ T$D$7|$4$D$ T$D$|$4$D$ )T$D$ |$G4$D$ ?T$D$9 L4$1[^_]$^却&UWVSD$D$L$< t< KD$L$< t< PD$L$< t< {獴&S\$ 0u  1$0 X , (  \  1D$ $1D$X $Ȥ1D$X $X CC`0@@1 11(1 1҉,L$T$$: $D$vX $1ɉ$L$1[Ð D$@@h J p X xl <px `KLD`NHOLpQPRT`TX0V\W`0YdZh`^lP`pbtdxg|@j`m@qPuv\Ðt& D$ h  p X yl `<xP pD Hp"L#P`%T&X(\*`+d-h0l2p4t6x9|@<P?CFpH. Ðt&D$p t <\$,ˉt$0t$@|$4ljl$8l$DAT$D$ AQ D$T$\ $J@uiyu7C sQ)ЋQE ЉE\$,t$0|$4l$8<èuŋyF CYF)؉Fƍ&D$(D$D$D$CS L$D$T$ \ $`SFV|$(ЃF n1g&<\$,ˉt$0t$@|$4ljl$8l$DAT$D$ AQ D$T$\ $*@uqyu7C sQYE)ЉE\$,t$0|$4l$8<èuŋSiFVCS FV CQ)F뷍D$(D$D$D$CS L$D$T$ \ $8K|$(NSK FЃVN FZ1St&,t$ ։|$$ω\$l$(8D$tqЉ ΋,@1, @1@1ȉ 1%,]tK%11 t\$t$ |$$l$(,ÍD$El$\$$č&' D$L$T$$荙 É' D$L$T$$] É' D$L$T$$- É' D$L$T$$ É'U W1VS1ۃ,t$@D$ƔX @$D$)&C@tH‹ uB1GD$B\$CL$l$ D$1D$$כ@u@\$|$$趛t dx | kdRP,$xN\$ D$ VS,$xB\$ D$ |$ l$\$t$$D\$?,[^_]붍&U@W1VSLD$`T$D$,X @$D$1D$< G@tZl$,1Eq؃ u׋AD$AQ |$G\$D$T$t$ $艚D$<@u@D$D$<$D$`T$,l$,t x | D$0dT$4kdd$0RP,$xV\$@D$@VS,$xJ\$@D$0D$@T$4\$t$D$ T$$D\$ϙL[^_]뮍&S\$$>[ÍvS\$$[ÍvS\$ $t<L$T$$Ǖ11ɉ| 11҉ 1t x [Í&'S\$ $茙t<T$L$$W11҉| 1 1t 1x [Í&'LD$PL$h\$T$8\$X $pD$8X t/T$4\$t$|$T$ l$ $ЅD$8X T$4\$8t$@T$lCS|$\\$\$\t$`|$dl$hl=t=r=ukfD$|D$D$tD$D$xD$D$pD$D$ \$t$,$1녍v== v'D$|D$D$tD$D$xD$D$pD$D$ 랐t&t =@uŐt&D$8D$ \$t$,$pu.D$|D$D$tD$D$xD$D$pD$D$ ?$L$8<$D$ʉ%=tiwW=;؉%D$8D$@؃%D$X$L$<L$PL$8T$DD$<$B=؉%D$8`D$@؃%D$X$L$f'UWVSӃ|D$8L$b^'UWVSӁΉD$8L$ Gt&'L$ \$D$$t$T$(+Q1u \$t$ËATʋXHpЁDK LȋDtP \$t$þ!R(t$ \$L$$5t&',D$4l$(l$0\$t$ |$$x@4T$΋HPXDQ ‰DDD$/D$D$8DL$A |$8t L$4GA L$41ۋ AHD$4X 11  11 u 11 ] 11 E 11 - 11  11  11 &'L$4T$t$,$L$D$\$t$ |$$l$(,ÍvL$4QA L$ D$4T$@z D$4$轞T$4$@ aL$4QA L$ L$4Q $T$D$?D$4t$$ϟT$4B @BB >T$4$ D$41$ڂl$D$ `D$(D$$H v'WVS |$0\$$>1ҹ8T$L$$ \ @Lt1 D$D$!D$ D$T$$    D$4$    t111t& C‹ 9P rٹ L$t$  D$X @$D$V1 [^_Ë D$D$$ҡ2\$L$$D$ o뤐&1t#1 Buк@ T$L$ T$D$$LÍv'UWVSD$4|$0u 1҉T$ ^1D$l$D$;F7w D$;F (V ΋@1؋@1؋@1؉ 1Ћ8%u؋$ u1ɉ1 T(t  B A u݋V$t  B F$ D$ D$ ) [^_]É @ fUW1VSl$l$|$D$(D$ D$d$j tP$<L$(BD$ \ t$D$$ \$(X $1l1[^_]Ë$F $ 1ۋ$\$,1ɉꉍT$(Zr؉ ΋<ʋ,L$(@1<@1@1 1%,8<(؋O%11 G t$(WN^|1%GD$$l$(T$$$BL$( ˋ I1ыS1 D$,l$(D$,;, $ t 4 t 1l$,SV$ H$ 1D$,u؋$u11ɉ T(t\$(  B A uًW$tt$(  B G$nT$( щ8 DY q\$0t$4 D$1D$<$T$4L$(D$0W tB\$( W$W G T$$D$1҅G+ D$$G]G1Wt$D$T$ $2G=T$(1ۉ\$|$$.W$G )=~~ÃwL$( L$(C  O GW$_$T(@G)ʍB~=rAG AG G G=Y1WD$<$T$G @G -ty1D$H1@W A%tFJ<X $MX $)$jGD$($M$1ɋD$dBL$$VB,p<JI$Tv $r)\$$t$$($aWD$D$T$ $8u؋$<u11ɉT(tt$(  B A uًW$tL$(  B G$\$( D$01T$4D$D$T$ $~\$( lt$( q$pD$ 0D$D$DT$(1 1 \$(8 |  tT$D$ TD$X $&\$(1D$$T$(  )ȅۉ %& L$(1D$@ 3{t$P@{ d6S ΋4@14 @1@1ȋL$( 1Ћ8%^u &$pu11ɉT(tt$(  B A uًS$tL$(  B C$t$(D$@ \$P\$Pt$(dD$4$D$ XD$TD$X $$ 1ۉ\$4$l&$ D$ /D$D$)L$(L$( 7T$( t$( jT$@XD$() T$ TL$T$X $$\$( L$( )Ћ G$Jf D$ tD$TD$X $#t$(1D$< Y{D$L4S ΋4@14 @1@1ȋL$( 1Ћ8%uu t&$u11ɉT(tt$(  B A uًS$tL$(  B C$0t$(D$< D$Lt \$LD$(T$<)  1D$DY{D$T4S ΋4@14 @1@1ȋL$( 1Ћ8%u t&$u11ɉT(tt$(  B A uًS$tL$(  B C$t$(D$D L$Tt \$TD$(T$D) T$( ,t$( T$( t$( S&'U1WVS t$ l$ <!W ΋@1؋ @1؍@1ȉ 1Ћ8%0 u ؋$0u11ɉfT(t  B A u݋W$t  B G$ D$ tD$) t$ۉu싖 t $D$ $c8D$ [^_]M D$`ÍvT$D$JR !9ÍT$L$B R!9Ðt&1Í'1Í'1Í'1Í'UWVS,D$@D$D$ D$1D$D$($tGT$@<L$BD$ \ l$D$$\$@$,1[^_]ËD$@@ $,1T$@1D$H @ @$‹px 1D$ T$1 \$1%‹ D$b%HPpDQ Ӌ|T$D` dd ڃx|D$хu L$AQL$@Aup\$ K s11 \$E;, $ t 4 t11%@C$ H$ \$C CL$@AQ\$@CSCSCH$@  L$@Au T$@@;2$1rL$@^BD$ L$|$$L$ CD$@v$UT$@|$t$$T$@1ۋD$(B\$$v't$Ɖ\$HXT$$<L$\$ X $/\$1t$É' 1 f 1 f 1 f x1 f C > $$$$$$$D$($T$,HX@Q D$tD`T$4 `\$x|$ $D$|$t$ t$8\$@\$4$sT$4Bv^$D$D$$t$T$ $D$$1$$$$Ĭ$Lf D,$$t$L$D$ $T$$1$D$$D$$t$D$ vD$$$T$$Z1'$$t$ D$T$ D$D$$$D$$1$t$ @D$D$$D$ fD$DD$$$t$T$ fD$T$Y$D$$D$$ 떋$Y$t$L$ T$D$$D$ $$1$Y$t$\$T$ $D$$$D$1h$D$(T$,t$H% ȉˉD$$ ډT$t$D$ $Ht$|$ЉD$(T$,D$(T$,D$T$$T$ $4t$l$ЉD$(T$,D$(T$,D$$T$D$$D$ $$T$$n1;$t$ЉD$(T$,D$(T$,D$T$ $D$$T$ $$D$D$$D$1$t$D$D$$ D$$D$ D$$$t$D$$T$ D$D$ D$$$D$$1$t$D$$D$D$$D$ D$8$$t$T$ D$D$$ D$D$5t$D$$D$$ D$$D$ D$$$t$T$ T$D$$D$D$$$D$ D$$T$$WvUWVSl$$$tt1l$$G\$t$$PȉD$$L$\$ t$D$,$l$ \$t$$9$ul[^_]Ít&S$ dt>1ېt&x|$D$`T$ D$& uɋD$ d ` $lT$D$[Ã1dt#1 Bduк`@T$0L$ T$D$$Ív' $Ӊt$|$HPpDQ DڋD` dd x|хuGW$t$|$ Ít&'у $Ӊt$|$։׋T 1T T$1T$1$t$|$ Ã$Ӊt$L 3L L L$T$1ʉT$1$t$É' ʉ$˃|$ˉt$Njt$ًD 111 t$Ћt$|$ É47፶' |$lj$t$L \$t$D 111 t$Ћt$|$ É6' \$Ӊt$ƉЁʃT FL$$\$1t$ Í \$Ӊt$ƉЁʃT FL$$\$1t$ Í \$Ӊt$ƉЁʃT FL$$h\$1t$ ÍSӋL +L L T$1[ÉSӋL +L L T$1[Ã$t$L T T L$1$t$É'SщT  T L$1[f$t$L T T L$1$t$É'SщT  T L$1[f |$ljt$։$ \$L ;\$ws1ɉ\ L$;L rv11T D$$1t$|$ Ív |$‰$Éىt$ˉ;\$rvD 1D$;L wv1D 1D$$1t$|$ Ív |$‰$Éىt$ˉ;\$|~1҉L T$;L wv1D 1D$$1t$|$ Ív |$ljt$։$ \$L ;\$}D 1D$;L rv11ۉD \$$1t$|$ Ív$t$L T T L$1$t$É'SщT  T L$1[f \$Ӊt$ƉЁʃT FL$$d\$1t$ Í \$Ӊt$ƉЁʃT FL$$\$1t$ Í \$Ӊt$ƉЁʃT FL$$\$1t$ Í \$Ӊt$ƉЁʃT FL$$\$1t$ Í \$Ӊt$ƉЁʃT FL$$l\$1t$ Í \$Ӊt$ƉЁʃT L$$\$1t$ Ív \$Ӊt$ƉЁʃT FL$$`\$1t$ Íу $Ӊt$|$։׋T  T T$ T$1$t$|$ Ã$Ӊt$L  L L L$T$ ʉT$1$t$É'$Ӊt$|$l$ | l$L$T Ӊ҉\ T$1$t$|$l$  уt$1|$lj\$\ L t$$1ۉL$D$$$\$ ։ɉ 1(\$,t$$|$Ðt&$\$t$|$l$ T L D$ ͉$D$$t$$<T$ Ɖ $1(,\$t$|$l$ $Ít&'SӋL L L T$1[ L$T $ 1ÍvL$T ,(1Ív  1 Ít&  1 Ít& $ t$T T t$1$t$Ív' уSt $D T$[1Ít&' уSt(,D T$[1Ít&' :&1 Ít& Z1 Ít& \$Ӊt$ƉЁʃT L$$X\$1t$ Ív \$Ӊt$ƉЁʃT L$$t\$1t$ Ív \$Ӊt$ƉЁʃT L$$p\$1t$ Ív \$Ӊt$ƉЁʃT L$$T\$1t$ ÍvсS˃L \$1[ \$Ӊt$ƉЁʃT L$$\$1t$ ÍvсSىL \$1[Í \$Ӊt$ƉЁʃT L$$P\$1t$ Ív \$Ӊt$ƉЁʃT L$$L\$1t$ Ív \$Ӊt$ƉЁʃT L$$|\$1t$ Ív \$Ӊt$ƉЁʃT L$$x\$1t$ Ív \$Ӊt$ƉЁʃT L$$\$1t$ Ív \$Ӊt$ƉЁʃT L$$\\$1t$ Ív \$Ӊt$ƉЁʃT L$$H\$1t$ Ív \$Ӊt$ƉЁʃT L$$D\$1t$ Ív,l$(ʼn\$t$ |$$pL x\$  L$11 ‰\$1%‹ WˋHPpDQ Ӌ|D` dd x|ыD$T$EU\$t$ |$$l$(,É L$|$,$ 8WVS O _ЃL \$GL \$WD$ L$L$\$ӉT$ 11 D$1%‹ ˋHPpDQ DڋD` dd x|ыT$L$WO [^_É L$\$<$ Ev!\$L$$D$ j ;4$~4t$D$$I$r'U-WVS|$$T$$誦$踡T$$T$$D$ @t$P|$\$$t$ -uNt&v%)9vӸl$ D$\$ $HuP)tL߸D$$|$$uD$|$$|[^_]É,$I1|[^_]$ã$-谣҉'VS$t$0$蛧CL$D$ C T$D$CD$D$ C$@D$1D$C D$ D$CD$D$CD$D$ C$@D$D$蠥C0 L$ D$ C,T$D$C(D$ D$ C$$@D$D$TC@D$ D$CD$t΁!9D$t΁!9D$t΁!9D$t΁!9yB11%L$t1ۃD$@D$tT$D$L$8L$8%D$XD$(t$<\$PT$$&Tr&'L$v1É u!ʃ‹D$Qtԋ@ Ãڍv'SD$ PtS\$HÌt&Qt5Aw‹QÉQPQu׍[Í&'W1VSӃ D$$}tsL$Ջ@3ҍ@3@3 1%u"f<t;0u%9t v [^_ø D$T$4$q!Ӌ< @1@1ȍ@1Љ1Ћ%됃\\$LӉt$PƉ|$Tρl$Xʃ%;uFZtfD$81D$<D$8D\$Lt$P|$Tl$X\ÍD$ D$1D$D$D$ l$8l$D$\$4$t@ lHX t=l$1$l$L$ \$D$P$1#D$\$L$ D$$ݤ&S\$ ÔT$L$$r{\$T$$R{[Í'T$$\$\$ t$t$(v \$t$É uhЃȍBtωp t$T$$zt$\$(\$L$$D$ z듍&S\$ t,${$x{11$\~tv$F~t`L$T$$ zL$T$$y11ɉ111'0:0-200@&PB?=.86P4* 0%x%=@u!1[Ít&'UWVSÃ\D$,ȜˠD$HT$Llj胃%;G G u{ot]t$H1ɋ|$L% É 1 ډ؉% Ɖ  ]M\[^_]ÍvT$,sOd Ë@3@1Ћ@1Љ 1%490ut&;0t<ut$ Ћ [1ˍ[1Ӎ[1øD$D$,$T$,1Á;0g jD$0D$D$D$D$ D$D$,t$Ht$l$$@  HXD$, tKt$t$L$ \$D$$P$12\$L$ l$|$$'Lt$DL$Xt$P\$@\$T|$H‰؃%;uJ%ȋ\$@t$D|$HLÍD$ D$1D$D$|$81|$D$ L$\$4$1tB tJZ t4|$1|$t$ \$D$$P$[D$D$\$L$ $՝12&'\\$LӉt$PƉ|$Tρl$Xʃ%;u_Zt1ȉT$;0ut$ Ћ [1ˍ[1Ӎ[1øD$D$,$؋T$,1Á;0g D$0T$,D$D$D$D$ t$Ht$D$l$$~@ SHXD$, tKt$$t$L$ \$D$P$1 2\$L$ l$|$$D$@ÐT$D$JR!9ÍT$L$BR !9Ðt&L$T$B Bt P ÉÍ'T$tf@@uD$Í& ST$$\$ u.1t [Ë T$L$D$ $`Ѝ,|$$|$ht4Bdh؉V @11<[^_]Ë=L1D$ , T$4cdY ‹@3 @1ȍ@1ЅD$$(((e,8t(<t 88181<$u &($$>u11ɉ$T$thdBh1l$A@u׋W thdBhGG $=T,D$$T1D$$d$$D$$98D$ l$4t:|$4v-t$\$$L D$ @D$ TX)|$D$ L$$1ehh)҉F tTL$T$D$ $dL1D$Y, D$0R ‹@3 @1ȍ@1ЅD$(((,8t(<t 88181<$u($;u11ɉ$T$thdBh1l$A@u׋W thdBhGG $i;T,D$T1D$d$D$;8D$T$0|$0L(P,kdL1D$(, T$8R ‹@3 @1ȍ@1ЅD$,e(((@,8t(<t 88181<$u($:u11ɉ$T$thdBh1l$A@u׋W thdBhGG $9T,D$,T1D$,d$,D$,98D$(l$8tg|$8L9(P,D$)(L(P,D$()st&UWVS\D$pD$$tT$D$1D$D$X$T$ ;tIL$p\$AD$ D$<D$$L;$a\1[^_]Ët$pF $l91l$ l$p1ꉽvT$W\$ ȉ ҋ<4@1@1@1Љ1%<48';D$FV FˁD$l$T$T$pBL$p9D$ t$l$ ;ttnudT%ftT1ۉxtHt t/1ɉ$L$ҋT$1D$ 1l$ ,(((,,8t.<t 8<8181<$u؋$6u11ɉ$&'T$t\$hdBh1D$A@uӋV tl$hdBhFF $5T$T,TL$D$T1ɉ$D$^\$$\$Tz,TD$1D$4$ 4l$$.T$T0΋,ʋ @1@1؍@1ȉ 1%4D$hcB\$hdV F1D$$D$1҅FD$$2FD$@Fl$L,1(L*T$L$(L4<؉8t <8\$444$<D$ 2D$D$<6$u؋$T3u11ɉ$T$tl$hdBh1D$A@uӋV tL$hdBhFF $2\$T,Tދl$pD$ED$ D$ D$$v5,$N[D$)\$pCt$pFVFVFt$H%$@ 2T$pBuF@;$1oW\$pL D$L$$4T$$ԍL$$"\$$`ZT$p?Ⱥ @@tcD$T$pT$p$ ZL$p D$TD$ $MYD$p1@D$Xl$${.l$t$,$F\$鉵PD$| D$$3$u؋$0u11ɉ$T$tl$hdBh1l$A@uӋV tL$hdBhFF $10\$T,Tt$$ \$t$$21$ D$ +D$D$2Y$2t{(l$P(,T$L/L$T$$ D$ $2t$RL$1D$0L,{ l$Dv{dl ‹@3 @1ȍ@1ЅD$4M(((,,8t.<t8<8181<$u($L.u11ɉ$T$tl$hdBh1l$A@uӋS tL$hdBhCC $-l$T,D$4T1D$4d$4D$4;uD$0\$Dt3\$De,l$L(L$PT$0XD$)T$ TL$T$$NU\$hL$)ЋhIF /‹Tt\$L$D$ $TL$1D$(L,{ l$@n ‹@3 @1ȍ@1ЅD$,(((,,8t.<t8<8181<$ut&($+u11ɉ$T$tl$hdBh1l$A@uӋS tL$hdBhCC $g+l$T,D$,T1D$,d$,D$,;D$(T$@t \$@mD$T$()L1D$8,{ D$Ht ʋ, @1@1ȍ@1ЉD$"I'SÃT$$4 D$'$覀1[ $T$y Ív $%1 $1 S$ " t=1ۍt&$D$T$ D$6&uɋD$ $lT$D$&[Ã1 t!11ҍ'AuȺ{{T${L$ T$D$$`  Í |$ǡ$t$XHpDK DD )ȃхu$t$|$ UWV1S1ۃ (\$l$$&%ʋXHpDK DD )ȃօu%9k 1[^_]ÐL1Í'SÉЉD ?Jt T@1[Í@D1[Ít&'SD ?Jt @T1[Í@D1[Ít&'1Í'1Í'1Í'1Í'S3TT1[ÉS3TT1[SщÉ T3Tx+yT1[øِSщ T3TT1[É'ʉt$l$ʼnD$\$ |$|9}9t:D$,$!u\\$ t$|$l$,9t:9ǍrvD$u1vD$u1vu9sٍ&u'붍&'щt$Ɖ |$\$\ϋD9};t<4$T$Ut\\$t$|$Í>9tL9r&vu1\$t$|$Í&u1&u9s&ot&뤍&'SDЉ9v | y1\[ÍvSDЉ9v 1\[Ív'VƉSDЍH99v 1T[^Ð& t$Ɖ$Ӊ|$T҉ σ|199v 1|$t$|$ Ð t$Ɖ$Ӊ|$T ҍJ|199v | y|$1t$|$ à t$Ɖ$Ӊ|$T ҍJ|199v 1|$t$|$ Ð& $Ét$։|$T Dlj)11xM| y|t$1$|$ Á t$Ɖ$Ӊ|$T Dlj)11x%1|$t$|$ Áٍ&SÉЉ D+Dx+҃yD1[úِS уL+LL1[É'UWVSÉȃ lЃt|1~TqOtFEuF؉ u1Ouƍ 1[^_]ÍUW1VSÉЃ  tlt1҉׉~q(f 1[^_]1 q t&O~EuF؉ u1fSÉȃ DtDƒ 1[É' щ|$ ׉t$Ɖȃ$\ DÉ 1\$t$|$ щt$$ډ|$NjTӉ 1\$t$|$ Ív'SÉЃуtT؃ 1[f щ\$É t$tЃtT֋u;1ɉx\$1t$ ø1\$t$ f؃x11\$t$ øݐ&SÉȃ DtDƒ1[É'SÉȃ DtDƒ1[É' щ|$ ׉t$Ɖȃ$\ DÉ1\$t$|$ щt$$ډ|$NjTӉ1\$t$|$ Ív'SÉЃуtT؃1[fWщljVStTփ ˉ'ىC u[1^_Ðt&SÉȃ DtDƒ1[É' щ|$ ׉t$Ɖȃ$\ DÉ1\$t$|$ щt$$ډ|$NjTӉ1\$t$|$ Ív'SÉЃуtT؃1[fSÉȃ DtDƒ1[É' щ|$ ׉t$Ɖȃ$\ DÉ1\$t$|$ щt$$ډ|$NjTӉ1\$t$|$ Ív'SÉЃуtT؃1[f |$lj $t$\? uSЈt| yt$1t$|$ ø1Ƀ $É |$׉t$t? u#DD$1t$|$ 1t獶t$1$Ӊ|$ l$ lىxG| y|$1t$|$l$ øЅt럐t& t$1$Ӊ|$ |كDx$1t$|$ øЅtՐt& $1t$։ |$L| u7Dx$1t$|$ øЅtՉDv' |$lj $t$\? uSЈt| yt$1t$|$ ø1Ƀ $É |$׉t$t? u#DD$1t$|$ 1t獶D$Љt$ ֋T$ \$|$l$l|à $1;$sӃډ!xFL$yL$1T\$t$ |$l$ø뾍&D$Љt$ ֋T$ \$|$l$l|à $1;$sӋD$!\1\$t$ |$l$Ít&l$ʼn\$t$։|$ |$ $1;$sӉ !xAy1T\$t$|$ l$ÍvÉ'l$ʼn\$Ӊt$|$ |$ $1;$s։ !t1\$t$|$ l$Ívl$ʼnD$Љt$ փ\$|$| $1;$sӋD$ Njt!Ӊ! x<yL$1T\$t$ |$l$øȐ&D$Љt$ ։l$ՋT$\$|$|à $1;$sӋD$ NjT!! ߉|1\$t$ |$l$ÐS TT1[ÉS TT1[ÉSÉ D Dx1҃yD1[ÍӉ'Sщ T TT1[Í&SщÉ T Tx+yT1[øِSщ T TT1[É'SÉ D Dx0҃yD1[Ðt&ԉ'Sщ T T҉T1[Í&ЃD؉D=t&|8y1Át&'̉'ЃD؉D=t&|8y1Át&'̉'SÉLك| yL1[Ív'TډT1Ðt&SÉ D#Dx0҃yD1[Ðt&ԉ'Sщ T#T҉T1[Í&$D$ ЉT$T$ \$t$|$l$ LD$ D$T$4$|$$,T$ lj鋲11 uZ| ɃT$ yT$ l$d$L$D1\$t$|$l$ $ËL$ f$D$ ЉT$T$ \$t$|$l$ LD$ D$T$4$|$$,T$ lj鋲11 u,l$D$ d$T$|1\$t$|$l$ $ËD$ ƒ$Љ\$$l$Ջ$ t$|$ LD| Ƀ$y$D1\$t$|$ l$Ív'у$\$t$|$׉l$ ŋLTӉ$D$ $\$\$ L$t$؋D$D$$$$1T$$T\$t$|$l$ $ÉSTT1[ щ|$lj t$։$LD1҃| ɃyD1$t$|$ Í'у$t$1|$1l$ ʼn\$\t$|$ $ tt$D$$$׉Ɖ1t1\$t$|$l$ $Ð$Љ\$$l$Ջ$ t$|$ LD˙։Љ| Ƀ$y$D1\$t$|$ l$Í&'у$\$t$|$׉l$ ŋLTӉ$D$ $\$\$ L$t$؋D$D$$$ډT$T$$$ЉD1\$t$|$l$ $Ðt& T $u1 ÍVS у ƒtxvF|9f:t&uNDBfv]f&uD\fDh1[^ÁuDp؃tbu΋Dx뷍&D4$T$D$L1[^ËDt눋DL4$FtqD%߉DMDX>Dl/D DD1҉T%ft 1҅1ÍS y D@tD tDtDtD tDtDt D[1Ð T T1Í' T1Ít&VS у 1D, v\$&:t&t&u>DLfHt&vJv1D1[^fD1[^Á St&utDfv]f t&z|D눉4$T$~D1[^ËxDaDR/LD:~DhD ЉD`DDlDXDdDD\DpDr&S|2|L1[ÍvSL1[Ít&'TL1Í'S ˋ ˋ ˋ ˋ ˋ ˋ ˉ\1[Í&'1ÐUWVSÉȃ lЃtTՋ1~TqOtFEu F1D؉ u1Ou 1[^_]ÍUW1VSÉЃ  tlt1҉׉~q(f 1[^_]Íq 1ɉ t&O~Eu F1D؉ u1뼍SÉȃ DtDƒ1[É' щ|$ ׉t$Ɖȃ$\ DÉ1\$t$|$ щt$$ډ|$NjTӉ1\$t$|$ Ív'SÉЃуtT؃1[fSÉȃ DtD‰1[Í&'SÉȃ DtDƒ1[É' щ|$ ׉t$Ɖȃ$\ DÉ1\$t$|$ щt$$ډ|$NjTӉ1\$t$|$ Ív'SÉЃуtT؃1[fSÉȃ DtDƒ1[É'WщljVStTփ ˉ'ىC u[1^_Ðt&SÉȃ DtDƒ1[É' щ|$ ׉t$Ɖȃ$\ DÉ1\$t$|$ щt$$ډ|$NjTӉ1\$t$|$ Ív'SÉЃуtT؃1[fSÉȃ DtDƒ1[É' щ|$ ׉t$Ɖȃ$\ DÉ1\$t$|$ щt$$ډ|$NjTӉ1\$t$|$ Ív'SÉЃуtT؃1[fSÉȃ DtDƒ1[É' щ|$ ׉t$Ɖȃ$\ DÉ1\$t$|$ щt$$ډ|$NjTӉ1\$t$|$ Ív'SÉЃуtT؃1[fSÉЃ TtLʉ11[ S\| y1\[Ít&'TT1ÍS\| y1\[Ít&'TT1ÍSщ T3T҉T1[Í&VSÉT tt1Ƹ| yt1[^Ív'щ$Ét$T tt1D$1t$É'VSÉT ttNt;ЙƸ|<x1t1[^Ãu1yσʍv'щ$Ét$T ttt1D$1t$Ðu'1Í'1Í'1Í'1Í' t$ у|$ljщ$1بt,փ $1t$|$ Ðփ!ҍt& t$ у|$ljщ$ بt+փ $1t$|$ Éփ!Ӄ t$ у|$ljщ$ بt,փ $1t$|$ Ðփ!ҍt& t$ у|$ljщ$ بu,փ $1t$|$ Ðփ!ҍt& $ t$ƉЉ|$Ѓu+Ӄ $1t$|$ ÉӃ!Ӄ $ t$ƉЉ|$ЃЅt2Ӄ $1t$|$ Í&Ӄ!̍t& t$ у|$ljщ$1بu,փ $1t$|$ Ðփ!ҍt& $ t$ƉЉ|$Ѓt+Ӄ $1t$|$ ÉӃ!VƉ1SӋT t&A tt1L[^Ðt&щt$Ɖ$;Twۃy1$t$Ív'VSÉt L9r 9y1[^fщ$É҉t$9T| t6y1$t$Ít&'щ$É t$T9T| t6y1$t$Ít&$t$ƉӉ|$l$ տuH1lj11҃ t$Ћt$|$l$ Ð&$l$ Ճt$Ɖ|$uH1lj11҃ t$Ћt$|$l$ Ív\$t$ƉӉl$|$ Ѓ$u"H$1ŋ$$ً,$1$$$$ 1҅t >\$Ћt$|$ l$Ív'$l$ Ճt$Ɖ|$uH1lj11҃ t$Ћt$|$l$ Ív\$Ӊt$Ɖ|$ ׉l$ƒ$uH1ʼnڋ$$ً,$1$1҃$$ $ ȅt Ǻ\$Ћt$|$ l$Ít&'\$Ӊt$Ɖ|$ ׉l$ƒ$uH1ʼnڋ$$ً,$1$1҃$$$ ؅t Ǻ\$Ћt$|$ l$Ít&'|$ lj\$t$։ƒl$$uH1ʼnڋ$$ً,$1$$$$ 1҅t ƺ\$Ћt$|$ l$Ít$Ɖ\$|$ ׉ƒl$$uH1ʼnڋ$$ً,$1$1҃$$ $ ȅt Ǻ\$Ћt$|$ l$ÍÍt&Ít&  SÉЉ#Tx+yT1[øِ&SÉЉ҃#Tx+yT1[øِ&SÉ D#Dx1҃yD1[ÍӉ'Sщ T#TT1[Í&SщÉ T#Tx+yT1[øِSщ T#TT1[É'S1ҋT9v | ҃yD1[Ít&'Sщ1ҋT9v D1[fVSӋ1DJ4BtI| y1t[^Í&9v뱍v'щ$Ét$1DJ4Bt"1t$t$9v؉'SÉЉtL1L[ÍVƉЉST19| y\[1^Ít&SLڍ9Ƀ\1[ÐSÉtL1L[Í&'t$Ɖ|$׉l$ $1L \ 9Ӎ,wh9wdt&11хxa| yl$1t$|$l$ Ív듁띍&t$Ɖ|$׉l$ $1L \ 9Ӎ,w=9w9t&11хx61l$t$|$l$ ø뾁f $Ét$։|$1| D99ȍwO9wK&| yTt$1$|$ ÿ밃 $Ӊt$Ɖ|$1| D99ȍw,9w(&1T$t$|$ Ðt&Ӎv $Ét$։|$T L1< 911҅xM| y|t$1$|$ Á뱐 t$Ɖ$Ӊ|$T L1< 911҅x%1|$t$|$ Áى'VSÉT t19| yt1[^Íуt$$ \уt19 t1$t$Ð& $Ét$։|$T Dэ<11҅xM| y|t$1$|$ Á뱍&' t$Ɖ$Ӊ|$T Dэ<11҅x%1|$t$|$ ÁٍSщÉ TTx+yT1[øِSщ TTT1[É'T1Í'L1ÐD$@1fD$É'D$1ɋÍ $Q Í'S\$ $DD$D$D$$t$z$@t$1[øpD$$fVS4t$@4$/$#1D$D$4$6D$$V\` $D$ 11ɉD$1҉D$ D$\$L$T$D$4$F(111ۉL$T$ D$ gD$1D$D$\$1ۉD$4$赆D$ \$4$D$1D$1D$D$ D$H1T$L$ D$4$B1D$1D$4$>F\$4$D$D$ 1D$D$&4$ L$$W4$$@$ <V\D$0Ôt"D$0D$ 1D$T$$3.KFPD$ 1D$FT$D$.\NpU}D$ D$$$D$VptJD$4$D$ pD$D$t8F$14[^ø믍t& yF41[^ÐD$4$oD$4$^4[^Ívm4$D$*D$D$D$1D$ D$E$F\4$D$D$F\pD$4$ FT\$4$D$ S\$t$$x@t$M[ÍvpD$$O1[Ð\$\$$t$t$(D$ D$ \$t$$t ؋ZJt$)؋\$ȉD$ \$1t$ÍT$l$ L$$t$|$HE uEw!HE$t$|$l$ Ãu؋1y1ɉ% É 1 ډ؉% Ɖ  ]MyfEEE`EEGEȉE4v'UWV1Sl$11Ƀ 3CCl$,S,$D$ RD$@T$D$MS 7t_6l$ D$CD$CS D$T$SD$T$ G$`D$FtY=9&.@l$l$,L$,$`1l[^_]Ð&t$D$,t$ |$T$0l$|$$\$ l$($T$t^11ۃtcD$4Z\$ $zB1Z\$8j JZ B@\$ t$|$l$Ë띋1듐t&<1\$,\$Dt$0t$H|$4|$Ll$8l$@D$1D$ |$\$t$,$\tZ@ugJtD$D$D$؉t$ JT$)ȉD$$R$…t ff\$,t$0|$4l$8<ÍD$$D$T$D$\$t$ ,$t%f؋Z)؍뛍t&<1\$0\$Dt$4t$H|$8|$@D$ 1D$$1D$ \$t$<$c@ubJtD$ D$1D$؉t$ JT$)ȉD$$R$tM\$0t$4|$8ƹ 1E ]E"D$L$XT$ED$hɉU Ety|$\E D$D$4D$<$(@]D$4 ED$$$ljF(tXMtk1҅tt& B9uM0D$4T$\D$E$D$OE @D$4EtMD$Pl$$:<[^_]ɋD$$vu1MW4$1c뷡1\$\$$%$71,$-끍t&'LD$`T$dt$@t$Tl$H\$<|$DD$T$$4Qù 1E uED$T$ED$XU T$hUug|$\|$\D$4D$T$<$E @D$4EuD$Pl$$؋t$@\$<|$Dl$HLÐց T$$$"ljC(tMt(1҅t B9uM냉‹D$$vt W1͋D$h$D$E/,$1藱;1ۉD$t$$V$R1,$[W$4@tL1׹ B gBB D$ BB$PT$$腸1_øgD$D$$诳Ր&UWVS,l$@D$LT$Pt$HD$ T$$u[,t$$D$u$4]ƉNjD$ F D$DT$$D$ V FD$TFCFC F CFC$F$C(F(t$,$膷,[^_]Ét$ 1E T$D$$該,[^_]øT$D1D$T$$|$D|$ E D$D$$Z믐T$D$DHJ!Ít&S1ۋT$ L$DltDH [Ð&UWVSD$Pp҉T$tU1۽4$J $C;\$t2L$TJtHluҋJ C! $;\$u΋4$[^_]Ð&<\$,ˉ|$4ljl$8Չt$0D@D$$Gt$@!É\$(!ƋD$(DPd @`1JDKhAChG t )ȉ`BU;rLp!‰SlDxhu@d@h&\$,t$0|$4l$8<ú!ЉD$(t@t$@!D$GL$L$@T$\$ l$L$D$$,蠯t$@!փЃ뺋X\uL$$T$@qٍT D`DH\AH\ t 1H 93DB`B\BdBhL$$T$@t냉?qTDl$G'UWVS t$ l$$|$(Ft1ۍt&ډC<$9^w [^_]Ít&UWVS,t$@Nn1)D$DuC\C`CdG9~VuClFtNDH1T$DD$D$DT$L$l$ D$|$F$D$ŭDH_D$DpC\GC`Cd9~[Ft$1ۍv'D$DډC$]9^wD$DF,[^_]ËD$D!ЃЃ@T$1t 1zÍ$\$ t$L$t$C9v&CPt1$t$fSD$\$ T$D$C9v#CуtT$% f1Z[Ðt&D$ ␃t$t$ $\$|$|$l$ l$AG9GPt:1<t<t0ȸE$ȋt$|$l$ Ít&CG9s͋GPt $E$E뢹또S\$tCt$CC[fWVS\$ |$$t0s &v t|$$9u[^_Ã1ۉ[^_ÐUWVSD$ |$l$tJG9D$sDL$1t&L$4+G9v#GPuC9\$ u[1^_][^_]Í&'UWVS\$$L$|$tlD$ A9lj$sai1ɉ(%A 9L$$ft:D$ $)9t.ЃtuA 9L$$fuZ1[^_]Z[^_]Ív'\$\$$t$t$ |$u\$t$|$ÅtFt$MFFC$2tCS<$D$T$t~CF1\$t$|$Ðt&WVS|$ t1  v t|$$)u[^_Ã1ۉ[^_ÐWVS|$ t1 v t|$$٫u[^_Ã1ۉ[^_ÐWVS@|$ t1L@ v t|$$艫u[^_Ã1ۉ[^_ÐWVS|$ t1 v t|$$9u[^_Ã1ۉ[^_ÐUWVSD$l$D$E<ȸ8T$tP 9vU9sQuFuAu7;P|;P~0@$t$H tHPPtQ@ [[1Ë@tX9u[Ít&D$T$L$ @ u @,t 9P u9HuÐ&D$T$t ҉Pt@BÍT$L$ tD$JD$BBtHÉ'S\$(L$$AtCPt%D$ \$L$$҅ƒt[Ðt&1ut[Ë@[ÐWVS@@ |$|$ D$ \$<$袈^ t{|$ t&D$$[,tYCD$C |$D$CD$ CD$$$ D$ׅCu$ [,u^t'C([$u@[^_fD$ XXD$"G'S\$t+$ D$R D$[i[Ít&VSt$tZF tX,$襂ۉuFt&X$$腂ۉu$ut$X[^iX[^Ðt&T$tJ,tB0A0B0tT$9Ð&T$tJ$tB(A(B(tT$ Ð&t$t$ \$1ۉ|$tQ$,ۄtSù 1CFVCCF҉S$C(tC$B(^؋t$\$|$á$\ D$ 1D$D$-ōt&'S$@t@@@@ @D$ $蜆D$$C[á+1ۉT$$ D$ D$裃ΐUWV1Sl$0\$@tQE u Rf@,tI;X uT$D;Pu 1\$ D$D$DD$E|$D$$J[^_]$4Tƹ 1nD$4D$8FD$<^ FT$DVD$HFD$LFD$PF D$TF$D$XF(E F,E U F0tF,B0L$Pu h4$T$P[^_]á.t$1\$$ !D$ h)v,1D$(1D$$1D$ 1D$D$D$DD$D$@D$D$([É'S\$ dt6$o`t ddd$PmCfE0$CiE0E4p$#f_ f0T$$d$d$$G qt0t9|$t$$$D$ h L$L$$T$$⿉T$$G\$L$$$D$ hh$&7e(l$1ۉ|$$%D$ )hT$$$D&d@T$$D$$%D$$Wt D$$D$2D$3D$E,$e|$$$D$ D$g$#ed"L$L$$=Xv=t&it&==t&9t&T$$-$D$ D$f/QGT$1T$t$E,$gE,E4E = =t&==%t =,=XT f}\$1ۉL$$$D$ e,$c==L$T$$$D$ e &VS:4D$ D$t$@D$D$D\$$aaD$$g|1D$ D$1D$D$ $'aFF~oD$([`uMD$$$$$D$G,$V$$$D$$D$G,$yV$$$T$$D$G,$AV$$"$D$$D$G,$VG@&T$TD$ GD$'D$$ Z&G,$YG,wH$ZD1Q!;@=D9@D-C D$$v%D$Y$'\Z CcD+H$YD1Q!;@D9@D$0Wt8t&Gv Gt&H$XD1Q!;@5D9@D$V%GvGvGt&{D$us 1@,C@,DF9s C7HTKʃ;u͋@,؅kCHTKʃ; P, T Љ .OJ>АVCvJC{6HT;  P, C@,TCJC@C$C eu| v@tjftcSD$CD$ .D$BD$$TCCC==ut&Ct&Ct&C t&@,@, C s 1$ P, C@,TG9{ wKCt(ʋHTKʃ;u@, CC{C$C fUWVSLD$dxD$pl$l1퐍&D$lWP\$hwX))ЋT$tD$$NL$$!ދR\$D$T$ t1҉D(OTD\L(ډ $L$p_P9l$lwL1[^_]Ët$lD$t@t1t&D$hOTOXI!L(D\ $1L$l1ҋ_PD()) t1L$t  QOP9t$lwL1[^_]ÐFL@4$GT$@s>F f|$$PFPn,$yD$T$s,~FD$$V T$PD$FPF8fV$T$$ yF0F4D$$~4F(t9D$@l$$yFT$@t$$D؋t$0\$,|$4l$8<ÍvFPD$/D$$AFP$>4$1>볡1$/D$ D$D$3A눡"L$T$$/D$ A렐&S\$T$t0CD$$CPt$>\$[=t&[Ít&' D$@u Ë@(tT$ЋT$$T$T$T$?1ӃT$0D$$\$\$(t$t$4|$ҋ|$ HuQHtDT$ 0T$QH vH0T$ L$<$D$]e1\$t$|$É؋Y(t$|$؋\$Ít&$80 Uv؃0 t5 1AH뚋~6AH  0 ALy(1D$t$$;1SUt U Fu1AH 3Q(AH1 t5 F`1AH AHt+1UtU F&1AHv5 t^wgw_5 5 u1AHxvA$5 Fu1AHO1AHA5 t5 ?1AH1AH 1AHD$T$PtT$ PxÍ'S\$L$ STKX ЋSPCT!ȋ”[S\$L$ STKX!ЋSPCT!ȋ”[S\$T$t CD$$A\$[d:t&[Ít&'S\$t1t$11[ÍST$D$t0w+i\p1S t$谠1C [f[ÍD$ T$$u Ëu퉐1ɉD$ЋL$ D$$转1͉'SL$ T$$\$(tv [iDpx uX nT$ L$D$$a1ˍ',D$8T$<|$$l$(l$4\$t$ D$T$$8!;8!1T$wD$_<$7T$0/4$WP@oGi$D$T$o0G D$@W$T$0G<rƇG($Ƈ\$?D$0t$$ >1\$t$ |$$l$(,á&\$L$$`0D$ :뾍UWVSL\$`l$hf ‰ЃT$(D$88@D$48D$3f89 …T$,T$3f ‰- T$$f vgT$(f89 ‰T$$T$$L$8툄8t$48Af -|$dʉL$Df8AL$H8 ƍBf8L$#9L$=:L$>;D$?;l$,BD$@v|$,T$#D$=L$?|$ D$>  ЉD$1D$ D$dD$CP$KrL$@׉)89ut$Dщ 8D$H8D$$D$$t&L1[^_]ÍUWVST$Tl$XT$ \$$9v1L$8)݉D$ D$ \$L$D$FP$p\$ D$3t D$(uiiD$`0 L$XD$0ʃ0809D$2 fD$2D$3 u7T$GJKT$0É҈2829D$3 tɋD$Hf2829 ǍQ2829t D$2L$0% fD$21918l$(giT$`2A T2|fA BR!fL$`n F`N\% )‹FdF`Tthyd~T VPNXFT!ȁ”<[^_]ÃD$XHT$`n!F`x^T!뛃D$XUWVS $ $ $ $ $ xu A=8=Da9 'zt&/ @t&'1҉؃~؉Ӄ u1҉t& [^_]Ív t_1X@t&z .1EA뉅Gi1Amo !)ЅTыWT!ЋWPOXGT!ȁ”1iD8|D$D؃(t&'1ҁ [^_]Ád \p@ S v t&EF 11Ƀ $ \1T$L$\$ t$D$,$D${W1$LT :ÉƁ0|W1\$ D$D$GP$TA:1 GiH? )ЅT_T  f &N_p1A$k 1҃e  t&01v$1&D$D1A@s\$D1A[T\$DCfSn G`O\% )‹GdG`TN4A* n1$D$H$C f8889 ЉD$X- f f$ f:8:9 ЍQf$ f:8:9 f$ 9899 9; 9: Љ$ f$ >t$D$ 1ۉD$4\$L$t$P1D$T$XSf:8:9 ‰T$XL$XC 8889FQf f$ f:8:9 ЍQf$ f:8:9 f$ 9899 9; 9: Љ$ $ ^1ɉ\$VL$ L$PT$L$GP$bF\$P\$Tt T$L9t$4t&%fF9899F $D$XZD$Xc\$DS!SfCn!G`| D$D1A@ E11҃t$8T$</$ 1D$8T$ T$8D$x88f $f>8F$>8 ōAf8889$A88L$89$8:$8;$+$f f=T$$$t$ $  ЉD$1D$ $D$GP$VWttGx$t$L$<$D$ ҉鋴$щ >8$88QCc%_\ w`ځ !)ЅOdO`T1҈Gk1 Gh11҉1ҋt$DFT$DB1T$DB 1t%0t$D$ \$D$GP$0fwGh1A&Gk1A=%=R&0f J f9899 :8:91f ʃf9899 Gj1A8[$@2\$Tf$ $ %f$ 9899D$LT$DBfBRun G`O\% )‹GdG`T4,wT WPOXGT!ȁ”D$H|$Hn11҉Gp11AA11҉Gl1A1)xu1% ‰BPf ʃf9899 :8:9}&===t&nʃf9899 :8:9nn\$D1AC\$D1ACnʃf9899 :8:9n_T!n!G`_d1A'g`L$T$t$DL$\$$ OhG`1A41D$D$GP$j,nʃf9899 :8:9nnnnnnʃf9899 :8:9n2n|n(xt&n@AfGft&'Ll$Hl$\\$¿@.w$4FQXy명t+҈D Y1ƍvu(AXF{DYFeAX[SLPF5K.M11҃D$T$V,$D$ 4T$84T$D$u6HF@FFm1`t&S\$t$CH$iCL$ޙ\$[ [Ít&'WVS0|$@$\1ɻ\L$\$^$V 4$4vFp$vTD$TF4v,T$D$D$P\$ D$D$L$賗4FL1D$(1D$$1D$ D$1D$D$H\$\$L$D$D$ D$D$VL҉FHtrtnt$<$G,W01u0[^_Í&1VD$ D$DD$1\$<$T$D$ FT01[^_Ð|$$4D$ (D$FH$讉FL$#4$ 0[^_ÉD$1@1۹ D$ LT$\$L$D$<$|W0FP1'#|$t$$`4D$ PD$@bPÍ&D$u1Ðt&@tÐt&UWVS,D$HT$Ll$@|$DD$T$$||D$1D$$ ST$$$%+{[C CP|$,$CCL[Ct CbPCTC\ D$T%CXD$ 5T$L$D$|$,$D$BD$CL$X‰CPsXCTK\$ƍs D$ 4$BQD$T${[0C D$PC4S$C(T$Xu/C<t$,$eT$$,$T$D$$,[^_]C< $6T CL$ $ 1D$$D$$,[^_]ø|5D$|$$E 1D$$똡#|$t$$5D$  뛍t&S\$T$t7CD$$QCPt$ CL$\$[[Ít&S\$ ClHClu CbP[Ít&Ch1@Ch T$D$CP$ @t7D$C|D$CP$#=t $+6 CbX[$6 'S1\$ D$Ch D$CP$ @tJC|L$D$CP$=t $Q6ClChCbXHCluCbP[Ð$=6f,l$(ʼn\$t$ |$$@x@`<0tL<< <D$ 5D$ED$E$\$t$ |$$l$(,ÍUg„҉El]e@Ed Ec Ef É]hEpEbX뙍vEX]|1uTE\|$$D$E|CEXCEXCETCE\KSC,C CCCjEXClEXCmETCnE\SsKuCpCrCtEpEbXfUg„҉EluEl]e@Ed Ec Ef É]h1D$Eh D$EP$b @E||$D$EP$=t $+6}EppEbXCUdMcuTEfʋM\֍эDEhn]eEl@t8UdMcuTEfʋM\֍эDEh-$6l'D$$l$T$0\$ l$4t$|$pD$(v]u\~x1ۍ?L0|]MD0}ӉM]G~xu"FpFxt4$ tj&\$ 1t$|$l$ÅtUEFdEFcFdVcЙEU븅unFbVeЙEU랅uFfVgЙEU넋UEFfEFgi~xE ?D1|UED1}UEF`EFe$t&T$(D$$l$L$0\$ l$4t$|$pw-u6EE\$ 1t$|$l$fwsFt9r9s~x1ۍ?L0|]MD0}ӉM]G~xuFpFxq4$gt}uFbVeЙEU5uFfVgЙEUUEFfEFgE"Et>UEFdEFc~xE ?D1|UED1}FdVcЙEUUEF`EFeeT$vÍ)‹D$XB4u܋D$ B41É'T$w')‹D$X1J4tB4Ív'1|$ H% 1|$ H% SRDT$$<7?C,$W7D$,C0$i7D$C4${7D$C8$7D$CD$7D$CH$7D$$ [Í \$\$t$sT4$F1-غ!4$ \$1t$ Ít&'ST$D$t1w,@@1St$f1C[ø[Ðt&ST$w1)‹D$X1S8t$Ff1C8[Ð&SL$ T$$\$(tv [ÍR@xuXT$ L$D$$Nr1ȍv'L$$\$\$ t$t$(v\$t$Éȍ)ЍXP8uӉp8L$ \$D$4$q1븍&WV1SӃr<$D$t$0<$‰ щ  ȉFD$1D$I0<$‰ щ  ȉCF D$1D$ 0t$<$‰ щ  1ɉCL$/c‰ щ  ȉC[^_Ðt&UWVS<|$Xl$\$ um 1D$1D$$BCTt$$D$T`T$P118<\`D$d4SPD$hsD$lD$pClCpCD$8$uT$T[C4$SLCD$T1҉[0{ k$CD$`C<T$ C(1D$1D$Cl$A~tP1D$\$$'Bt$<D$P@$;D$PT$8$T$w1<[^_]1D$(01D$$11D$ SD$ClT$T$T\$l$|$L$ T$$jzCLR$7D$ &D$D$i$7D$ 'D$D$8'L\$3(*  1҉'S\$KP$tt& $T$ЋKP$tt& $T$ЋKP t $T$ЋKP t T$ $Ѓ[ÍKP@ )t&' 0<&'$*6v'$([Í&,t$ t$@|$$|$4\$\$8l$(oVD$D@D$<ىT$t$$D$0GvJ t& n&t&uIT$DBt&D$DЉ%  D$D ʉ@\$1t$ |$$l$(,Á   vu.T$D1D$ t$T$EpD$D$0$yo'X뉍D$DЉ%  D$D ʉ@tw6vuD$D@ UhFD$D@t?T$D!ЋUL_T$EP$grT$DB'Z v=T$DBT$D1D$ t$T$EpD$D$0$pjD$D@  3T$D1D$ t$T$ElD$D$0$o o&uT$DB,  f=T$DBT$EP$fu~D$D@D$D@T$D1D$ t$T$ElD$D$0$lD$D@^D$DELztD$EP$e^D$EP$eJ&,|$$|$4\$\$8t$ t$@l$(l$DGD$.EED$<ىl$t$$D$0 t&&t&uCEE&UEЉ%   ʉU\$1t$ |$$l$(,Á * u)T$1ɉL$ L$0l$t$Bl $D$mt&x룍UEЉ%   ʉUtw1uCEEet&EE tg *]T$EU  EEVu]L$EM9 & t&t&zD$U@LtvD$AP$bEEfEEL$1ۉl$\$ t$AlD$D$0$hT$D$BP$:brL$EQL!҉RtT$AP$a6T$T$BP$aUWVS$$TD$,$Y$[1DHD$\ɉL$<D$\PDPD@H%QD$Ѓ $D$,$Ĝ[^_]f$11ۋ$$D$'RT$&1I Ƌ$1҈L$%@D$$ Ӌ$ RˆT$#¸ Ƌ$ @D$"¸ Ӊ ʉT$`T$\ ؉D$dD$'R,T$Lƒ ;4 ;t$& ډ ;4 ; ȉˉ t$% Ӊ  ;4 ; ȉ t$$   ;4 ; ȉˉ t$#   ;4 ; ȉ t$"   ; ȉˋ ; ډՉ  D$L q1% L$D1ۃ%11D$D t$DD$Ld$DT$\D$DRLЉD$H1D$@D$HT$H11틌$D$T$AP$$NjD$HD$1D$BP$1҉ É؃ ؉у u!L$d؋l$`11 D$@|$@ ]L$<1۽\$T$T$T\$L$PD$PT$ $L$D$BP$#$T$4l$0$ȉ$$ȉ$$ȉ$$ȅ$$d$1ɉދ$L$8vt$<g0$D$D$xt$1t$ D$BP$WD$xȉD$xD$|ȉD$|$ȉ$$ȅ$D$|D$8t$xF9~É\$$1N l$݉D$ L$BP$F %)߉Fu  FD$8 L$L&t&z$ $BRfPHZ+@HoHH&$u $Q@@ s $u$C::f$f1탧<$9@-<$XnHt&Pt&$S$ADC$_$Q<@$D(r$$QL@K$$A!$$A$$@$b$@$T$<B$D$$BL$11҉D$1T$ D$$:1dD$(D$$11D$ 1D$D$TL$ T$\$|$t$D$$6D$8,$D$ND$4,$D$莽1<[^_]Ít&11D$(1D$$1dD$ D$D$T\$|$t$L$ T$D$$z6CL$;D$ &D$D$b%\$L$$;D$ 跹1'\$L$$`;D$ 膹\$\$$t$t$ t@D$4$GCD$4$8CL$3t$\$ \$I\$t$Í'S\$L$ !Љ%Kp%Kp%uKp%tLKpCPStCl!‹Cx#Cp [Ácpecp벍cp뉍&cpXt&S\$L$ Kp%Kp%t{Kp%tQKpCPStCl!‹Cx#Cp [Ðcpht&cp뭍&cp냍&cpVt&S\$T$ Kp%Kp%tzKp%tPKpCPStCl!‹Cx#Cp [Ácpit&cp뮍&cp넍&cpWt&UWVSL$d$hkETD$$&$p$tB{1=vv ىɁD$(\$$t$pu$lL1[^_]Ã$l]$tЉ%  $t ʉ@f  h$p)$tL$(A Dt&$ptf$tL$(A 1=vpv t?ډ)ƒ0:@w#$<\$(C$tC=<&&~ i &Z$p$tMpB 3v$tЉ%  1 ʋ$tAL[^_]Ë$p$tL$(AYۉ\$ D$ 1۾$<t$\$ D$T$GP$S$<ȉ$<$@ȉ$@$D$@ȉ$D$Hȅɉ$H4l$ L$,1҉T$$<ʉL$$t&FnD$$,1l$$,D$ L$GP$T$$$,ȉ$,$0ȉ$0$4ȉ$4$8ȉ$8^\$F T$D$1D$ GP$3F\$$\$=%FD$ ED$1D$GP$nFD$tD\$( ȍ)Ћ8@8@Z $@%D$ $@D$ D$1D$GP$=D$(huT$(  bOp%Op@GPWtwl_pGx!! L$(IɉL$ E$pt$tL$(A\$(C$tC| ht& x t&j$t1$pD$ $`T$L$$D$-0\$(C $tC$p$tC$p$tBC$p {$tD C$pv$tBCr$p B0$t BHgpgp$@1҉T$%D$ $@D$ D$GP$\$(Ca$t‰ep%mMp@EPElUt}p!‹Ex! D$$$puElMp#IA%? @$tAB8.T$L$,L$$T$f\$(  vFt&$p0$t@\wEDf T&j$p#$tC@tP|d%$pElMp#%? $p$tC$p$tAB4T$L$,L$$T$cH\$( x$tB0G$t7$tD %$tB$tB$tt   1$tD$ $p$`\$D$$D$($[4t&6q$p$t]xAJ&$p$tB $pl$tEtC$p$tA$t$p$`D$1D$ T$ $D$*q$puM$tAKep$t‰OMpJ$t$tep%XMp%.Mp%Mp$tEtep%Mp%Mp%aMp]PUt}lExup!! !Mp%Mp@epepep$pW$t!Љ%FMpA$t1$pD$ L$\$D$$`$|'$p $tC$p$t ȅЉ\$p3$tCZ$pElMp#]|8$pElMpMx#]t $pw$tElC$p$$tSepepepepf>$tExMpep%$p$tE|C$puW$tA$pm$tC$t@$t,$t1һ;%D$T$ D$EP$臶\$D$ T$ED$EP$M$t$tE|$tUWVS|$hl$~2ۍ\$ D$wkT$   Љt\Op%tOOp@GPwl_pWtGx!! |[^_]Ãgp뢍t&gp1Ҹl$0\$dT$4D$T$4D$0\$T$ D$GP$D$dȉD$dD$hȉD$hD$lȉD$lD$pȉD$pD$h1މD$$T$wD$,T$(D$,nHD$1D$ D$Tl$D$GP$D$TȉD$TD$XȉD$XD$\ȉD$\D$`ȉD$`D$,]D$X_D$$D$,t$T^9~É\$T$(F T$D$1D$ GP$vF \$(%)\$,Fu/T$ F)8@u &L$$FȉD$HȉD$DFȉD$LF ȉD$P1D$ D$DT$l$D$GP$D$ hD$h D$hȉD$HD$dȉD$DD$lȉD$LD$pȉD$PT$4D$D$0T$ D$D$DD$GP$rT$  T$ jD$h D$h뇐T$tD$BxD$ B|É'T$tD$BtÃD$$t$t$(\$X<t$ D$D$C$<t1t \$t$Ít&C(\$t$ÐCX\$t$ÐVSt$$$kt}ù1҉L$T$$>C $胥D$ s [C CC 3C\Ch$Ds [8C(C,C0CD [^á\$1ۉt$$<D$ 葟 T$D$,$D$h농`IjSx҉CpZD$C|$D$Et&CtF/^sXVC\F؉BCXD$1D$ FD$C$ VBD$BR D$1D$ =T$D$D$C$ا11 ',T$@\$\$4t$ L$8l$(t$<|$$ҋl$0D$D{u @t0t$<|$$\$4t$ l$0\$D$Dl$(T$@L$8,9Jt"Wh@\$1t$ |$$l$(,Í_dSGhtۋC1؉BGdT$t$ D$G$SBD$BR L$ D$T$=T$D$G$裦t&',D$4\$\$8|$$|$D$D$0$T,Ít&',1D$ D$811҉L$T$D$D$4D$$D$ D$H>D$D$0$,Ít&',1D$D$81҉T$ D$1D$D$4D$#D$ D$Q>D$D$0$,Ít&',1D$ 1Z>D$D$8L$D$1D$D$4D$!D$ D$D$0$4,Ít&',1D$ 1D$D$8L$ T$D$1D$D$4D$c>D$D$0$,Ð,1D$ 1PD$D$8L$ T$D$1D$D$4D$l>D$D$0$t,Ð,1D$ 1(D$D$8LL$ T$D$1D$D$4D$t>D$D$0$,ÐT$ Dt2~Ht&1t&Ã4@t@!t u ,1D$  D$D$8L$ T$D$1D$D$4D$|>D$D$0$a,Ð,1D$ 1 eD$D$8L$ T$D$1D$D$4D$>D$D$0$,Ð D$h@\tHL@H t L$$҃ Ã,t$ |$$|$4l$(l$8\$$xّx1ۉ\$^D$4$襍D$04$FHD$DFLD$@FPD$HFdD$LFpʖ>vF $D$<  v,` F>~F$D$Hn F8  hD$LhD$HpD$Lp1D$t$$ l\$FTD$0VX$膕D$0t$$Ɠ1\$t$ |$$l$(,á$>D$ D$D$yf\$\$$t$t$ tKCd11҉pCppSXCTT$$AC4$D$"t$\$ \$>\$t$f<\$,\$PD$Dl$8l$@t$0|$4ۋpuD$T@NPD$H w$>t{]11҃\$L1D$T$\$ \$TS>L$ t$D$T$\$,$蝴'\$,1t$0|$4l$8<Ë]f11҃L\$L>D$>T$L$ \$D$|$,$3롋FHNL$tL$$Ґ&x?Cd$1ɺuC`1ɺtC`1ɋD$TH0\$T?1 A\Ӄ Ad@8$?Dd$%T$TB `Kt{?Dd$EL$TY191 ?T$TL\B ;T$T?D$Cd$}C\tFHNL t L$$ҍ?T`t&'S\$Ct@Ctt 1[Ðt&C\t*CHC`KL tL$$ҍv'Ct1[f D$h@htHL@H t L$$҃ ËT$ D$Htt Ҹ u1Ë@ S\$t.T$$6$1[Ít&'\$\$ t$t$$t\$t$f1\$D$$! D0' 1\$4$D$ L$\$1t$ S\$tU$&D$$ގ$$L\$[?[Ív'<|$4l$8l$D\$,t$0$ 1T$D$<$Ն D$( D$$1D$ D$Pt$|$l$D$1D$D$LD$ D$ D$H$,$tbD$@G G G,/BB BB$  z؋t$0\$,|$4l$8<á?l$L$$4$<$1뼡?1ۉl$L$$貉랡?l$\$$薉뺍t&D$$|$(t$T$ \$t$,Xt\$t$Ív1t$D$ D$$t$,:?t$(t$D$$\$D$ 鱘,L$8D$4\$\$Dt$ |$$l$(pwt5?L$ l$D$D$0$\$1t$ |$$l$(,Ë|$@t$w<t&1D t&뾃f\D C뛃 uË;kF05@ _5  ]~L/NL$@FF0F$Cu F% uF K 0KCы1!F F Et ª+V D$$FF?D$D$$ϖj1FLFPFTFXF؃FL7؃FL( FL FLFXA Ӄ0^XFLFP0VTf\F`FL؃FLFPFL ЉFPFTA Ӄ^TFLFPDF`F\FL]؃FLNF,C5ɉV tD$$b ^\xf0f\N0%mHAD$ "D$X?D$$w?"HA!X?L$ T$D$$g?t&'U1WVS< $P D$0'}E% E1ҾT$ T$D$ T$t$D$D$@$4$ ȉ$ $$ $ ʋ$( ȉ$( $, ȅۉ$$ $, yn`uv$$ EE1T$DD$ D$@T$D$$i$$ qD$0|$0 < [^_]ÍT$P1$ T$tsùVAD$ L$D$X$迉\$0t$4|$8<ËD$ ȉD$$ȉGD$(ȉGD$,ȉG 1\$0t$4|$8<Ðt&D$(ȉD$$ȉGD$ ȉGD$,ȉG 1\$0t$4|$8<Ít&'tsÉD$ VAD$D$X$迈\$0t$4|$8<ËD$ ȉD$$ȉGD$(ȉGD$,ȉG 1\$0t$4|$8<Ðt&D$(ȉD$$ȉGD$ ȉGD$,ȉG 1\$0t$4|$8<Ít&'S\$tUT$6PD$X${X$P$\u\$[Ou[Ív'<|$4l$8l$D\$,t$0$hx81øht$ D$<$s@nHL$T$$5v1D$G$Tw0 "D$(+ D$$1D$ D$Tt$ |$L$D$1D$D$Pl$D$D$L$,$賻tTD$@/TPXD$HBB B$01 GzB@؋t$0\$,|$4l$8<øAD$l$$v4$<$1s뼸rA1ۉD$l$$v랡Al$T$$v뺐D$$|$(t$T$ \$t$,Xt\$t$Ív1t$D$ PD$$އ:?t$,t$D$(D$$X\$D$ 顅$$$$$$$$xuEEGD$($ut<tTt~\$($s$1$$$ĬNG$EE븍G$< tT<"(EMfG$<wWu5%W(EUVNEE;tVED((EG$<tNEE듍v ,}&(&ZKGLEEAKGxEE'&K_88&Kt&Eu((K\wlEu0@GL$(% =QXHЁ%T\/Nht$(CvL3ST$(rP"BQBQ5t$(F(D$F,$N 1҉ȉ%$G141L$(AQs%D$(PX% =uT$(CBX t$(^41L$VT$(D\%} ۸,xԸ͸aƸA뿸f붸G믍&t$(FLF8FHL$(A(D$A,$贾D$(x8‰\$J@@HȉD$1D$ D$|D$B,$q{D$|ȉD$|$$ȉ$$D$@$$LL$(QHA89t$(FLF@*v'UWVS1ۃ\D$|D$$FT$|z8tL$ $~D\[^_]Ít&B@1JHt$$\$L$ D$HL$,L$$T$ D$L$ L$|T$A,$zzT$HD$LȋL$PT$HɉD$LD$TȁL$PD$T&D$|l$xP@1D$4щL$0Ft$D$8|$T$4 @ D$ D$8D$0T$T$|D$B,$st$tT$0L$4D$T$T$|L$ L$8L$B,$yD$DȉƋ|$8?L$<ɋT$@9D$DvT$@T$t^FD$L$<\$$|$8$q1L$@D$ D$tT$|\$L$)D$݋B,$~L$8\$xD$t$\$pD$,1ɋT$tL$ L$|\$D$T$A,$}v'D$T1T$xL$H%  ‹D$ T$TT$$L$ L$HD$T$T$|B,$RrD$TL$|t$D$ D$, D$A,$,rD$|HQ@D$H@L$|IQA8L$|QPL$|AQ%A(D$A,$L$|1\$D$H1C<pd Ct[pC8D$TD$1D$D$Pt$(L$$T$ D$D$ 7D$D$L\$|$$Ժtc<$t`D$@;s4BC,B B@B$p ZS00[^_É|$HD$1ۉ$>ٸlH|$ธH|$Րt&D$$|$(t$T$ \$t$,Xt\$t$Ív1ɉt$L$ C0D$$aO:?t$,t$T$(D$$C,\$D$ 'M&U1WVSF$F^41l$$\$ D$ $m=~$n4^F01ҹT$ T$4$FL$D$T$D$0E,$Pq$Fȉ$F$F$Fȉ$F:D$81ۍ$FD$,\$(&څ\$(G@F4@8)F0;F(F0 )D$$FF0$FT$D$1D$ E,$p$F\$,ȉ$F$Fȉ$FWF4H8K8)Ӆ-f\$D$,WD$T$1҉T$ E,$o\$(G@&'1D$ 1V0D$T$E,$iF4@8t&F0;F(F0 \$(1T$4D$ D$0T$D$E,$4i} E EE$@E$D$ $8D$$|$$vĜF[^_]ËF$F0;Ht$ED$E,$'JT$ $8ĜF[^_]%؃)D$(T$8T$D$(D$F$=E4D$E,$膱GE4D$E,$蟱E$)vUWVSLD$lt$hX4ST$$:L$l t:T$lD$lz@4D$4t$ZtRt‹u(&T$$7L[^_]Í&L$lD$\$@1I,D$ \$L$B,$mD$@ȉD$@D$DȉD$DD$@yD$l@,D$$T$d1݉D$T$ r;q QQ1D$,T$,t$(D$(T$T$4D$B,$gT$%%0E؋M ȅ҉EL$lq,E T$,D$(L$4t$T$ T$8D$T$A,$lD$8ȉD$8D$<ȅD$<D$l$8]9~\$D$ 1MT$4|$ D$)߉L$B,$;qL$l\$ A4Q,p8;Q rqL$lD$ T$41I,D$L$B,$e t&qL$lA @\$ Eq,D$@1ۋT$4\$ @D$ D$@D$$D$B,$xeD$lT$4J ȅB Bu2B$@B$B4D$B,$蘮D$4@$hB4D$B,$FQT$T$4D$ 1D$B,$dL$lBt&',|$$|$@D$4\$\$8t$ l$(puD$D@= v= w\$Ћt$ |$$l$(,Í=vݸD$r1aD$r?D$rD$r n,$5Htrw:kfwzuT$DFBf,$x31,Gt&wf|uم&u΋D$D@뻅uT$DB뤃ut&uD$D@x$,n,,`XD$D@BVT$$4)ʼn؍L50l$q )=`dut&D$DV@D$$>21u.D$DV @uUT$DF(BT$DFF  F$@F$cF4D$F,$QF$ET$DF(7=w=POD$DV(@4F8HT$Dكʍ)‰ %0|2<Pu4I\$ D$D$F,$BudD$D@lT$DV!ЅF FF4D$F,$1\l$kD$$ T$0$SHKVK[C` ,$#UD$1 Ð& D$D$D$@0$膬1 à D$D$D$D$D$@0$讬1 Ð&\$\$$t$s0$Y1D$CD$D$ $w4$/\$1t$Ð \$\$t$t$$!Vڋ\$D$D$t$ Kt&' \$\$t$t$$Uڋ\$D$D$t$ t&' \$\$t$t$$Uڋ\$D$D$t$ t&',|$$|$4\$l$(l$0t$ w_tG($U|$,$D$X\$t$,$I\$t$$$Et$$tK1D$4$D$CD$G(t$D$ ,$D$聹G01\$t$ |$$l$(,øpSD$t$,$ Ѝ D$T$@0u Ðt&9vD$01㍶ D$L$P0u Ðt&9 vD$D$D$81ۍt&VS\$$s0$W1ɉL$CD$D$ $tË$sC9w4$1[^ÐD$T$ @0tv ÍT$D$#vD$T$ L$@0tvfL$ T$D$O S\$$$@V1D$CD$D$ $C0$v1[ ,|$$|$4t$ l$(l$0\$_tG($ lR|$,$D$UGD$\$$c$\$$ytX1ɉL$$e1҉D$FD$G(T$D$ ,$D$tG01ҋ\$Ћt$ |$$l$(,É\$pS\$,$ΐST$ \$L$w$S1v'[É1[É1[É1[É1[É1[É1[fD$T$ Í&' T$L$t"Q Q1 tD$$1 ÍÍv' $t! @t$tMi‰Ѓ Ðt& SD$$Vx Ít&S$Stt<1ېt&tt%T$D$$(t0u$ ?[Ív'\$\$ |$|$$t$FD$ <$D$TD$CD$ *T\$<$D$&\$t$|$ÍC$WYC$C(t$pC$4$b1[^øpD$4$YfST$$D$ v 7v+[͉D$$D$ [馀ЃD$T$C$f[VS\$ sF D$$PTD$[F$JD$HF$JD$5F$$nTD$"F($JD$C$TD$$TD$FT$JD$Fl~>4$9$Hn$:n D$ [^&[^Ív'UWVS]|$$U;PD$D$1D$ =JT$D$${@}E(D$ U\$\$D$$L$$OrUD$T$ D$$D$$nO0D$ UD$D$$]L$$,OUD$T$ D$$D$$ND$ UD$D$$L$$NjUD$T$ D$$D$$fN(D$$U9ND$$UN1D$|$$=\$D$$=1ɺT$L$$=D$D$$=}tx|ExD$D$$=E}kD$D$$E(}tx|ExD$t$$1E}xD$D$$s1E}*D$D$$E1E}|D$D$$1E}D$|$$0E}wD\$D$$0Ĝ1[^_]fD$L$$/D$L$$/Ĝ1[^_]þD$t$$/kt&D$D$${/D$D$$[/D$D$$;/Ĝ[^_]Á!'$$$$$wL$$F=w~1_D$$T?1D$$Uq?퉃tJL$$X$$$$ļ- F$FD$ 1T$D$FtD$1D$D$ F@4$D$UD$n*D$D$1D$ *JT$D$$&@oD$ U\$\$,D$$L$$T>BUD$T$ D$$CD$$>D$ UD$D$$L$$=UD$T$ D$$D$$=|D$ UD$D$$}L$$L=:UD$T$ D$$;D$$ =D$$U<D$D$$,_D$$U<t3,$;‰G$t"@ $D$9G(tx|GxD$L$$+G=D$D$$+GD$ D$$}+G|D$D$$O+GwlD$\$$%+Gw&D$ D$$*1D$ D$$*1D$L$$)뒽D$l$$)ND$ D$$)D$D$$)D$D$$)v UWVS!'$w\$$ 1F$ L$ T$D$FtD$1D$D$ F@4$D$ D$i1_D$$T91D$$U9퉃D$1D$ VL$T$D$$@C1D$VD$D$l$ L$$诿@ Uo\$,L$ T$D$$D$$8D$ UD$D$$̾D$$8UL$ T$D$$芾D$$Y8=D$ UD$D$$HD$$8UL$ T$D$$D$$7D$ UD$D$$ĽD$$7wT$$Up7D$$UU7D$$U:7D$D$$C&_D$$U6t3,$36‰G$t"@ $D$Q3G(D$D$$%D$D$$%tx|Gx2D$l$$%GD$L$$%G=D$D$$%G|D$D$$Z%GD$D$$,%GwjD$t$$%1Ĭ[^_]ËJt$$D$Ĭ[^_]ûD$\$$#D$\$$#1뛽D$l$$#ND$D$$#D$D$$#D$D$$q#v($$$$1퉴$wD$$_l$$T31ɉL$$U3҉tu;JD$$$Ћ$$$Ĭø1ɉD$*JD$l$L$ T$$ʹ@oD$ UD$\$D$$)D$$2D$ UL$D$$T$$2MD$ UD$D$$襸D$$t2 D$ UL$D$$cT$$22D$ UD$D$$!D$$1D$ UL$D$$߷T$$1ED$$U1D$D$$ _D$$UL1t3,$0‰G$t"@ $D$-G(tx|GxD$D$$} GD$D$$O G@ D$\$$! G|D$D$$GD$D$$GwoD$ D$$G$vD$D$GD$? 1@!Vt$G$r1D$ D$$l돉D$D$$UKD$D$$; D$L$$!D$l$$sD$D$$+GTZl$D$G$諿1t&U#WVS$uT$$P1]D$$UK.==JD$D$D$1D$ |$$苶@5U}E(\$ \$L$T$$D$$-D$ UD$D$$诳D$$~-UL$T$D$ $mD$$<-_D$ UD$D$$+D$$,UL$T$D$ $D$$,D$ UD$D$$觲D$$v,D$1$UL,|$$U6,L$\$$T$D$$1D$D$$D$D$$}tx|Ex)D$D$$$E}D$D$$E}D$\$$E}|?D$D$$E}D$D$$lE}D$D$$>11ɉl$U K|$\$L$ T$4$D$1D$4$D$ D$ KD$1D$ UD$Ĝ1[^_]ÁĜ[^_]ÉD$D$$Wt&D$D$$ D$D$$D$L$${nD$|$$[ D$D$$;JD$$Ĝ[^_] ($$$$1퉴$wD$$v_l$$Ts(1ɉL$$U[(҉tu;JD$$F$Ћ$$$Ĭ1D$ *Jl$L$T$D$$j@oD$ UD$\$D$$ɭD$$'UL$ T$D$$臭D$$V'MD$ UD$D$$ED$$' UL$ T$D$$D$$&D$ UD$D$$D$$&UL$ T$D$$D$$N&ED$$U+&D$D$$:_D$$U%t3,$*%‰G$t"@ $D$H"G(tx|GxD$D$$GD$\$$G@D$ D$$G|D$D$$GD$D$$eGwo D$l$$;G$vD$D$GD$1@!VL$G$1 D$t$$ 돉D$D$$KD$D$$D$ D$$D$L$$sD$l$$+GTZ\$D$G$K1S`[\$ L$T$CP$軥,@]L$T$$蛥C,C8CD[Ít&',D$0\$|$$|$4l$(l$8t$ p$D$1D$$豢1D$CL$@D$0,CH,,,C|$荫CD$$VK[C ^D$(OD$D$@T$t$ L$l$|$$*v'T$($\$,1t$0|$4l$8<ÁDtu8tȐ&t&8K&$ GH,$ZT$TBhK ¸Ht_yHtLH*l*zZD$(OT$ D$GH@$d1fT$TB rt&48K&L$T1ҋу u @8$0[Mi4v:<t&,t&=$=Z(OD$ l$t$GH@$R11ҋL$TQLyLvLvlt&j\K&$l.L$TglߙQ)WNTۍvD$T@t& fZKGxT$TBSKjL$TȉW&H_`ULDt&|Ht&=t&T$@ 11҃L$L(OD$T$L$ L$TQt$ 1t$D$D$@T$\$$L$TȉK}L$T1ҋу h@8$-NF $,Ë$tT$,$ЅۋT$T BKqGHPnt|Lt&*KT$Tȉp$d,KD$TWl@1[ VS\$$s0$L1҉T$CD$D$ $-$>F$x>4$P{1[^Ð&,t$ t$4|$$l$(l$0\$^$~tF($t$,$D$FD$\$$荂1D$$D$1D$F(D$ D$,$D$>u7\$t$ |$$l$(,Ë,$D$gD$θ$D$t\$D$F(L$D$ ,$D$=Gt1~0넃,|$(|$4t$$t$0\$ _tG($|$4$D$GD$\$$w1ɉL$$ف1҉T$D$G(D$ D$4$D$=tG01ҋ\$ Ћt$$|$(,ÐT$D$ L$u A=t=t =t1Åu1AÍ&T$D$$\$t$t$ ҋHu Ftt($1t$Åt-A1$t$Ðt&t,A 1$t$ËAF1$t$ÐA F1$t$Í&T$D$$\$t$t$ ҋHu Ftt($1t$Åt-A1$t$Ðt&t,A$1$t$ËAF1$t$ÐA$F1$t$Í&D$P1|$ tËÐ&SD$X0tIL$uA1t: T$$5$11[ø[Í&'D$$t$t$,\$X0tD$(t\$t$Ëu剳1\$D$$3 '1 \$`5 D$ \$4$1룍WVS\$$t$ {0$71D$CD$$~$G84$D$O|G<4$D$@|G@4$D$1|GD4$D$|Gx4$D$s|4$D$a|4$D$O|$a<$u1[^_UWVS:?t$,t$L$(D$$C(\$D$ t&T$0D$$t$L$4\$t$ ҋXu AD$(-0(wS$,jIfCЃ Ѓ C C D$ iD$C44$D$\$1t$fuA݅uCAʅuƋCA@CuD$C($CC ciC T$ L$D$C44$D$l7&UWVSL $` wtit_G$1ҹ$@ L$T$ D$\$D$0G(T$4$*$@ ȉ$@ $D ȉ$D $@ x 1L [^_]1ݍT$8D$(1T$$D$,mGG$T$$8 G$$8 T$D$1D$ G($蕧$8 t$$D$,ȉ$8 $< ȉ$< EƁuHD$,t$(uU@cG$`t&11ɉ\$ W$L$T$G($č^T$$\$ET$D$1D$ G($D$$\$$薞yiD$D$G($D$(uQ$@ T$4%D$ $@ D$0T$D$G($HD$G($c\D$(T$8T$D$$돉'UWVSp1ɉD$ D$2L$ T$l$t$\$D$<$T$(D$ D$1D$$@T$(VKD$B$F]T$(1@rB!'D$$#D$(Xl$$I1ɉL$$J҉`X D$ D$D$1D$ =pl$L$T$D$$[U@T$(=pD$B$\\@1T$(FHfB x1D$1D$<$\aG l$ t$<$D$D$O)1ɻL$$\$D$ _D$<$.t=Xp t&Y\$t$<$t1TD$1D$@D$D$1l$D$ <$)~ D$(X8$=$Y@Ɣ4$zCPD$ 1D$CT4$D$dSpUu D$FVD$T$ $wD$1Cpu L$D$T$FV$D$ MD$xT$D$A1C; KD$<$> D$D$P$><[^_]É, vT$(JD$B$X>붸KD$$E>븋G4@G4D$$-0C$KW1끋T$PT$PB\$D$D$=D$P@\pt$$=1CTML$$D$=t&VS$t$0\$44$\$g@D$#D$^1D$$D$#t.<tR@xD$\$F$/=1҃$[^Ðt&D$ t$$D$$1[^ÍD$D$D$$o1҅uD$ D$t$$D$̄1닸4N\$D$F$rT$41r0[^_]ËT$4D$\SD$D$0$Q,ҐD$T$ @0tv ÍT$D$vD$T$ L$@0tvfL$ T$D$ S\$$$x1D$CD$D$ $C0$1[ ,l$(l$4t$ |$$|$0\$]tE($ tl$<$D$\xED$\$$C1ɉL$$e${1҉t$D$E(T$D$ E<$D$tE01ҋ\$Ћt$ |$$l$(,ÐL$ T$D$u @!v$~vD$@ D$ ܸո1ʍv'S\$C0$$5w1[Í&'S\$C0$$w1[Í&'1\$t$&t$\$t$,$t1[^_]ËE4@E4D$$-ۍ T$D$tNw.tvL&D$D$ : r'v't?& øŐt&빍BƒT$D$A$kɸf<|$4|$@\$,t$0l$8D$<$(t$<(D$$D$ D$(D$l$<$@tpD$$D$C09D$bt$(SfDLT$ fT$ ft4MT$ L$t$<$\$,Ћt$0|$4l$8wtZvvN0& r#vXtp&' øD$D$ 1T$D$ BƒT$D$A$P랸렍&WVSt$ t4$$@@tc(t*11 CD$4$9(w4$ G$4$<$&[^_øpD$4$1䐍t&T$ D$ D$D$D$$$貼Í&'SD$ X C D$$!D$C$JD$C$JD$ֻC($JD$ûCT$JD$谻Sl~9$$#6$6 D$ [飷v[Ít&'UWVS @8$ $t&,t&4t&<t&t&t&t&,t&u~==D$ ZD$(OD$FH@$11ҋL$TQT<D<D$@11҃L$L>D$D$@|$ (OT$L$l$|$$* vuKL$T<<!11퉆11svtd|XlfEp$v%T$@ 11҃L$L1(OD$T$L$ L$TQ|$ t$D$D$@T$\$$T$T1ɉL$TL$TArKAD$TVl@VK3$L$TflߙQ.L$@1ҋL$@1ҋKqFxL$TAK} $L$TflQK8FH4$L$TAzrD$T'@\T$VL$TA *L$TFpT$TD$$#flK<cA$==W=Z(OD$ L$T$FH@$*t&T$TFxbT$TD$FH4$jET$TD$ $Lfl#<oA ƒ t21xV|A ƒu1111묿1ۉr 71111ۉ'D$ t$\$hsL4$@Cpt"CHKl@ tL$$҉t$ \$t$t&\$\$ t$sL4$Ct@Ctt4$貅\$1t$Ít&Cpt*CHKl@ tL$$Ґ&Ct뭐,t$ |$$|$4l$(l$8\$$TIT1T$^D$4$D$04$FHVTvF $.D$$$@Ɣ4$#CPD$ 1D$CT4$D$mSpUu D$FVD$T$ $D$tCpu L$D$T$FV$D$ MD$qT$D$߃C$=13\$<$&D$D$P$ˀ<[^_]É, HvJD$$蟀뽡)\$1҉D$G L$T$ <$D$D$!_WD$$K1CrCTML$$D$ Ppt$$5T$PB\$D$D$D$P@\ \$\$$D$ t$w ÉD$4$ 8 u\$t$ÍX \$t$D$ ֔S\$ $0D$qD$}D$$܁t$|$@t @$$Є1[øpD$$~WVS \$0D$4T$8{D$T$$qD$1D$4$m1D$FL$5q,^H,^F|4$vVKvF 7 $臵D$ ? T$v,FVKFD$D$D$@|$ (OT$L$l$|$$:(KQ $3L$TflQt&T$($k\$,1t$0|$4l$8<Á4t$tȁ,f:KgD$TVl@롐3h Kt&jL$T<<K11퉆11&$L$TA D$T'@T$TD$ $fl Kt&L$T1ҋу u @8$[,T4v;<t&*Dt&t |vzT$@ 11҃L$L1(OD$T$L$ L$TQ|$ t$D$D$@T$\$$覐T$Tx1ɉL$T`vL$@1ҋRL$@1ҋKFxL$TA==D$ ZD$(OD$FH@$#z11ҋL$TQ $[Ë$tT$,$ЅۋT$T BUKNL$T1ҋу 9@8$L$TA<PA[=J=D=4Z(OD$ L$T$FH@$x T$TFxnT$TD$$5flLL$TFp>A ƒ tF1Y<F|A ƒu1111똿1ۉ l1111ۉ&D$ t$\$hsL4$ hCpt"CHKl@ tL$$҉t$ \$t$et&\$\$ t$sL4$gCt@Ctt4$e\$1t$Ít&Cpt*CHKl@ tL$$Ґ&Ct뭐,t$ |$$|$4l$(l$8\$$)g1T$^D$4$bD$04$FH6lTvFA $D$U$YD$@PtP1 D$@F(;ps2l$@tCFD$($ĢXD$@;pr$%Y5I4 YL$@$-D$nX\$@CF F11J$ GcT\$@9{9~ 9~zFVl$@lj\^T$@$B%D$D$Wt%D$$SWgI D$t$@$hD${Wn6l$} 'E11ɉt$l$@$eD$-WM|$@C1D$$\$( \$@E(9kvu\$$Ƌ!֋T$(! tЍGD$$oVt۸tu|D$$vVt$zE(V\$@9kw$ Rt$@D$L$;Ns-D$;H r$;HwP@\$t$@É$ ^R#I D$Tl$@E$D$UD$h ;h#‹@Rt$@ʼn%=D$$UD$@pS1T$1҉\$ L$@G;ys\$Ƌ !΋L$ !É tэT$@$oD$=Ut۸tu|D$$vUt$zG UL$@;yr$ #Q\$E;kw ;k rCSt$@ʼn2$ PI, t$@$D$T} 9}EUL$@lj4 u3G9};} EU\$@lj4t̉|$$$TD$@@tI11 L$@C9Yv7tT$@C$ĢD$SL$@9YwG$ O9}\$ O$T$ O Dt   D$ |$7v'ST$D$u[Í9Bv1t׉$j1ŃT$ D$$L$(u Ít&9BvD$ q T$D$ $1Ít&'T$L$ BD$ L$D$f,\$Ӊt$ 1|$$l$(z<zz,j1ɉl$|$L$ D$F$݋@D$ D$1D$F$襀CD$ D$1D$F${C<\$t$ |$$l$(,1 D$ T$|$D$F$GC D$ G D$1D$F$ED$GD$1D$  D$F$v\$\$$t$t$(C u=KBABAKC D$T$ $OC CD$(Ct$ \$t$D$$4t&\$\$$t$t$(C uPKBABASCffB fBC $ D$T$MOC CD$(Ct$ \$t$D$$顼WVS|$ W0G,T$$TT$$lG$!G D$G$SG$qG $SM t)1$Ë$4M8u1 uv؋X$LuF u։<$L1[^_Ðt&D$$|$(t$T$ \$t$,Xt\$t$Ív1t$D$ C D$$at$,t$D$(D$$C\$D$ ^&,\$ t$$t$0|$(|$8I4$yRD$F \$D$<$D$1D$D$4\$,D$D$D$;|$t\$ t$$|$(,ÍD$D$L$<$@tύD$D$D$T$ <$D$b1믍&'|t$p$$\$l$|$t$l$xhu GED$($>NDvb\t&JPwD%‰C2 C CT@ChCl8Cp{1SP1CH0CLCC\CXCdC`L$T$$ $hX@@ @ @$ Ct1^0,[^_]Ë,$D$gD$1ڋ\$,$D$0뼋t$,$D$0랋D\$,$D$0뀋,$D$NkD$0_v$$$$$5$tKD$ ϪD$ED$$21$$$$ĜÍt&$0Ehωx*lL$\$ D$ED$$21눍At|]l \$4\$4L$41Q+[T$4L$t<$F\$4 E @2D$,‰D$0D$,!;D$0wa=ZUl-ЉD$4cPL$ED$$11Ul@T$4/T$0t$,\$L$ T$t$|$ED$$811:t$4T$tBF V\$xD$41X P|$ @t$D$$`OL$4$ 3D$4Ήt$88xX t$8L$\X4$uQD$4pMlL$4D$L$\$ t$ED$$1013T$4t$4T$\% J=NVT$`D$41P \$t$$fOT$4J\$t$ ȉD$ $CNL$4Y 0$1ɉt$t$4 vL$ D$t$$YD$4L$4P @0C Q tED$8t=t86\$ED$$/Juȋt$4^1t$\$$iN\$t$ @D$ $JM$T$4X-B trE u` 1ɍFD$L$$NxcT$ED$$V.E IF -E udF L$<1L$(|$(D$8T$4D$<% =uL$@L$4D$<ȋQ\$HˁT$DID$$D$D$ D$D$G1[VSt$ t:'eL$4$D$D$ 1D$[ uӸyD$d4$T$ D$1[^Ð&UWVSt$4l$0|$8~E1ۍ&D$$a1ҹ\$CL$ T$,$D$eD$h9uĸyD$ D$d,$D$A1[^_]Í&D$D$ D$dD$D$ $1Í&VSt$ u =[ t6t$$uԭD$t$$1[^$t(‰0D$$BBB [^á$D$ +D$D$_1͍t&'WVS D$8|$0ۋ0u[ t$$u[tGCD$CD$<$D$D$ 1D$eD$[uŸydD$ t$<$D$ 1[^_ût$\$ <$L$T$R [^_ÍUWVS\$8$p$/D$8D$ &GrG D$D$D$8$N|$8tʍL$8! t€uD$ ҃)D$8D$$8L$$1s$T $@$8$/D$$$@D$(D$$ۋh0u([ t$$usut&OvDl$$uT$(N9| ;VoFL$T$<$D$`D$ D$D$s$$8$x/\1[^_]Í$81$:.<$D$ӬD$ D$D$3l$$ D$$$d$8$/t$l$ t$\$<$뷹,t$ \$L$<$1҉T$$댹l$L$ T$D$<$`D$ D$D$<$]8D$$_T$<$D$V t&'UWVSti&[ tS3 uD$ԭD$$ ֯!|$ t$\$$.$tS- CCC t1ɸ ЉHHPuC1[^_]á$D$ +D$D$JHt&UWVS\tf t&[ tS3 uD$ԭD$$֯!|$ t$\$$.$- CCC t1ɸ ЉHHPuC2}v+"(;S[ D$$ 1$tu $t$( D$$tl$ |$D$$p$#LD$^$t$D$@ t&|t$(1 1ɻ(tЃT((9~A9L$uӸ 1҉$T$PD$1D$ 1D$C$Pt$$@U1 C9\$(tȉʃD(tӸ$X$$XD$T$ $VX$ 1󫸇-FnD$,$F !0D$,$cFF $F$ 1ɉt$ |$L$4$wuzF҉VtFBC9\$5u)!Bru~8t&$DnF$F $4$D$l$$a,$9G$b6$$$<1'(t T$$($C9\$u$du ؋Xvu1\[^_]á$D$ +D$D$n|*t$\$$D$ B뛐1D$$k tT$$1øD$ D$L$$.'S1Ƀ( \$0D$$L$$T$D$ \$$AyD$ D$d$D$^(1[Í&D$ D$D$ 1D$eD$D$$$Ít&'\$\$(t$|$|$ D$<$D$BƸtm 11L$T$D$ C$ST$ T$$4$T$D$詂$_YyD$ D$dD$<$l1\$t$|$Ív',\$ \$8t$$|$(|$0$Xt;<$D$D$ D$D$\$ t$$|$(,ËL$ T$<$D$dD$ft$t$(\$|$|$ D$<$D$øtbD$F<$D$tV$dD$ e$ XF$XyD$ t$\$<$'1\$t$|$Ë$Wߍt&VS\$(t$ $ht;$W4$D$4D$ D$dD$1[^ù\$ L$T$4$VS\$(t$ $gt;$+W4$D$4D$ D$dD$21[^øED$ D$D$4$VS\$(t$ CD$$jt;$Vd4\$ L$D$T$4$1[^øD$ D$D$4$Љ'VS\$(t$ CD$$Bht;$V4$D$4D$ D$dD$1[^ù\$ L$T$4$Љ'VS\$(t$ CD$$qt;$U4$D$4D$ D$dD$1[^ø_D$ D$D$4$`Љ'VS\$(t$ CD$CD$$^t;$Td4\$ L$D$T$4$1[^øxD$ D$D$4$fVS\$(t$ CD$CD$${bt;$]T4$D$4D$ D$dD$d1[^ù\$ L$T$4$9f,1ɉ|$$|$8\$ t$ 1L$l$(l$0t$ \$G $Uw1҉T$ ø D$1D$G$0\$ t$D$$:htId$wS|$t$,$D$4D$ 1\$t$ |$$l$(,øD$ D$D$,$Jvt$t$(\$|$|$ T$<$D$røtR1D$ D$1D$F$GC $RyD$ D$dD$<$1\$t$|$Ðt&,|$$|$8t$ l$(l$0\$D$,$D$Ƹto1_D$ D$1D$G$\$4$D$P~Ë$Qt@Gİt$ \$D$L$,$1\$t$ |$$l$(,øydD$ D$|$,$1ʼn't$t$(\$|$|$ D$<$D$øta1D$ D$1D$F$$D$yË$Qt;ְ\$ L$T$<$1\$t$|$ÍydD$ t$<$D$\$1t$|$Ð1D$$t@T$$61øD$ D$L$$.I'S1Ƀ( \$0D$$L$$T$D$ \$$yD$ D$d$D$(1[Í&D$ D$D$ 1D$eD$D$$$Ít&'VS$\$8D$t$04$D$¸tHC$D$n@t<$pC4$D$D$ D$dD$K1$[^Ë$pD$C|\$ L$T$D$4$ fVS$\$8L$t$04$D$<¸tHC$D$n@t<$%pC4$D$'D$ D$dD$1$[^Ë$o|D$CT$ 4$D$D$D$If,\$ \$8t$$|$(|$0$lt;\$<$D$D$ D$\$ t$$|$(,Ë<$D$7D$ D$dD$fVS\$(t$ $Ynt;$nOL$ T$D$dD$4$b1[^Ë\$4$D$ȲD$ D$1ʐ1D$$tT$$1øͳ D$ D$L$$.'S1Ƀ( \$0D$$L$$T$D$ \$$QyD$ D$d$D$n(1[Í&D$ D$D$ 1D$eD$D$$$/Ít&',\$ \$8t$$|$(|$0$t;<$D$%D$ D$D$\$ t$$|$(,Ëd\$ L$D$T$<$fVS\$(t$ $)t;$4$D$@D$ D$dD$B1[^Ë4$D$D$ D$D$ʍv',|$$|$8l$(\$t$ T$D$D$0$.Ÿ1D$ D$1D$G$w 1D$ D$1D$G$\$t$ D$G,$D$?@tGf$͠D$0d\$ L$T$$+1\$t$ |$$l$(,ËR$|D$0l$ |$t$$봍',|$$|$8l$(\$t$ L$D$D$0$Ÿ 1҉D$1T$ D$G$w 1D$ D$1D$G$\$t$ D$G,$D$_@tG$蘟D$0dt$ \$L$$1\$t$ |$$l$(,Ë$QqD$ D$0l$|$$봐1D$$t@T$$1ø D$ D$L$$.)'S1Ƀ( \$0D$$L$$T$D$ \$$yD$ D$d$D$(1[Í&D$ D$D$ 1D$eD$D$$$Ít&',\$ \$8t$$|$(|$0$_}t;<$D$D$ D$D$O\$ t$$|$(,Ëd\$ L$D$T$<$fVS\$(t$ $ t;$ˀ4$D$"D$ D$dD$1[^Ë4$D$D$ D$D$ʍv',|$$|$8l$(\$t$ T$D$D$0$Ÿ1D$ D$1D$G$w 1D$ D$1D$G$Z\$t$ D$G,$D$|@tGJ$D$0d\$ L$T$$1\$t$ |$$l$(,Ë5$\D$0l$ |$t$$d봍',|$$|$8l$(\$t$ L$D$D$0$~Ÿ 1҉D$1T$ D$G$Ow 1D$ D$1D$G$*\$t$ D$G,$D$蟈@tGk$x~D$0dt$ \$L$${1\$t$ |$$l$(,Ë$1~VD$ D$0l$|$$4봍'<l$8l$H\$,t$0|$4L$ED$D$@$MD$$T$$11D$ 1ۉD$1 D$E$|$ t$\$D$(E$1ɺ }L$ T$1D$E $1D$ D$1D$E$T$(t$|$\$ T$D$ED$D$$$@tHEd$|D$@|$ t$\$$1\$,t$0|$4l$8<ËE$|T$@wD$ D$l$$볍&'<l$8l$H\$,t$0|$4L$ED$D$@$D$$T$$11D$ 1ۉD$1 D$E$|$ t$\$D$(E$d1ɺ }L$ T$1D$E $?1D$ D$1D$E$T$(t$|$\$ T$D$ED$D$$$w@tHEd$U{D$@|$ t$\$$]1\$,t$0|$4l$8<ËE${T$@D$ D$l$$볐1D$$tT$$v1ø!*D$ D$L$$.'S1Ƀ( \$0D$$L$$T$D$ \$$1yD$ D$d$D$N(1[Í&D$ D$D$ 1D$eD$D$$$Ít&'VS\$(D$t$ 4$D$F$$yD$ D$dD$<$1\$t$|$Í,1t$$t$8\$ |$(|$0D$<$D$øtEF$D$ @tC$PL$ T$D$dD$<$W1\$ t$$|$(,É$t$\$<$D$D$ 븍',t$$t$8\$ 1ۉ|$(|$0\$<$D$5øtEF$D$@tC$<$D$ D$ D$dD$臽1\$ t$$|$(,É$=L$ T$D$D$<$D븍',1t$$t$8\$ |$(|$0D$<$D$eøt>$2@tC$dt$<$D$ D$ D$込1\$ t$$|$(,É$t<$D$ܻD$ D$D${븍t&,1҉t$$t$8\$ |$(|$0T$<$D$襽øtHtP$X@tm$0d\$ L$D$T$<$1\$ t$$|$(,f<$D$D$ 1D$eD$躻눉$t$<$D$,D$ D$臻뎃,\$ \$8t$$|$(|$0$t;\$L$<$D$PD$ /\$ t$$|$(,Ë<$D$@D$ D$dD$f,1t$$t$8|$(|$0\$ ^D$ D$1D$F$\$D$$ttS11ۉ$XiT$ <$D$D$dD$_1\$ t$$|$(,Ët$<$D$PD$ D$$',1t$$t$8\$ |$(|$0D$<$D$EøtV1D$ D$1D$F$Cl$L$ T$D$dD$<$膹1\$ t$$|$(,Ít&1t$t$(\$|$|$ D$<$D$襺øtP11ɉD$ L$D$F$zC$yD$dT$ D$<$1\$t$|$Ív'1t$t$(\$|$|$ D$<$D$øtP 11L$T$D$ F$ڱC($?yD$ D$dD$<$L1\$t$|$Ív't$t$(\$1ۉ|$|$ \$<$D$eøtP1ɺ 1L$ T$D$F$:C@$yD$ D$dD$<$謷1\$t$|$Ív'1t$t$(\$|$|$ D$<$D$ŸøtP1D$ D$1D$Fd$蕰Ct$yD$ D$t$<$ 1\$t$|$Ív'1t$t$(\$|$|$ D$<$D$%øtQ1D$ D$1D$F$u=$yYd\$ L$T$<$k1\$t$|$ÉC<뾍t&1t$t$(\$|$|$ D$<$D$腷øtS11ɉD$ L$D$F$Z$輿yD$dT$ D$<$ɵ1\$t$|$Í&UWV1S\$8t$D$D$0$Ÿ1ɺ 1L$ T$D$C$辮D$$$t]1t&' eFD$ L$D$D$ 1D$D$0T$$ڴ9w,$蚾yD$dD$D$0T$ $裴1[^_]É,$ayD$ D$D$D$0$jv1҉t$t$(\$|$|$ T$<$D$蕵øtP1D$ D$1D$F$jCL$ϽyD$ D$dD$<$ܳ1\$t$|$Ív'1t$t$(\$|$|$ D$<$D$øtS1D$ D$1D$Fy$Ŭ$"dt$ \$L$<$91\$t$|$Í&1t$t$(\$|$|$ D$<$D$UøtP11ɉD$ L$D$F$*C,$菼yD$dT$ D$<$蜲1\$t$|$Ív'1t$t$(\$|$|$ D$<$D$赳øtP 11L$T$D$ F$芫C0$yD$ D$dD$<$1\$t$|$Ív'1t$t$(\$|$|$ D$<$D$øt^1ɉ 1L$ T$D$F$ߪ$AyD$ D$dD$<$N1\$t$|$Í1t$t$(\$|$|$ D$<$D$eøt^1ɉ 1L$ T$D$F$/$葺yD$ D$dD$<$螰1\$t$|$Í\$\$(t$1|$|$ t$<$D$赱Ƹtw1ɺ 1L$ T$D$C$芩D$$t$$4$ȹyD$ D$dD$<$կ1\$t$|$ÍvU1WVS\$8L$|$0<$D$D$T$1 1l$D$ t$C$ȨD$D$$X4t71ҹ@D$CL$ T$<$D$eD$[u1&'D<$6D$ D$0l$|$$迓랉<$D$ ȐD$ D$$蛘t@T$$1øD$ D$L$$.)'S1҃(\$0D$$D$  T$$D$\$$ќyD$ D$d$D$(1[Í&SL$ \$$AS@;Bt[Ðe$L$D$D$ 1D$蚒[Ðt&VSD$(t$ 4$D$%øt;$茚$$yD$ D$dD$4$11[^É',|$$|$8t$ l$(l$0\$,$D$角Ƹt_1D$ D$1D$G$&$D$芯4$肛ydL$ T$D$,$菑1\$t$ |$$l$(,É',t$$t$8\$ |$(|$0<$D$øtEFD$$@t=$yD$ D$dD$<$1\$ t$$|$(,É$p讚\$ L$D$T$<$躐븍v,t$$t$8\$ |$(|$0<$D$;øtEFD$$@t=$d+yD$ D$t$<$=1\$ t$$|$(,É$<$D$D$ D$D$븍v,t$$t$8\$ |$(|$0<$D${øtEFD$$@t=$pydL$ T$D$<$}1\$ t$$|$(,É$.t$\$<$D$ȿD$ :븍v,|$$|$8t$ l$(l$0\$,$D$跏Ƹt_ 1҉D$1T$ D$G$6$D$j4$蒘yD$ D$dD$,$蟎1\$t$ |$$l$(,ÐD$ D$${tT$$1øSD$ D$L$$. 'S1҃(\$0D$$D$ @ T$$D$\$$豗yD$ D$d$D$΍(1[Í&SL$ \$$AS@;Bt[Ðe$L$D$D$ 1D$z[Ðt&VSD$(t$ 4$D$øt;$h$yD$ D$dD$4$1[^É',t$$t$8\$ |$(|$0<$D$苍øtEFD$$o@t=$耖ydL$ T$D$<$荌1\$ t$$|$(,É$>t$\$<$D$pD$ J븍vt$t$(\$|$|$ <$D$ˌøtU 1҉D$1T$ D$F$P Cx$谕yD$ D$dD$<$轋1\$t$|$Ít&',t$$t$8\$ |$(|$0<$D$+øtEFD$$q@t=$ydt$ \$L$<$-1\$ t$$|$(,É$<$D$(D$ D$D$븐D$ D$$ۏt`T$$V1øtiD$ D$L$$.i'S1҃(\$0D$$D$  T$$D$\$$yD$ D$d$D$.(1[Í&SL$ \$$AS@;Bt[Ðe$L$D$D$ 1D$ډ[Ðt&VSD$(t$ 4$D$eøt;$*$dyD$ D$dD$4$q1[^É',t$$t$8\$ |$(|$0<$D$øtEFD$$k5@t=$ydL$ T$D$<$1\$ t$$|$(,É$螒t$\$<$D$pD$ 誈븍vt$t$(\$|$|$ <$D$+øtU 1҉D$1T$ D$F$谁 Cx$yD$ D$dD$<$1\$t$|$ÐD$ D$$tT$$v1øD$ D$L$$.艁'S1҃(\$0D$$D$ " T$$D$\$$1yD$ D$d$D$N(1[Í&SL$ \$$AS@;Bt[Ðe$L$D$D$ 1D$[Ðt&VSD$(t$ 4$D$腇øt;$=BBGC A BC S BC =BB_C A BC C @@@@@@ @@@ @ @ @ @ $@@@@@@@@(@@@@@@@,@@@ C 1[^ÐA BĈBBBBB‰C A BĈBBBBBC -BB‰C &BBC VS\$t$S BC >=BBGC A BC S BC =BB_C A BC C @@@@@@ @@@ @ @ @ @ $@@@@@@@@(@@@@@@@,@@@ C 1[^ÐA BĈBBBBB‰C A BĈBBBBBC -BB‰C &BBC VS\$t$S BC =BBGC A BC S BC R=BB_C A BC S BBBC =wBBGC A BC C P@S \A$BĈBBBBC 1[^ÍA BĈBBBBB‰C A BĈBBBBBC t&A BĈBBBBB‰C BBBS BWC $B1C [^ÐBB‰C BB‰C o@C 1[^Ã[뫍t&S\$ L$S BC =BBGC A BC ܋C PS \A$BĈBBBBC @@ @@@@@@$@ @ @ C 1[ÍA ܈BĈBBBBBPC S n@C fBBS B_C $BC C `&[3Ӑt&S\$ L$S BC =BBGC A BC ܋C PS \A$BĈBBBBC @@(@@@@@@,@ @ @ C 1[ÍA ܈BĈBBBBBPC S n@C fBBS B_C $BC C `&[3Ӑt&VSD$t$‰ N AF =AAGF B AF V BF =^BBGF A BF F P@V r\A$BĈBBBBF 1[^ËV B3BBF =waBB_F A BF ܋F PV ti\xt&B AĈAAAAAF A ܈BĈBBBBBPF V u@F 1[^BBV _BF $B1F [^ÍAAF xA BĈBBBBBF BBBV W@F 1[^Ã[z[tvЍ&'SD$\$ S B BB BBBBBB$B B B B C =wTBB GC A BC ܋C PS t\\A$BĈBBBBC [1ÍvA ܈BĈBBB BBPC S u@C 1[ÍB BS B_C $B1C [Ã[nS\$ L$S B BB(BBBBBB,B B B B C =wQBB GC A BC ܋C PS tY\A$BĈBBBBC 1[ÍA ܈BĈBBB BBPC S u@C 1[ÐB BS B_C $B1C [Ã[vUWVSD$l$ЉljӉ֋M  ށQljU =AAGE G AE M QQA܈AAljU \| [G$BĈBBBB‰E 1BB1JU [^_]ÍG AĈAAAAAE [AAE JAAE 땍AAGE $AE U y S\$$L$(S BC Z= BBOC A BC ܋C PS \AA$BĈBBBBC @@0@@@@@@4@ @ @ C D$D$ \$$'C P@@0@@@@@@4@ @ @ @ @ OS @C P@@WS @C @@C 1[ÍA ܈BĈBBBBBPC S @C BBS BWC $BC C v[אt&VS\$t$S BC *=XBBGC A BC ܋C PS `\aA$BĈBBBB‰C B+C =WBBGC A BC ܋C PS _\A$BĈBBBB‰C BC T=BBGC A BC ܋C PS \oA$BĈBBBBC 1[^ÍA ܈BĈBBBBBPC S @‰C A ܈BĈBBBBBPC S a@C 1[^ÍA ܈BĈBBBBBPC S @‰C BBS B_C $BC S vBBS B_C $B1C [^BBS B_C $BC S @[뇐t&[&뜃[t&벍&'VS\$t$S BC &=EBBGC A BC ܋C PS M\!A$BĈBBBB‰C BC =DBBOC A BC C P@S @?S BBBBBBBC  =BBGC A BC ܋C PS \CA$BĈBBBBC 1[^ÐA ܈BĈBBBBBPC S @‰C A ܈BĈB B BB B PC S `@C 1[^ÍA BĈBBBBBC BB S B_C $B1C [^Í&BBS B_C $BC S &BBC C[Ðt&[&|t&'UWVSt$l$^ ܍KN S\B$AĈAAAAF  F P@V PF V B3BBF =wTBBGF A BF ܋F PV t\\A$BĈBBBBF 1[^_]ÍA ܈BĈBBBBBPF V u@F 1[^_]Ã[CCGF $CF F @‰F CCF BBV BWF $B1F [^_]f[ِt&WVS\$|$S BC =BBGC A BC ܋C PS $\A$BĈBBBBC P@@؉S PS BC sBBBC BC S BC =BBGC A BC ܋C PS \A$BĈBBBBC 1[^_Ðt&A ܈BĈBBBBBPC S @C A ܈BĈBBBBBPC S \@C 1[^_BBS B_C $B1C [^_BBS B_C $BC C eBBB‰C [*Ń[&댍&'VS\$t$S BC &=EBBGC A BC ܋C PS M\!A$BĈBBBB‰C BC =DBBOC A BC C P@S @?S BBBBBBBC  =BBGC A BC ܋C PS \CA$BĈBBBBC 1[^ÐA ܈BĈBBBBBPC S @‰C A ܈BĈB B BB B PC S `@C 1[^ÍA BĈBBBBBC BB S B_C $B1C [^Í&BBS B_C $BC S &BBC C[Ðt&[&|t&'UWVSt$l$^ ܍KN S\B$AĈAAAAF  F P@V PF V BBF =wTBBGF A BF ܋F PV t\\A$BĈBBBBF 1[^_]ÍA ܈BĈBBBBBPF V u@F 1[^_]Ã[CCGF $CF v'F @‰F CCF BBV BWF $B1F [^_]f[ِt&WVS\$|$S BC =BBGC A BC ܋C PS $\A$BĈBBBBC P@@؉S PS BC sBBBC BC S BC =BBGC A BC ܋C PS \A$BĈBBBBC 1[^_Ðt&A ܈BĈBBBBBPC S @C A ܈BĈBBBBBPC S \@C 1[^_BBS B_C $B1C [^_BBS B_C $BC C eBBB‰C [*Ń[&댍&'VS\$t$S BC &=EBBGC A BC ܋C PS M\!A$BĈBBBB‰C BC =DBBOC A BC C P@S @?S BBBBBBBC  =BBGC A BC ܋C PS \CA$BĈBBBBC 1[^ÐA ܈BĈBBBBBPC S @‰C A ܈BĈB B BB B PC S `@C 1[^ÍA BĈBBBBBC BB S B_C $B1C [^Í&BBS B_C $BC S &BBC C[Ðt&[&|t&'WVS\$|$S BC S=BBGC A BC C P@S PC S B3BBC =BBWC A BC ܋C PS \A$BĈBBBBC 1[^_ÍA BĈBBBBBC 1C @‰C 5A ܈BĈBBBBBPC S c@C 1[^_ÍBBC BBS BGC $B1C [^_Ít&[ؐt&WVS\$|$S BC =BBGC A BC ܋C PS $\A$BĈBBBBC P@@ÉS PS BC sBBBC BC S BC =BBGC A BC ܋C PS \A$BĈBBBBC 1[^_Ðt&A ܈BĈBBBBBPC S @C A ܈BĈBBBBBPC S \@C 1[^_BBS B_C $B1C [^_BBS B_C $BC C eBBB‰C [*Ń[&댍&'VS\$t$S B3BBC A=BBGC A BC S BC =BB_C A BC C @@@@@@ @@@ @ @ @ @ $@@@@@@@@(@@@@@@@,@@@ C 1[^ÍA BĈBBBBB‰C t&A BĈBBBBBC *BB‰C BBC 'VS\$t$S BC F=BBGC A BC S BBC =BB_C A BC C @@@@@@ @@@ @ @ @ @ $@@@@@@@@(@@@@@@@,@@@ C 1[^ÍA BĈBBBBB‰C A BĈBBBBBC .t&BB‰C BBC VS\$t$S BC *=XBBGC A BC ܋C PS `\aA$BĈBBBB‰C BC =WBBGC A BC ܋C PS _\A$BĈBBBB‰C BC T=BBGC A BC ܋C PS \oA$BĈBBBBC 1[^ÍA ܈BĈBBBBBPC S @‰C A ܈BĈBBBBBPC S a@C 1[^ÍA ܈BĈBBBBBPC S @‰C BBS B_C $BC S vBBS B_C $B1C [^BBS B_C $BC S @[뇐t&[&뜃[t&벍&'S\$ D$S %JBK B S BBJ̈B B B BBBBBBJ B BBBĉC B C @@C 1[fVS\$t$S %BĈBBBBB3BB#C )=B BGC A B C S BC =wwBBGC A BC ܋C PS t\A$BĈBBBBC 1[^ÍA B ĈB B BB B ‰C _A ܈BĈBBBBBPC S u@C 1[^BBS B_C $B1C [^ÍB B‰C [>̍'VS\$t$S BC *=XBBGC A BC ܋C PS `\aA$BĈBBBB‰C B#C =WBBGC A BC ܋C P#S _\A$BĈBBBB‰C BC T=BBGC A BC ܋C PS \oA$BĈBBBBC 1[^ÍA ܈BĈBBBBBPC S @‰C A ܈BĈBBBBBPC S a@C 1[^ÍA ܈BĈBBBBBPC #S @‰C BBS B_C $BC S vBBS B_C $B1C [^BB#S B_C $BC S @[뇐t&[&뜃[t&벍&'VS\$t$S BC =BBGC A BC S BC R=BBGC A BC S BC =BBGC A BC C P@S \A$BĈBBBBC 1[^ÍvA BĈBBBBB‰C A BĈBBBBBC qA BĈBBBBB‰C vBBBS BWC $B1C [^ÍBB‰C BB‰C o@C 1[^Ã[릍t&VS\$t$K ԈQAAAAAC *=AAGC B AC S BC =wBBGC A BC C P@S \A$BĈBBBBC 1[^ÍB AĈAA AA A C WA BĈBBBBBC t&BBBS BWC $B1C [^ÍAAC @C 1[^Ã[6뷐t&VS\$t$K ԈQAAAAAC *=AAGC B AC S BC =wBBGC A BC C P@S \A$BĈBBBBC 1[^ÍB AĈAA AA A C WA BĈBBBBBC t&BBBS BWC $B1C [^ÍAAC @C 1[^Ã[6뷐t&VS\$t$S BC =BBGC A BC S BC R=BBGC A BC S BC =BBGC A BC C P@S \A$BĈBBBBC 1[^ÍvA BĈBBBBB‰C A BĈBBBBBC qA BĈBBBBB‰C vBBBS BWC $B1C [^ÍBB‰C BB‰C o@C 1[^Ã[릍t&W1VSt$$|$(F@VӉ1ۅˉF ՈHHPHۉF F ׈XXPXF ‰BF M=BBGF A BF ܋F PV \bA$BĈBBBB‰F BF =|BBOF A BF ܋F PV \A$BĈBBBBF @@0@@@@@@4@ @ @ F D$ T$t$$F P@@0@@@@@@4@ @ @ @ @ OV @F P@@WV @F @@F 1[^_ËF 3@ۉF  F 3@ۃ‰F A ܈BĈBBBBBPF V <@‰F VA ܈BĈBBBBBPF V |@F BBV B_F $BF V BBV BWF $BF F C&[멐t&[&뼍&'UWVS|$8t$4%ЉӉ1ۅˉF ՈHHPHۉF sF ׈XXPXF ‰BF =9BBOF A BF ܋F PV A\h[_v'B_F $BF V B3BBF =BBwF A BF ܋F PV \[&BwF $BF F Ph@;T$@wn @V BZr^ BF x@;@ȉ|$x@}~ |$@~ G~ <wD$ 3D$D$$jt&<tHr,p<wȍt&L$$,p<D$$yT$0L$,T$4L$0G )ԋL$(T$0L$4<1[^_],p<%t$(D$,D$(붍&UWVS<|$TWT$WD$T$ W Bt$XG =>BBGG F BG W ;B\$XG =BBGG C BG o MEuO L$$EO QAW \| [ F$BĈBBBBG Q;W h\| [C$BĈBBBBG CSKCsD$(CCT$,SCL$0CD$4CW E<%L$$ȈT$ <u,p<D$(W )B=ЋT$(ȈD$`\$|$$迠L1[^_]Ðt&F CĈC C CC C G 7[AAGG $AG G nQD$\$hV  \nC$BĈBBBBF PH@T$P@L$(H@T$&'#9|$ t$\$$j٩D$DT$@L$<\$(D$HT$DL$@\$nQD$\$hV \C$BĈBBBBF PH@T$P@L$(H@T$U1WVS,l$DEu}D$Ӊ1ۅˉE ՈHHPHE E ׈XXPXE Z BBBBBBBBB B B B L$H] \A$CĈCCCCÉE SKCCCT$SCL$KCD$ CCT$$CL$(CE D$D$@l$$kD$1Ƹ׉D$D$HЉƋD$@׉4$|$CtT$0@L$0MD$ $7D$D$0$bT$0D$1D$$sT$0XD$D$1 $D$sT$PT$01҉D$t$T$ $D$QsT$PT$0D$ $D$sL$0`@N$@M0FQV$BĈBBBBF$׸N$ԈAQQAAAAA\$V$`KBĈBBBB‰F$ջ؉BBB JBBBB#BB B F$B l$F$ՃD$ @F$=wuD$ @‹|$V$`RBĈBBBB‰F$ЈF$MF$@F$L$ Aʋ|$V$`BĈBBBB‰F$ЈBJBMV$vV$BBF$D$$BF$N$Q` V$| BĈBBBBF$L$0 $1[^_]à A AGF$,`A F$V$ mAAGF$,`AF$n&A AF$AAF$GAAF$mAA_F$,`AF$S&(T$ ЃBgF$,`BF$V$"t&mD$ @gD$ T$ F$,`BF$V$aȃA'F$N@'D$ ‰F$&UWV1SGD$8L$0t$‰ʼnǸ D$T$ $nT$0@L$0\$ $D$0L$$1T$T$0D$$qnT$0XD$D$1 $D$0nT$PT$0D$ $D$D$1D$mT$PT$0t$ $D$mL$0`@N$@G0FQV$BĈBBBBF$׸N$ԈAQQAAAAA\$V$`KBĈBBBB‰F$ջ؉BBB JBBBB#BB B F$B l$F$ՃD$ @F$=wuD$ @‹|$V$`RBĈBBBB‰F$ЈF$MF$@F$L$ Aʋ|$V$`BĈBBBB‰F$ЈBJBMV$vV$BBF$D$$BF$N$Q` V$| BĈBBBBF$L$0 $h1[^_]à A AGF$,`A F$V$ mAAGF$,`AF$n&A AF$AAF$GAAF$mAA_F$,`AF$S&(T$ ЃBgF$,`BF$V$"t&mD$ @gD$ T$ F$,`BF$V$aȃA'F$N@'D$ ‰F$&Wg VSt$(\$ D$$t$$ǸD$D$$}i@@g PH$ʇQAAAAH$D$1D$$ixpx $I1[^_S\$ L$T$$h@@>PP$BBBBBP$[Í&'VSt$ T$\$$D$$3h@@PP$JBH$B H$AANjSAAQQQYވQ Q Q QY 1A AAAAĉP$A @$\$D$$rg[^Ðt&UWVSl$0|$\$8L$t$4$g@@|8GFW$̈BBBBJBBBljG$B W$B B ZB ZB BJ BBBZBB BBBĉG$B W$JBtBBO$BG$G$@G$BȈT$ BV$̈BJBJ BňB B BBBBBJ B BBBF$B N$AAF$D$@,T=AAWF$AF$F$P@ĉV$@ V$BV$<<A<$vD$ z6D$Du_F$3@ۃF$#v<D$ eD$D$$j2<mr,p<fw>N$^$AT$DF$!=AA_F$BAfAAT$DF$=zAA_F$BANUfWVS l$ D$,$ D$,$ ø D$1D$$>Xt$ $|$}>@@fN$0FЀ AAAAAAAQD$(F$t@T$$BAA @AAAAA A A A QF$F$1@F$D$1D$$=T$$B@|$4$øD$u=T$$lj%;uف G<,$襰 1[^_]Ít&'UWVSD$8t$‰D$0T$$)T$0\$$)T$0$ƋD$D$L$D$D$0$ T$T$0D$1D$$8GD$4@4%9‰D$* G$PՈPP@P@ÃG$D$1D$$D$1D$$T$NjD$49tbL$41A@|$l$4$RT$4lj%;uف G<1[^_]Ë G<녍&jt$ G$|$ $D$zG$@@@@G$&UWVSD$8T$0\$8|$$D$yD$0\$$T$T$NjD$0$T$01ɉt$L$ŋ$3T$0xXx T$D$ $;\$@@D$00FtN$$ AN$V$ BBF$B V$BBBF$BV$D$8BF$- JBBT$0F$1D$1D$$T$PT$0hh 1틊D$1 $D$T$0@@ $D$l$T$0@|$t$ $j@T$0D$0$w1[^_]fT$01ɻ\$L$$T$hPh UVWVSD$0\$8l$8|$8T$$wT$0\$ $|l$D$D$0$|T$0|$$D$|T$0D$D$1D$$iT$PP T$0XD$1 $D$*T$PP T$0xD$D$ $9@@VD$00F9V$D$D$B3$ ȈBD$$ JV$L$ ЈBBD$8F$2BD$JBT$0F$1|$t$$T$PP T$0h1҉T$ $\$T$0@@ D$1 $D$T$0@ D$1D$ $]@T$0D$0$t1[^_]Ðt&T$0D$1D$$T$hPP 뚋N$3T$D$$ ЈAʉN$Pt&N$3T$D$Ή'UWVS \$(l$ |$(D$ ,$s1D$,$st$,$s\$,$y1ҹL$T$Ƌ$&@T$(@ PD$1 $D$pXp D$ $D$@@AQ$$ BB3BBD$(A$uBB1BA$D$1D$$"@x@  $t$\$@@ 1T$ $D$@ D$1D$ $y@1 1ۋ |$ $D$=@t$\$ $@,$Iq 1[^_]øD$1D$$@x@ :U:WVS D$D$ t$($pT$ \$$vT$ ǸD$1D$$=X\$ xx D$ $D$@@:AA$P=P@@A$1ҹT$T$ L$$\$ p@ D$1 $D$L@ D$1 $D$@$Qo 1[^_]Í&}1A$XPP@@A$ʋA$PPQ$PA$U5WVSt$8T$T$0 $D$|nD$0 \$$vtT$T$ŋD$0$`tT$0ǸD$1D$$T$0hXh D$1 $D$T$PT$0xx D$ $D$qT$0@@5PH$11;QT$0H$l$|$$T$0p @t$\$ $T$0@ 1T$ $D$T$0@D$0$l1[^_]ÍU0WVS D$ |$(L$$plT$ \$$erT$T$ 1D$$X\$ hh D$ $D$@@0AA$P׈P=PXA$T$ 1D$11D$$A\$ x @ l$ $D$@|$t$ $@$k 1[^_]Ít&};A$XP׈PPXA$fA$PPQ$PA$&UW,VSt$8T$0|$ $D$,jD$0 \$$&pT$T$ŋD$0$p1ҹT$T$0L$Nj$T$0hXh  D$1 $D$cT$PT$0xx D$ $D$!T$0@@,PH$11;QT$0H$D$1D$$T$0p @l$|$ $T$0@t$\$ $NT$0@D$0$h1[^_]ÍUWVSD$8ɉǸoD$D$0T$$hT$0\$$nT$0$ŋD$D$mT$0D$D$1D$$T$0hXh t$D$ $N;\$@@oD$00Ft!N$$ T$ЈAN$L$@F$PP%@PF$1T$T$01D$$T$PT$PT$P T$0D$1 $D$aT$0@@ D$1 $D$!T$0@ l$ $D$T$0@D$0$f1[^_]f};V$D$B$ BBBBV$t&F$T$PPV$PF$yt&UWVSD$8L$0‰T$T$ $9eD$0\$$9kL$0T$ $T$#kT$0D$D$1D$$T$0xXx D$ $D$L$0;\$@@0Ft!N$$ T$ЈAN$D$6F$P%P@@F$T$01l$1D$ $T$L$PT$0HH |$t$ $T$0@@1҉\$T$ $]T$0@ D$1 $D$$T$0@L$0 $Vc1[^_]Ã}7F$T$H@@PՈPF$vċF$T$PPV$PF$t&UWVSD$8|$8l$0\$8D$OD$ ,$rb|$,$vhT$,$T$D$bh\$,$D$RhƸD$1D$$T$PP xD$1 $D$pXp T$ $D$~@@OAQ$$ ؈BBBB;|$A$5B#D$B$ ؈BD$ ÈBBA$D$1D$$T$PT$PT$P D$81D$1 $1ۉD$@@ $D$|$Y@ $t$\$+@,$e`1[^_]B#D$ ÈBBA$'UWVSD$8\$8l$0|$8D$ ]D$ ,$_\$,$eT$ ,$T$D$e|$,$D$e1ɉt$L$D$$AT$PP X1T$ $D$T$PP xD$D$ $;\$ @@]0FN9|$ mV$D$D$B#$ ȈBD$$ JV$D$1D$$8T$PT$ PT$P D$81 $ 1ۉD$|$@@ $t$\$@ 1T$ $D$y@,$]1[^_]ËN$#T$D$$ ЈAN$N$#T$D$Չ'U WVSD$D$0l$8\$8$]T$0l$$b\$D$D$0$bT$0ǸD$1D$$T$0xXx t$D$ $K9݉@@ D$00FV$B3BۉF$BD$$ ȈBBF$ɇH1@@@@@@@@ @ @ @ @ @T$0F$L$\$$T$PP T$0hD$81T$ $D$9T$0@@ D$1 $D$T$0@ D$1 $D$T$0@D$0$Z1[^_]ËD$F$t&UWVSD$8L$0‰T$  $T$iZT$0D$$D$e`L$0\$ $D$Q`T$0ŸD$1D$$T$0hXh D$ $D$L$09\$@@ 0Ft!N$$ T$ЈAN$D$rF$PՈPPHF$T$01l$ D$$T$L$PT$0HH F$@@@@@@L$0F$1|$t$$T$0@@1҉\$T$ $WT$0@ D$1 $D$T$0@L$0 $PX1[^_]Í}D$0|$$DL$0T$ $T$DT$0D$D$1D$$#T$0hxh D$ $D$L$0@@0FD$8T$8D$ L$ 1;T$ s;|$t!N$$ T$ЈAN$D$t0|$?F$T$PPV$T$PF$tAl$F$T$PPV$XF$vD$86V$D$ ȈBL$0V$1|$t$$T$L$PP T$0H1҉T$ $\$PT$0@@ D$1 $D$T$0@ D$1D$ $@T$0L$0 $ <1[^_]ËL$0D$1D$$~T$L$PHP 뛋F$׈XX%PXF$et&F$T$XPXPXF$,V$D$$ BV$ UWVSD$8\$8T$8l$0 D$T$D$,$:\$,$@L$,$L$D$@ǸD$1D$$ZT$PP X1ۉt$\$ $$L$Hxx T$8D$8D$ L$ 1;T$ sֺT$$D$@@StFу4+S$$ BBC$ЈBC$'S$D$$ ؈BBC$D$t$|$BBBÉC$D$BC$t6NC$HP@PHC$S$ ÈB S$D$1D$$T$Pxx D$8 D$11 $ D$9@@ $|$t$@1҉T$ $\$@,$81[^_]Ít&C$P@S$PC$C$ΈPP%HPC$BBBÉC$AC$PՈHHPHC$UnWVS|$8D$8l$0L$\$8D$ ,$6|$,$tMC(t!;Zvu9ډu %9t@ uK1[^_]Ë@ u1[^_]Ë{LK(t ؃[^_]ËS,{8tC0EFEF@xCdChChS@{ [ESCCffF>,[^_]Ít&'UWVSE}EE;} Us;t/EE M EQȉGE9Euڃ[^_]ËUt] 41ÃSȉEɉMMU9}Nuփ[^_]Ð&UWVS4}EEEEEEEEEEEEu] @@S ȉCɉFCMȉEEUFV SCȉEыUɉMEVFSCȉE܉ыUɉM؋E؉VFS$C ȉEԉыUɉMЋEЉF C(V$S4ȉF(C,ȉщF,C0ȉMȉE̋EȋỦF0V4Sø1\ֻ1KUWVSMEEEEEEEEEEEEDžxDž|DžpDžtDžhDžlDž`DždDžXDž\t6ExTW@DPURX҉Ut#Eļ[^_]EEļ[^_]ËO@EMD$<$uċE=wE$/ẺGDGG<EM1_Q(I,UЃM9U1UM9s9kMGyUEEЅ҉UủES ȉCȉFCȉEUɉMEV SFCȉɉMUEMCȉVSNEыUɉMEVS$FC ȉɉMUEMV S4C(N$ȉщF(C,ȉF,C0ȉEUɉMEEV4S D$EЉ$(뼍vUHuƍEԉE1}}Mй]8CT$ED$$w!}D$34$|$#tE]u}]$,!D$D$ P D$EЉ$k'뼍t&U8uuE]UÝBD$E}} D$ D$D$E$&~,EF$vMD$ $D$ D$uEEEEQtfED$D$ UD$D$4$qsC1$}D$<$D$ D$jUD$D$ D$$<$uMD$ $D$  D$4$f4$Dž$ }D$<$D$ { D$_4$DžXu1D$4$ED$t$D$$ETu!,$"ǃTfMt$D$$vPBlB|P t$ h$}D$<$D$ p D$=3$D$ $D$ u D$D$4$9v'UWVS,U3E w|D$E$'XUBHE$|UU4$D$T$f}u~e1v9tNΉƒx%@t=t uӍvE@ptƋDD9uD$D$ D$D$U$D$D$U$D$D$U$ut&D$ D$t$U$y0|$D$U$; 0E4$D$D$ " D$E$E>D$'D$D$ p$fEEEUzHlEt$1},[^_]Ít&D DuDfED$D$ D$D$U$E܋E܅E@H[ED$D$ D$D$U$E܃u 8ƋEm>v \_$ D$D$$L,[^_]ÍPD$D$E$ ,[^_]É}pt&` $l D$D$ p D$E$PU(uu]}.~du~tNpu6ED$ D$E D$$ t=]u}]D$D$$ Ɔ $ D$D$ + D$$뎍D$fUWVS\E-PxpƒUỦUExueEED$UD$ T$U)D$ED$$u6% t i1\[^_]ËUB\[^_]ËEpdu#@tt;EuȀ}_EtUJpte}UfUEffBfEffBE<wȋUE؃L$D$$ E΋UfBUB 9~ƋEPHu)tt$ |$U$T$EED$D$U$ EUu}샀T$ED$E$U\[^_]E֋,$D D$ 4 D$D$E$~aUE;BxP>EfUfEfUftEfg $ D$ A Z$Uf t1f]Í'UWVS +lEE$ EUUwG EEEtcWUȉEEEtGEt 5EfEEtW҉Ut ED$:G$FEt* U0t&JDFuuEU E܉T$,UЉD$(E؉T$$ỦD$ EԉT$UȉD$D$EĉT$UD$ GD$G$D$x??E$ E UD$$xU1ɋEl[^_]ËE$ Utډ$ 1ҹEUU$wD$D$ zD$E $ 눐UEUD$ E$D$E D$Í&UEUD$ E$D$E D$Í&UU VuBABAB A EF^]Ðt&US[($E D$EED$ lD$E$4#E$[]UU VuBABAB VA E^]ÍvUE@]ÐUE]@Ðt&UWVSqù'MU t&1E:}:uu҃1[^_]B[^_])Ít&'UWVS9' t?t&F t U$T$1u݋ [^_]à [^_]ÍUVSu&t$u&B 9t J u[1^][^]AfUVSu/w&t'1Ʌt'1 vB 9tB u[1^]ÍI[^]Ð&UE]@ Ðt&UE]@$Ðt&UE]@0Ðt&UE]@4Ðt&UE]@ Ðt&UE]ÍUE]@Ðt&UE]ÍvUEU $T$Ðt&UEUD$E $D$Í&'UEU $T$Ðt&UEU $T$Ðt&U]Ít&'UEUD$E $D$ɃfUEUD$E $D$Í&'$U]Ív'Uuu](p$4$t$+$4$]u]Ít&'U]$u1$t>D$D$$E F EF\]u]Í'USSÛ#D$D$E$[]ÐUSM U#tE $D$҃[]ÍD$D$$Ӑ&UWVS}"u t|Eto~'E19uuv&94tj9u4$tKD$ D$D$$$[^_]Ðt&1;wt4$u4t$ 볃u}t#t$<$Utw1[^_]Áu0GUuu]!t$x$f]u]ÍUScë!E$[]Í'UVSu,t!D$D$$@t5M t)D$D$$1҃tH[^]À$WD$ D$D$$$D$ ĐUuu]hð D$D$$|t ]u]"$D$D$ D$$뼍'USE% D$ E D$D$$[]Ít&'U(uu]}} u+$‰tQF]u}]$`t' $D$T$$D$D$ p D$$|t&US$UMUU EA u(ED$ D$D$ $$[]ÍED$ D$D$ $uո΍UWVS1y}u G t9Et$<$D$ ED$/~~)ƅv1[^_]Ít&Et$<$D$ ED$t $ÐUWVS룍T$ 7'UWVS EcEUEr EtLF>t$ Ft$F t$Ft$4$uUB$UBt$E$U҉Ui [^_] U(]EKÓuu}1$t$bt=Et@ft>1D$D$4$ƆE$]u}]ÐD$@X4$D$aƃh뽐&UWVS: :u; :Ft`v4$<9smL t&9t^DAtD$ D$ D$$_ǃ[^_]< :Fu= :Fu1DAu[^_]Ðt&UWVS,E u8u(?t"G4$D$9uU1:,[^_]ËUD$ D$D$DT$4$$$sE}4$UB9ME$UBZEE@ @3U E2EuƋE@uFu>F9E}UBt(Fu"uuʋUuEUUE҉0uEU E,1[^_]@ZUB0E$D$D$ p D$U$R$qD$D$ p D$E$U$ $,D$D$ p D$E$kUB$E$&US4E=ÅD$ED$ED$ E D$ED$E$04[]Ív'U]6uu 4$1tEt$$D$C]u]É'UWVS,E4}D$D$ED$ E D$ED$E$E1҅$cE<$D$FEE D$E$FE$E(D$E$$F $},trE0D$E,$FEP uZ‹u21҃,[^_]@EbE$Fx},F uEFP up ,1[^_]$D$D$ p D$E4$j$oD$D$ p D$E4$Ft$4$$D$D$ p D$E4$]Ft$~Fu릐t&;$D$D$ p D$E4$4$8$D$D$ p D$E4$F t$F^aUtA,uAvMHUEeE$yFt6UD$$T$KE9ljw)]Fu}]Í'$n&'UVƃ=@@`p^]Ív'US $EEǃ,E($WUE$JE3atU$U$ǃǃlǃpǃǃ=‰ǃǃǃǃǃǃǃǃǃǃǃǃv'T$$&.ǃǃ ǃ& <,Et t2ED$,$蕆U BE1$[]Í,$j,t xu@u$ǃǃ ǃBǃ@ǃǃ ǃǃǃ ǃǃǃ ǃǃǃ ǃǃ ǃ ǃǃǃ ǃfǃǃ ǃCǃǃ ǃ ǃǃ ǃǃǃ ǃǃǃ ǃǃǃ ǃǃ ǃ ǃqǃǃ ǃNǃǃ ǃ+ǃǃǃǃǃǃǃ ǃǃǃǃǃǃ ǃǃ ǃǃǃ ǃ^ǃǃ ǃ;ǃ ǃ ǃǃǃ ǃǃǃ ǃǃǃ ǃǃǃ ǃǃlǃǃǃǃǃǃǃ ǃ-ǃǃ ǃ ǃǃǃ 0ǃ0ǃ ǃ ǃǃǃ ǃǃǃ ǃ oǃǃ ǃLǃǃ ,ǃ,)ǃǃ ǃ+,K=`D$ED$$$1U(E]uD$E }$t.E4$D$ED$ ED$ED$4$+]u}]ÍU]E;Ãu}$xq|$ƋE4$D$~D>]u}]Ít&UVƃ-`VP ^]Ít&'UuƸU}Up@`xPu}]Í&U ]UVÞuƉ$]u]ÍU0U]_ UVƃMaVP ^]Ít&'U WVE EF UFP wW^_]Ít&UWVSqù Eu NEE cǸ0D$<$E|$$UT$UB$UBU D$B$}U BUB-U F Bt$B$8E [^_]Í'UWVSEuqEE E ljpG`UUET$$UT$UB$UBU D$B$U BGBUBU tvU2t$t$|$$[^_]É<$bljG`@Et$$Uu뢐t&UVSRÚuSD$F$z@ D$F$TVP D$F$i[^]Uu}E ǸUFP wWu}]ÍvU|$Ǹ4$1F @@`p4$|$]ÍvUS#kt1=t []ft#=a‹B []Ѝ&U]u։}Elt6@U0P D$<$]u}]Í lj0EUW ɍ&'UVS"jT PP D$4$i/T@ D$4$F d@ D$4$# D$4$D$4$[^]fƋ F [^]ÍU]fuΉ}w 1f t&]u}] E0x E]u}]Ë (q@E 0P D$E$qU‰VƸ@E@`@p^]fU]Gu}Ǹ6ƉF`x@E@$(]u}]É'U]uu}^tTp D$<$MƋE v`~ɉFEFt } t} 0t]u}]Ðt&4$x⍶UE]M @uu}}tW~G&u;\aMu} EanE?ȉ%< ЋU1ɉEu} E]1u}]x?w|%?1ɉEu} E?벋t?wWMu} E눍L$$3($($L$$L$$O($k($@L$$vUE]+sut-1D$ D$D$ $?D$ D$D$ $?1t$$F]u]Ë-w}D$ D$D$ $?1]Ɖu]Ë-w<D$ D$D$믍($M($?($1UE]M uu3}}w$ 2luYltMu} E]u}]tPŋtMu} E븋lt4lMu} E눍h$%$$ 'U)Sw 2VD$ D$D$$6f[]D$ D$D$Z$6VD$ D$D$M$60D$ D$D$$6 D$ D$D$$6_D$ D$D$$66U(E]kóu }w 82+lD$ D$D$$3ID$ D$D$$4#4$ljD$]u}]ËlD$ D$D$$5ǃp뱋lDD$ D$D$$5ǃpNjP P DlD$ D$D$$3'D$ D$D$ljD$ D$D$$3D$ D$D$l D$ D$D$$3D$ D$D$7lD$ D$D$$34D$ D$D$ltQD$ D$D$$3D$ D$D$$$$4$X$x$$$&U(E] Su}FGl")*Ƹ*4$ljD$+|$$-|$$.|$$~$|$$]u}]Ðfl$tt&l4)XƸ*L4$ljD$+4|$$,|$$-|$$.|$$$|$$.lD$ D$D$$4gD$ D$D$$4A4$ljD$D$ D$D$$3|$$~$$ $L$t&UVuD$D$t$ u 4$^]ÐU]^æu}ttn'&D$$}D$$@ƹ1Ҹ[4$ljD$]u}]ùD$$D$$`뜐&UVuD$D$ $t$ ^]UVuD$D$0$t$ ^]U].v9ʉuΉ}E~։ʉ$UU4$ǸM<$ƉD$]u}]U]9ʉuΉ}E~։ʉ$U$U4$Ǹ<$ƉD$/]u}]UVuD$D$ $t$ ^]UVuD$D$$t$ V^]U]6uu} tD$t$BA $Ax04$D$<$ƉD$]u}]Í($~&'USKuu[]D$$+t&'USuu[]]D$$t&'UScëUuuU1[(]D$$t&US[uu1[$]D$$>&'U(E]U uu=}tX~>|tfsv&ÆEU܉MEvtETUE|fGO G щ $U1ɋEMɉtD$E$mm}uwu}v^UE؍tU܍|V Љ$ENU҉EtD$E$%mU}UwM؅u E,[^_]ËU$U܋EU҉tD$E$uE,[^_]Í&'U]޹&}ljuw2t&1Ҹ<$Wǐt&]u}]ÐƉ4$ljD$(ƍdƉV4$ljD$H떍<$rfUE ]Cuu<wt4$4t&t=u܋]ҋu]t&'U]莸uuuu*4$w/]uu]D$`$D$$'U]Vuuuu*4$w/]uu]D$$D$$ 'U]获}ljuw2t&K <$f]u}]ÐƉ4$ljD$ƍdƉV4$ljD$떍<$yrfUWVS讶Ew 2tt&LǸƉF`x@E@E$ED$4$ǸaƉF`x@E@$SU$4$ljD$E<$D$xƸUp@E@`@T$$95EƉF`@E@EF4$U$ 4$ljD$E<$D$1Ҹ5UPU@E@`@T$$1Ҹ~Ǹ@EF`@x$E $4$ljD$U<$T$]1Ҹ ǸƉF`x@E@$rE4$D$E[^_]ËE+NjE<$ƉD$uE[^_]ËENjE<$ƉD$uE[^_]ùDǸUƉF`x@E@$ED$4$ǸYƉF`x@E@$KE$4$ljD$U<$T$1ҸsƸUp@E@`@T$$41Ҹ3Ǹ@EF`@x$E$t&U]V}ljuw2t&˹<$f]u}]ÐƉ4$ljD$XƍdƉV4$ljD$x떍<$rfU].v}ljuw3t&<$f]u}]ÐƉ4$ljD$xƍdƉV4$ljD$떍<$rfU]NÖ}ljuw3t& <$lj]u}]úƉ4$ljD$ǐt&dƉV4$ljD$똍st&UE }]x<uuwtl$wt<~'t5Kz{$|tV~7 fteiu߉]}Љu]1=t=uvՃu]}Љu]a]}Љu]]}Љu]Q]}Љu]p $ E$ЉljD$E$]u}]É'UVΉMEEEMU$EEEv^]US训=tu~F=tl=&t&~s $3[]Ãt(=vuċ$ȋ ȹ$[]Ë $[]Ë[]vU]辬=}lju)~]==&=t&t&Q<$"E!=u$$Ƹ4$ED$71UT$$$OƉ$E4$D$V$7t&$Ɖ$ $4$ED$E]u}]Ë$Ɖ$S<$랋$dƉ$tO1EE4$D$O<$GUT$$x:?E묍v'UH].v}ljut2Wt~v=~=݆vuf]u}]xv2<$Ɖ]u}]Ë(3!t$늋]u}]]u}]D$11$CGM녍 $7`!v$=$/5%&ht&01]u}]p$.E$|ƉD$E$݆t&u$ E~݆>$Eи$o$ǸREԉD$<$EԉD$EЉ$quwt&$Eظ<$ƉD$E؉$胿f`t&X$!<Eܸ$-ljD$E܉$L$/ED$<$!uRc[?݆@ ҍvm $11ɸM݆D$$`1Ҹ$$ǹ<$D$2f Bf 1t&%D$ D$D$$5EƉD$E$b_$-E $ƉD$E$k݆p$0(P t+@$t$ʉȁ Љʁ $Rf%$'D$$@݆JW@$v룿'*+ ժ$Eh1Ɖt$E$d<$\t$$萻$X#$$$$71<$D$޺$t$$f$Zt$$莺$7):vUdS.vǃ J []Ít&Uc]fU]辠}uu  t$hD$P $ʺ Džx0 1ɸ4$D$<$ƉD$ u]}]ÍPD$$?zGi&UE]諟u}tf~Zx $t&x鋃wZlu]u}]$ǸƉD$<$÷uE]u}]à iKǸƉF`x@E@>ED$4$OKǸ迺ƉF`x@E@$豷4$D$E<$D$:1ҸƸ]Up@E@`@T$$誶1ҹǸƉF`x@E@$E4$D$WE<$D$蘶1ҹGǸ軹@EF`@x$譶U4$T$9݆$Ǹ&t&~@== =vGt]u}]zg{p $S$ٵED$4$Z1'UE]+su}xvlw~nC=t&=t&=t&t]u}]ty $t6& ]u}]> i ]u}]p1ɺ։Et$$_1ɺt$4$ǸE<$ƉD$t$E$膳]u}]ÃztK{tb($ ]u}]# ]u}]' ]u}]p$$x 4$D$躲/t&U]ޙ&ɉ}ljuI(v袡f,6)$1ɺ1ɺƉ4$D$苲]u}]Í)$辳݆<$Ƹ 4$D$밍D"$}"$o!$a!$S!$Ep!$7)$))$k)$ +)$@)$U)$D!$ղ!$Dz <$Ƹ]u}]F*$胲-*$u*$g*$Y1ɺ<$ƸhtOktmu1҉<$Ƹ_)$)$)$ձ+<$Ƹ<$UWVSeʱ(dD$D$$t\tWt&uAƋx4$ljD$誯[^_]Íp"$߰=蟲dtR"$臰 ]  0hP 5 lP pP @@t@@p@ ;B衱tx@ B{Dž$Dž,Dž0Dž4 Dž8 |@@@ 3Dž< Dž@ DžD DžH DžLDžPDžTDžXDž\Dž`d记,dF莰0 dP Pb4(dp @ !$@ `p իB@ xP|PPP腫Dž$Dž,Dž0Dž4Dž8@@@ 3Dž<BDž@DžDDžHDžLDžPDžTDžX Dž\!Dž`"$轨"$诨 U(].vE݆uΉ}UEt~JtuBEt$D$ ED$E$0NjE|$$菦]u}]Ãt 薕ED$D$ ED$E$D$ƋED$ ED$E$4$ljD$nED$D$ ED$E$|$$ANU(]VEuΉ}UEt~JtuBEt$D$ ED$E$NjE|$$o]u}]Ãt vED$D$ ED$E$D$ƋED$ ED$E$4$ljD$NED$D$ ED$E$m|$$!NU(]6E݆u։}MEt~JtuBEt$D$E$'NjE|$$V]u}]Í&t VED$D$E$D$ƋED$E$4$ljD$uE1v*}6,t&#T$$>|t6D$$]u}]ÍD$$ͺȍ~l됃,E]u}]3T$&+$D$$D$|$ t$$D$-%t1ElE1EMfU8]~ƪ}ljuw8t&;EEEE`D$$fEиhUع<$Ƹ4$EԉD$袗D$$Uܹ<$EwƉD$E$VEԉ4$D$藗D$$ĸU<$EƉD$E$Eԉ4$D$<D$$iU<$EƉD$E$蠖Eԉ4$D$EԉD$EЉ$Eԋ]u}]Í#$Ɖ4$EԉD$8뷺Ɖ4$EԉD$]E E EEv'U(]}Vu։}Ew |8˄E EUN ɋB UȉL$1ɉ$ UNɉNjBUȉL$1ɉ$|$$KUNɋBUȉL$1ɉ$Ŷ|$$Mʋ1ɉT$Uȉ$蘶|$$E|$$ؔ]u}]ËEUM $ET$L$UM T$L$EE$EU$ljD$o땋E MUD$EL$$jMUL$$EE D$EDM $ljD$c6EE^vU(].{vuu }׉E*t(w8vۂ >΍ $T$$:d$T$$(@$T$$*T$$*T$$*T$$*T$$Δ+T$$輔/+T$$誔$$蜔$T$$芔%$|$$nh%$`@%$RMED$D$$݆]u}]Í%T$$+T$$+T$$M+T$$ٓj+T$$Ǔ$$蹓#$諓+T$$虓+T$$臓+T$$u,T$$c%$U%T$$C%T$$1UWVSlEU ẍM҈MEmE$RFEiMApU}RUouM؋EME<EEEUT$D$ $&EupuE؋UЅBu=EЅFu3EЅFu)EЅF u}vX}t[X&$%t&EMD$8&L$$t&))MD q}u4EMUD$E$U$l[^_]Í~,$薑8,T$$~UM,$T$iED$&$Td,D$$>&'U(]vuƉ}w 49f{~E EEMU1ɉ|$4$E԰ljD$E$#]u}]Ít&ED$E D$E$`EED$E D$E$;ljD$E$躎땋ED$E D$E$EED$E D$E$ljD$E$貎:EEfU(]~uƠ}} uuUE*t(w H9*} >|$4$UEE싃uR|$4$UEwED$E$|$4$UENED$E$܍E]u}]D$D$ $UEED$D$$D$D$$5뼍*T$$诎*T$$蝎*T$$苎*T$$y+T$$g/+T$$U$$GE]u}]A%$#$$h%$@%$&$%T$$ٍ+T$$Ǎ+T$$赍M+T$$裍j+T$$葍$$胍#$u+T$$c+T$$Q+T$$?,T$$-%$%T$$ %T$$t&'U(EM}uƉ]brêɉE Ut UE D$$t;v,<v<f$fy<<t<EtEMUE MUƋE t$$谊]u}]Ð,$fE D$E$;5Ҁ U eU )e E ML$M $MpE MU[E MUFtEtEME $MUM$ƋE St$$藉7E  fu^u1E T$U E $1vE@$\E5ȉM ,$8,$ &$fUhE]o} ԉE׍ED$EUMu$8U)E Ut?U ED$$8u)ljЅEu}tM~,$y} uuXEuЅtɋEUD$8&T$$:UMED$$-]u}]+}E랋E UD$&T$$,$Ոt&UhE u]XnàE‰}E5vO&,Et&;EME̍vE̋]u}]À, fMEEEE $S;EKEF}ĉ}ȋuЍEEE $vFu}tFMU@ $MĉT$NjE̅tẺ|$$}먍l'$Nt&t!tt&tt,$ ED$ED$E$b8W<UME\UME̋EKủt$$LG&}UMFT$U $MȃE&EMEU$^9Zu uMu $t$ EUЉ$HtE̅}3au-MD$-$L$貅fEE}EEtbt]tXtR&$PwPwf%&'$ ED$ ED$ED$E$7<uMUE4$0UM4$E̋EỦT$$=8E =E$WM $3U u$1҉t$@EE=E; fiu4$f3U贲4$Etttzt&t{&pr$lj$gu4$2U芸<$ẺD$蛁4$sE=aEGE4E&Eg=GE=f=t&U$2CU4$E=s(Mu.$L$cU$1+U膷4$ErU$1U4$Eru4$~1UL4$ErU-$T$ǁM-$L$貁uu.$t$蝁u-$t$舁ED$-$su-$t$^U .$T$IED$h-$4u-$t$M-$L$ M-$L$U-$T$M&.$L$ˀU[.$T$趀ED$@.$血u&.$t$茀u@.$t$wM[.$L$bED$-$MMK-$L$8ED$4-$#M-$L$M&$L$'UWVSeɐ }y^‰}1,G,1B‰}`},t=  [^_]ÃtL0@ 3dD$<$O~F D$<$,~0D$<$~F ̀LD$<$}豀P D$<$}茀D$<$}UB<$D$}Ex [^_]Ã6 @ @@`p@i|$$m|?UVSc؎9FtNFF<11Fdt'FTFtBxuu uDžDžDž G LJwtGxW|dml}~c64t)FTNu>uZE8 ,W11`,_Tw,W[|9J<rh<8 ;"BTRTuG<0 DžDztP[] U]4f_}}u<$<.D$Dt @fq.D$<$|Dt @fЅx5E ҉0Ex9t]u}]1xE Eːt&U8]E[3ã^uuD$ ED$}4$=D$sB4$C1tmD$-<$Z#E@[_]ÍUVS1 ]E$A1҅tptȉQu[^]Ðt&UWVSq1ù\}$}?E7(=MMEK0UEMDput MAt`0M u҈tYE<:t*<.t&MQutWU뒍&Ճ7U{t W뙍7뎋E[^_]UVS1~0[t%@19tJu[^]Ë@[^]Ð&U1]É'U1]É'UE]Ð&US0K[E$3<[]Í'US/[E$3;[]ÐUS/ZE$<[]Í'USs/ûZD$`>D$E$D$E$>[]ÐU8uu ]}}.*ZEFEFEF |$ D$D$EE$<|$ D$FD$E$|<]u}] UH]^.æYuƉ}ϋH @fEUEòEEfEME|$ D$D$$;u]Ћu}]Ít&5$q7D$D$ED$ '@D$$=1;8t<$91뛍&'U(uu]x-X}} Ft=@]E}u]>D$D$ D$$ =]1u}]ÍU(E],3Xuu }E@EtL>-t1KD$4$6tlE]u}u](~uɋD@D$>t$ D$D$E$D<]1u}]04$5t$ D$붍U],VWuuV ;t$18F8t$7]u]Ð&UWVS+ W\}EfGEEG ED$ G(D$D$Ẻ$;;G(W$UԉЉ% % ЋU MЉ% % ЋU MЉ% % ЋU MЉ% % G,MQU9USfh;0vB%04t$50$q84SUET$D$D$ 4$9;EEED$4D$E$u6t(ED$ ED$$D$D$ED$E$UE E9EE\[^_]ÍEԉEE؉EẺEEЉEG,UEU9UEET$D$D$ E$8;E'E$9t$ED$ l?D$D$$8EE\[^_]ËU;UbMGEf E$9u%Et$G(D$ (?oR0$1D$D$ T@D$$$8EE\[^_]Íp@D$D$$7EE\[^_]Í@ǃ0&'U]'SuuD$?D$$61Ɔ]u]UWVSq'ùRL$5gED$D$$K1UED$D$$T$ 6[U܁òU4ͲtwЁ ЋUm U EЁ}ò}4Ͳ@D$D$E $6<$1EẼL[^_]G(f}E1@UĉGEG MEȅ-@1Uv9B u}4ͲO EȾUGW t Eȅ$3G8oUM)fG0G4fG,U$?-LJG<||ẼL[^_]EG$ EfU fUUЉ% % ЋU MЉ% % ЋU MЉ% % ЋU MЉ% % M}4ͲG(Eā}4Ͳ OG G,t&afv1fG,HLJE$4+$!-D$D$ T@D$U $`3@D$D$U $>3@D$D$U $,E ƀ?t$D$ D$D$E $2X@D$D$E $r,U ƂE4U(}}]u"M?-t>iD$<$,tJE 4$D$t!]u}]fu0ʋ;0tՉ4$n.*$+|$ 1D$D$D$E $1듐UWVU }~t#tF`t;f4tBE 9tJt։ЃuuPD;E r^1_]Ã|wf4uDtE 9uU ^D_]Ðt&D9E ~D9E _fUXE]!cLu}tEp1Ef>wC(EF9Ewg1]u}]ÿ;~tF+};}uF뛋VB9ErE <~;}w뾋F9EvU <e1vW;~s땋VB9EiM f.}%;~v\Mɐt&/1u;}J0UVB9EE < ~~UVB9EM f }}v#~p#}hF|\FDEMNCM8N.M#}MMߐ}F;EM E~FEF|FUT~F4~}}+~~UWVSqùI$PX9lhENE؍Lu썳g}荻uu܉}EԉUUEtJEӋuf>E4$D$tF [^_]Í\G⍃0G렐t&U]nö@uu4$!4$D$B]u]Ð&US3{@E$p[]Í&U]F@uƉ}E4$ED1>F(t H9tF F$t1<$q$ ~VEU]u}]1t&U]^æ?u}} $0'tB~ G$Ft UF ]u}]ÍGӍGfU]&?}}uDt)H4t]u}]1HDD$@$D1tH뢍&'UWVSAÉ>Tu\XǃT0 DHcJNguLutExMP\uXuLY gplUtufĬ[^_]ø?NOt&۸PԸQf˸VĸWf뻸T봸Uf뫸R뤸Sf뛸Z딸[f닸X넸Yfx&n'd(fX)N*D+f8].^$_f`abfc-./=5t&6$4yE 80V 7EzE PЋEE‰UqLuFuπ*Pċ$a42$1U1׹ET$D$ D$E E$m$33PD$F$Y(# # ### ####pDfE\FRGHH>I4Jf(### # # # # #x#b#L#6# $S1BKLMt&f   f~ t fh^!T"fHd>e4!f(7$%f<=f\89f:;ff~t fh@^ATCfH>4f(ff,fU\lMhEU+E\HDB,uB`B,R`UEP9u|EǍ19H4Dx(1)vǃdPX1$-0w$-0RD$F$["D$F$>"# ##PU#)QU}~2}}|E9щEt||Ћx,0UP DUt&W ~|G G D$G$GtP+uwHUPDҋP R1t H}PDtf9~xftBFBFB F DC7CىFEEtPBU\D$ D$$D$d+E0F D$F$dEFEFEF EEEEEFEGE3t&E4t&D$ AD$D$A$-EqD$ FD$D$F$-ECBEE)QB̓UD$ D$$D$_-E&F D$F$EFEFEF EEEEEE0t&oEt&_E t&OE0t&?Et&/${!ED$BD$BЉ$uEAD$AЉD$A$tED$F$D$e!ED$B$D$>!EzD$A$ D$!ESD$F$0D$ E,D$B$PD$ ED$A$@D$ ED$F$`D${ ED$B$pD$T E$\"ExFEg"EZE&NE|v?E<t&/E>t&E=t&BEEEEEEvEt&Et&Et&Et&Et&oEt&_Et&OEt&?Et&/Et&Et&Et&E t&E t&Et&AEEEFEEEEBEBEB EzAEȃ PH@U拕MERUB$nlEE!D$ D$FD$F$EED$ D$BD$B$`EEEE$F*EEy$-EEXA EE>$*&EEB EEEEEEt&Et&Et&Et&Et&Et&Et&oB $ YEKA D$A$/ EFEFEF EB D$B$ EAEAEA EEEEt&D$ BD$D$B$"ED$ AD$D$A$"ESPH@U拕M勍ERD$UED$$赀E0PH@U拕M勍ERЈUED$ D$D$A$zEPH@U拕M勍ERD$D$UED$ $yENPH@U拕M勍ERUED$$BE$UPH@U拕M勍ERUED$$8E$B $% EAEAEA EgFEFEFEFEDBEBEBEBE!A D$A$ EFEFEF EB D$B$ EAEAEA EPH@U拕M勍ERUED$$D$~E[F $ EFEFEF E.BEBEEAEEEFEEEBEEE$enE$QnE$,E$,Efo$NEW$NECNE6f+NE'E$#7E$6E$-E$-E$#-E$,EEwEkE _Et&OE t&?E t&/Et&Et&Et&Et&Et&Et&Et&Et&Et&Et&Et&E t&oE!t&_E't&OE$t&?E&t&/E%t&Et&Et&Et&Et&E(t&A$PEF$!ME$YE$EmD$FD$F$+EGB D$B${EAEAEA E FEFEFEFEBEBEBEBEHRMH@UM勍EED$$D$)yEuFEFEFEFERPH@U拕M勍ERUED$$|E0PH@U拕M勍ERЈUED$ D$D$A$C{E0PH@U拕M勍ERD$UED$ D$A$zEV1E̍EЍEԍE؍'E܍MȉЉUED$$uԉuD$$riEF D$F$EFEFEF EnE b">13$D$$$UWV(EUEEEE׋U EUu091 M؉E܋E؋U܃(^_];}ǃEt|U Mu)ЉEEM׋UM NjEM ЋUE׉E9׉rptaM1{ut4EƋE];}r(U9Uv 11G&1u뾉1$EM9sM1I UWV0UEu} EEEUu}u9UEM9MvuЉ}ԉEЋUԃ0^_]ÍvEEUܸ M܋u})ЋUEEMM ‹EUUMM ЋUMuU9UM)щM̉MM ‹ẺUENutEUEt&1uۉE9ErU9UvUMUЉMME+EMEM9i)U_U]Ít&'UWVSAÉ )t$1ED$E D$E$9uރ [^_]ÐU1S) tD$ED$$i []ÐUStv'ЋuX[]ÐUS[ôY[mempool.cblock->tag == 0xdeadbeefaddr != ((void *)0)mp_free_ptrmp_freemp_reallocRegistry dump: Objects classed by types: Type %d: %s(%d) registry.cregistry != ((void *)0)registry Objects (from name hash table): %s (type %d, ref_count=%d) registry->ht_names != ((void *)0)registry->ht_types != ((void *)0)registry_delete_type: object "%s" (type %d) still referenced (count=%d) Registry: object %s (type %d): negative ref_count. registry_initRed-Black Treehash.cht!=((void *)0)node!=((void *)0)ht->nodes!=((void *)0)hash_table_foreachhash_table_lookup_dcmphash_table_lookuphash_table_removehash_table_inserthash_node_allochash_table_createutils.c%b %d %H:%M:%S%s.%03ld %s: %4.4x: %2.2x "'dyn_sprintf: mallocdyn_sprintf: reallocmemzone_create_file: openmemzone_open_file: open((m_iptr_t)p & (boundary-1)) == 0memzone_create_file: ftruncatem_memalign"%s" error = %d unexpected end of lineunknown errorno errorinsufficient memoryunexpected quotec7200 show_hardware R1Tokens: c7200 show_hardware "R1""c7200" "show_hardware" "R1""c7200" "show_hardware" "R1L t= %d: Test string: [%s] => res=%d, state=%d c7200 show_hardware "R1" hypervisor set_working_dir "C:\Program Files\Dynamips Test"hypervisor # This is a comment set_working_dir "C:\Program Files"plugin_load("%s"): %s initptask_init: unable to create thread. ptask_add: unable to add new task. ptask.cid != 0ptask_addtimer_init: unable to create hash table.timer_init: unable to initialize at least one timer queue.>?456789:;<=  !"#$%&'()*+,-./0123ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ip_listen: %sudp_connect: socket%u.%u.%u.%u%x:%x:%x:%x:%x:%x%x.%x.%x%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x%2.2x%2.2x.%2.2x%2.2x.%2.2x%2.2x       YemrrrwCfnnnv+6>>>FNm]?8Rkw6'dSGnetio_rxl_init: pthread_createNIO %s: receiving a packet of %ld bytes: NIO %s: sending a packet of %lu bytes: netio_rxl_add: unable to create structure. netio_rxl_add: unable to create specific thread. NETIO: unknown descriptor type %u netio_vde_create: bad filenames specified netio_vde_create: insufficient memory netio_vde_create: socket(control)netio_vde_create: connect(control)netio_vde_create: socket(data)netio_unix_create: invalid file size or insufficient memory netio_desc_create_geneth: bad Ethernet device string specified. netio_desc_create_lnxeth: bad Ethernet device string specified. netio_desc_create_udp: insufficient memory netio_desc_create_udp: unable to connect to %s:%d netio_tcp_ser_create: port %s is neither number not service %s netio_tcp_ser_create: bind %s failed %s netio_tcp_ser_create: listen %s failed %s Waiting connection on port %s... netio_tcp_ser_create: accept %s failed %s netio_tcp_cli_create: port %s is neither number not service %s netio_tcp_cli_create: no host %s netio_tcp_cli_create: connect to %s:%s failed %s netio_tap_create: bad TAP device string specified. netio_tap_create: unable to open TAP device %s (%s) Virtual Distributed Ethernet / UML switchGeneric Ethernet device (PCAP)nio create_null %s nio create_gen_eth %s %s nio create_linux_eth %s %s nio create_udp %s %d %s %d nio create_tap %s %s nio create_vde %s %s %s nio create_unix %s %s %s Available NETIO types: * %-10s : %s netio_rxl_thread: selectnetio_vde_create: bind(data)netio_vde_create: write(req)netio_vde_create: read(req)netio_unix: socketnetio_unix: bindnetio_tcp_cli_create: socket Connected netio_tcp_cli_create: socket/dev/net/tunUNIX local socketsLinux/FreeBSD TAP deviceUDP socketstcp_cliTCP clienttcp_serTCP serverLinux Ethernet deviceFIFO (intra-hypervisor)Null devicenio_bridge create %s nio_bridge add_nio %s %s default# netio_bridge_create: unable to register bridge '%s' NETIO_BRIDGE: unable to create virtual fabric table. NETIO_BRIDGE: unable to parse configuration file. NETIO_BRIDGE: invalid number of arguments for UNIX NIO NETIO_BRIDGE: invalid number of arguments for TAP NIO NETIO_BRIDGE: invalid number of arguments for UDP NIO NETIO_BRIDGE: invalid number of arguments for TCP CLI NIO NETIO_BRIDGE: invalid number of arguments for TCP SER NIO NETIO_BRIDGE: invalid number of arguments for Generic Ethernet NIO NETIO_BRIDGE: invalid number of arguments for Linux Ethernet NIO NETIO_BRIDGE: unknown/invalid NETIO type '%s' NETIO_BRIDGE: unable to create NETIO descriptor NETIO_BRIDGE: unable to add NETIO descriptor. 98::y:D::9NIO %s: ending packet capture. NIO %s: unknown link type %s, assuming Ethernet. NIO %s: pcap_open_dead failure NIO %s: pcap_dump_open failure (file %s) NIO %s: capturing to file '%s' freq_dropcaptureatmsw_cfg_create_if: invalid interface description ATMSW: invalid number of arguments for UNIX NIO '%s' ATMSW: invalid number of arguments for UDP NIO '%s' ATMSW: invalid number of arguments for TCP CLI NIO '%s' ATMSW: invalid number of arguments for TCP SER NIO '%s' ATMSW: unknown/invalid NETIO type '%s' ATMSW: unable to create NETIO descriptor of interface %s atmsw create_vpc %s %s %u %s %u atmsw create_vcc %s %s %u %u %s %u %u ATMSW: invalid VPC descriptor. atmsw_create_table: unable to create switch '%s' atmsw_create_vcc: VP switching already exists for VPI=%u ATMSW: invalid VCC descriptor. ATMSW: Unknown statement "%s" (allowed: IF,VP,VC) ATMSW: unable to create virtual fabric table. ATMSW: unable to parse configuration file. atmsw create %s ATM SwitchIFatm_bridge_create: unable to create bridge '%s' frsw_cfg_create_if: invalid interface description FRSW: invalid number of arguments for UNIX NIO '%s' FRSW: invalid number of arguments for UDP NIO '%s' FRSW: invalid number of arguments for TCP CLI NIO '%s' FRSW: invalid number of arguments for TCP SER NIO '%s' FRSW: unknown/invalid NETIO type '%s' FRSW: unable to create NETIO descriptor of interface %s frsw create_vc %s %s %u %s %u FRSW %s: switching for VC %u on IF %s already defined. FRSW: invalid VPC descriptor. frsw_create_table: unable to create switch '%s' unknown LMI report type 0x%x. resynchronization with LMI sequence... FRSW: Unknown statement "%s" (allowed: IF,VC) FRSW: unable to create virtual fabric table. FRSW: unable to parse configuration file. frsw create %s Frame-Relay Switchinvalid LMI packet: invalid LMI item size. unknown LMI item type %u incomplete LMI packet. uethsw create %s ethsw add_nio %s %s ETHSW %seth_switch.cinput_vector != ((void *)0)ACCESSDOT1Qethsw set_access_port %s %s %u ethsw set_dot1q_port %s %s %u ethsw_save_config: unknown port type %u ethsw_iv_access: unknown port type %u ethsw_create: unable to register switch '%s' ethsw_iv_dot1q: unknown port type %u ethsw_receive: unknown port type %u multicast dest, flooding packet. unknown dest, flooding packet. source and dest ports identical, dropping. ETHSW: unable to create virtual fabric table. ETHSW: unable to parse configuration file. ETHSW: invalid number of arguments for UNIX NIO ETHSW: invalid number of arguments for TAP NIO ETHSW: invalid number of arguments for UDP NIO ETHSW: invalid number of arguments for TCP CLI NIO ETHSW: invalid number of arguments for TCP SER NIO ETHSW: invalid number of arguments for Generic Ethernet NIO ETHSW: invalid number of arguments for Linux Ethernet NIO ETHSW: unknown/invalid NETIO type '%s' ETHSW: unable to create NETIO descriptor ETHSW: unable to add NETIO descriptor. ETHSW: invalid access port description. ETHSW: invalid trunk port description. ETHSW: Unknown statement "%s" (allowed: IF,ACCESS,TRUNK) kt Ո? ethsw_forwardethsw_flood-LUnable to load plugin '%s'! dynamips_log.txtShutdown in progress...Shutdown completed.Unhandled signal %d 10:41:26Oct 14 2007Build date: %s %s -HUnable to set log file name! Log file: writing to %s H:l:hN:L:-iInstance ID set to %d. -N-PInvalid platform type '%s' NVRAM size set to %d KB. Idle PC set to 0x%llx. Using a clock divisor of %d. Unable to set log file name. IOS image file: %s dynamips.cvm != ((void *)0)0.2.8-RC2-x862007101400exec-areaidle-pctimer-itvvm-debugiomem-sizesparse-memPlugin error: no argument specified. Usage: %s [options] Available options: -H [:] : Run in hypervisor mode -P : Platform to emulate (7200, 3600, 2691, 3725, 3745, 2600 or 1700) (default: 7200) -l : Set logging file (default is %s) -j : Disable the JIT compiler, very slow --exec-area : Set the exec area size (default: %d Mb) --idle-pc : Set the idle PC (default: disabled) --timer-itv : Timer IRQ interval check (default: %u) -i : Set instance ID -r : Set the virtual RAM size (default: %u Mb) -o : Set the virtual ROM size (default: %u Mb) -n : Set the NVRAM size (default: %d Kb) -c : Set the configuration register (default: 0x%04x) -m : Set the MAC address of the chassis (default: automatically generated) -C : Import an IOS configuration file into NVRAM -X : Do not use a file to simulate RAM (faster) -G : Use a ghost file to simulate RAM -g : Generate a ghost RAM file --sparse-mem : Use sparse memory -R : Load an alternate ROM (default: embedded) -k : Set the clock divisor (default: %d) -T : Console is on TCP -U : Console in on serial interface (default is on the terminal) -A : AUX is on TCP -B : AUX is on serial interface (default is no AUX port) --disk0 : Set PCMCIA ATA disk0: size (default: %u Mb) --disk1 : Set PCMCIA ATA disk1: size (default: %u Mb) -a : Virtual ATM switch configuration file -f : Virtual Frame-Relay switch configuration file -E : Virtual Ethernet switch configuration file -b : Virtual bridge configuration file -e : Show network device list of the host machine format: "device{:baudrate{:databits{:parity{:stopbits{:hwflow}}}}}}" format: "slot:sub_slot:pa_driver" format: "slot:port:netio_type{:netio_parameters}" format: "slot:sub_slot:nm_driver" format: "slot:port:netio_type{:netio_parameters}" format: "slot:wic_driver" format: "slot:port:netio_type{:netio_parameters}" Error: Cannot acquire instance handle. Cisco Router Simulation Platform (version %s) Copyright (c) 2005-2007 Christophe Fillot.Unable to set hypervisor IP address! Error: option '%s': no argument specified. C7200: unable to create instance! Virtual RAM size set to %d MB. Virtual ROM size set to %d MB. PCMCIA ATA disk0 size set to %u MB. PCMCIA ATA disk1 size set to %u MB. Config. Register set to 0x%x. Invalid Clock Divisor specified! Invalid Console serial interface descriptor! Invalid AUX serial interface descriptor! r:o:n:c:m:l:C:i:jt:p:s:k:T:U:A:B:a:f:E:b:S:R:M:eXP:N:G:g:L:Please specify an IOS image filename Unable to create log file (%s). Unable to initialize router instance. 8Ĕ``,Е1`T`і E[Imain P{ j p 0F p  '  CVinsn_lookup.carrayarray->cbm_hasharray->id2cbmeqclrfctilt_%s_%srbiltwbrfct->nr_eqid < rfct->nr_elementsILT: loaded table "%s" from cache. ilt_createilt_phase_0rfc_phase_0cbm_createrfc_alloc_arraycbm_get_eqclasscbm_duplicaterfc_phase_jVM%u: vm_bind_device: device table full. vm_platform_register: platform '%s' already exists. vm_platform_register: unable to record platform. trying to shutdown an inactive VM. shutdown procedure completed. unloaded ghost image %s (fd=%d) at addr=%p (size=0x%llx) loaded ghost image %s (fd=%d) at addr=%p (size=0x%llx) Unable to load ghost image %s Unable to create lock file "%s". An emulator instance (PID %s) is already running with identifier %u. If this is not the case, please erase file "%s". vm_mmap_create_file: unable to open file '%s' (%s) vm_mmap_open_file: unable to open file '%s' (%s) VM %s: unable to create log file '%s' VM %s: unable to create new instance! VM %s: unable to store instance name! VM: Unable to store instance '%s' in registry! VM %s: unable to create instance! vm create %s %u %s vm set_ios %s %s vm set_ram %s %u vm set_nvram %s %u vm set_ram_mmap %s %u vm set_clock_divisor %s %u vm set_conf_reg %s 0x%4.4x vm set_con_tcp_port %s %d vm set_aux_tcp_port %s %d Console portAUX portVM%s '%s': %sunable to create file '%s' %s_i%u_%s%s_%s_%sfilename != ((void *)0)VM "%s" (%u) object list: - %-15s [data=%p] Shutdown of object "%s" VM_OBJECTshutdown procedure engaged. removing PCI busses. deleting VTTY. deleting system CPUs. (*img)->ref_count > 0GHOSTios_cfg.txt%ld%ld rommon_varsVM %s: unknown platform '%s' vm_ghost_image_releasevm_build_filenameCPU type %u is not supported yet cpu_create: unable to create thread for CPU%u Halting CPU (old state=%u)... Starting CPU (old state=%u)... cpu_group_add: CPU%u already present in group. CPU%u: %sCPU_STATEjit_op.cop->ob_size_index < 8op != ((void *)0)op->ob_size_index == size_indexjit_op_freejit_op_getload_elf_image: openLoading ELF file '%s'... load_elf_image: fdopenELF entry point: 0x%x statmips64_save_state: fopenpc: %16.16llx lo: %16.16llx %s: %16.16llx fpu%d: %16.16llx tlb%d_mask: %16.16llx tlb%d_hi: %16.16llx tlb%d_lo0: %16.16llx tlb%d_lo1: %16.16llx 0x%16.16llx: 0x%8.8x XXXXXXXXXX MIPS64 Registers: Instruction: %s CP0 Registers: Device access count: %llu BREAKPOINTDone. Suggested idling PC: 0x%llx (count=%u) 0x%16.16llx (%3u) load_sym_file: fopen%llx %c %smips64_restore_state: fopenfputlbzrv0v1a0a1a2a3t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9gpspfpload_elf_image: library out of date load_elf_image: elf_begin: %s load_elf_image: invalid ELF file * Adding section at virtual address 0x%8.8llx (len=0x%8.8lx) load_elf_image: invalid load address 0x%llx ELF loading skipped, using a ghost RAM file.Loading RAW file '%s' at virtual address 0x%llx (size=%lu) load_raw_image: invalid load address 0x%llx MIPS Stack Dump at 0x%16.16llx: %s ($%2d) = 0x%16.16llx %s ($%2d) = 0x%16.16llx lo = 0x%16.16llx, hi = 0x%16.16llx pc = 0x%16.16llx, ll_bit = %u %-10s ($%2d) = 0x%16.16llx %-10s ($%2d) = 0x%16.16llx IRQ count: %llu, IRQ false positives: %llu, IRQ Pending: %u Timer IRQ count: %llu, pending: %u, timer drift: %u MIPS64: cpu %p jumping to address 0... Virtual breakpoint reached at PC=0x%llx [[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]] You already use an idle PC, using the calibration would give incorrect results. Please wait while gathering statistics...Restart the emulator with "--idle-pc=0x%llx" (for example) Done. No suggestion for idling PCCPU%u: Unable to create symbol tree. MIPS64: TRAP exception, CPU=%p MIPS64: BREAK instruction (code=%u)  CPU%u: MTS%d statistics: %u/%u valid hash entries. MTSdev_access_fast %4u: vaddr=0x%8.8llx, paddr=0x%8.8llx, hpa=%p Total lookups: %llu, misses: %llu, efficiency: %g%% read access to undefined address 0x%llx at pc=0x%llx (size=%u) write access to undefined address 0x%llx at pc=0x%llx, value=0x%8.8llx (size=%u) TLB exception for address 0x%llx at pc=0x%llx (%s access, size=%u) AE exception for address 0x%llx at pc=0x%llx (%s access) null handler (dev_id=%u,offset=0x%x) mts_set_addr_mode: internal error (addr_mode=%u) _BTLB dump: %2d: vaddr=0x%8.8llx (global) (asid 0x%2.2llx) p0=0x%9.9llx(invalid) %c p1=%uMB%uKBCP0_S1indexrandomentry_lo0entry_lo1pagemaskwiredbadvaddrcountentry_hicomparecausepridll_addrwatch_lowatch_hixcontextcp0_r21cp0_r22cp0_r23cp0_r24cp0_r25ecccache_errtag_lotag_hierr_epccp0_r31 %2d: mask=0x%16.16llx hi=0x%16.16llx lo0=0x%16.16llx lo1=0x%16.16llx trying to set unknown register %u (val=0x%x) trying to read unknown register %u  |PPPPPPD0NNDDDsaaD00,#]ююBlock 0x%8.8llx: trying to record an invalid PC (0x%8.8llx) - mips_trans_pos=%d. Block 0x%8.8llx: unable to create patch table. mips64_jit_init: unable to create exec area (size %lu) mips64_jit_init: unable to create exec page array CPU%u: carved JIT exec zone of %lu Mb into %lu pages of %u Kb. VM '%s': unable to create Timer IRQ thread for CPU%u. flushing data structures (compiled pages=%u) %% No memory map for code execution at 0x%llx %% Unable to create instruction block for vaddr=0x%llx insn_page_compile: unable to create JIT block. insn_page_compile: unable to create JIT mappings. insn_page_compile: unable to fetch instruction. Block 0x%llx: too many JIT chunks. VM '%s': unable to compile block for CPU%u PC=0x%llx mips64_jit_tcb_run: Invalid PC 0x%llx. mips64_jit.ctag != ((void *)0)tagmips64jJITpartial JIT flush (count=%u) PC=0, halting CPU. balbeqbeqlbgezbgezlbgezalbgezallbgtzbgtzlblezblezlbltzbltzlbltzalbltzallbnebnelmips64_jit_tcb_apply_patchesmips64_jit_fetch_and_emitmips64_jit_is_delay_slotMIPS64: unknown opcode 0x%8.8x at pc = 0x%llx %llu instructions executed since startup. SLOW_EXEC%8.8x (unknown)[unknown]%%-%lus%8.8x %s%8.8x %s %s,%d(%s)%8.8x %s %s,%s,%s%8.8x %s %s,%s,0x%x%8.8x %s %s,%s,%d%8.8x %s %s,%s,0x%llx%8.8x %s %s,0x%llx%8.8x %s 0x%llx%8.8x %s %s%8.8x %s %s,%s%8.8x %s %s,0x%x%8.8x %s %s,$%d%8.8x %s (TO DEFINE - %d)0x%llx: %s * %-10s : %10llu mips64emovebeqzbnezaddaddiandibreakcachecfc0ctc0daddiudaddudivdivudmfc0dmfc1dmtc0dmtc1dslldsll32dsllvdsradsra32dsravdsrldsrl32dsrlvdsubueretjaljalrjrlbuldc1ldlldrlhlhuluilwllwrlwumfc0_1mfhimflomthimtlomulmultmultunopprefprefiscsdsdc1sdlsdrsltsltisltiusltusubswlswrsyscallteqteqitlbptlbrtlbwitlbwrxori:`R.׶;Ƶh%ʹpPowerPC Registers: ia = 0x%8.8x, lr = 0x%8.8x yesno 0x%8.8x (%3u) PowerPC MMU Registers: - IBAT Registers: - DBAT Registers: - Segment Registers: SR[%d] = 0x%8.8x - SDR1: 0x%8.8x * Adding section at virtual address 0x%8.8x (len=0x%8.8lx) load_elf_image: invalid load address 0x%x Loading RAW file '%s' at virtual address 0x%8.8x (size=%lu) load_raw_image: invalid load address 0x%8.8x $%2d = 0x%8.8x $%2d = 0x%8.8x $%2d = 0x%8.8x $%2d = 0x%8.8x cr = 0x%8.8x, msr = 0x%8.8x, xer = 0x%8.8x, dec = 0x%8.8x sprg[0] = 0x%8.8x, sprg[1] = 0x%8.8x sprg[2] = 0x%8.8x, sprg[3] = 0x%8.8x IRQ count: %llu, IRQ false positives: %llu, IRQ Pending: %u, IRQ Check: %s Virtual breakpoint reached at IA=0x%8.8x [[[ Virtual Breakpoint reached at IA=0x%8.8x LR=0x%8.8x]]] Done. No suggestion for idling PC, dumping the full table: BAT[%d] = 0x%8.8x 0x%8.8x %2d: hi=0x%8.8x lo=0x%8.8x tid=0x%2.2x ppc32_set_sdr1: unable to find haddr for SDR1=0x%8.8x %4u: vaddr=0x%8.8x, paddr=0x%8.8x, hpa=%p %u/%u valid hash entries for icache. %u/%u valid hash entries for dcache. Total lookups: %llu, misses: %llu, efficiency: %g%% MMU exception for address 0x%8.8x at ia=0x%8.8x (%s access, size=%u) read access to undefined address 0x%8.8x at ia=0x%8.8x (size=%u) write access to undefined address 0x%8.8x at ia=0x%8.8x, value=0x%8.8llx (size=%u) CPU%u: MTS statistics: Instruction cache:Data cache:ppc32_alloc_hreg_forced: trying to force allocation of hreg %d (insn %s) Block 0x%8.8x: trying to record an invalid IA (0x%8.8x) Block 0x%8.8x: unable to create patch table. ppc32_jit_init: unable to create exec area (size %lu) ppc32_jit_init: unable to create exec page array ppc32_get_free_hreg: unable to find free reg for insn %s Block 0x%8.8x: too many JIT chunks. Block 0x%8.8x: null dst for patch! insn_page_compile: unable to recompile page. %% No memory map for code execution at 0x%8.8x %% Unable to create instruction block for vaddr=0x%8.8x insn_page_compile: unable to compile page. VM '%s': unable to compile block for CPU%u IA=0x%8.8x ppc32_jit_tcb_run: Invalid IA 0x%8.8x. ppc32_jit.cppc32jIA=0, halting CPU. UU2VW2V2W(UWWVXXXYXX9YYYyYXXXYrXppc32_jit_tcb_apply_patchesppc32_jit_fetch_and_emitPPC32: unknown opcode 0x%8.8x at ia = 0x%x ppc32emflrmtlrmfctrmtctradd.addoaddo.addcaddc.addcoaddco.addeadde.addeoaddeo.addicaddic.addisaddmeaddme.addzeaddze.andc.andi.andis.bablabcbcabclbclabclrbclrlbcctrbcctrlcmpcmpicmplcmplicntlzwcrandcrandccreqvcrnandcrnorcrorcrorccrxordcbfdcbidcbtdcbstdivwdivw.divwudivwu.eieioextsbextsb.extshextsh.icbiisynclbzlbzulbzuxlbzxlhalhaulhauxlhaxlhzlhzulhzuxlhzxlmwlwbrxlwzlwzulwzuxlwzxlwarxlfdlfdulfduxlfdxlswilswxmcrfmfcrmfmsrmfsprmfsrmfsrinmftblmftbumtcrfmtmsrmtsprmtsrmulhwmulhw.mulhwumulhwu.mullimullwmullw.mullwomullwo.nand.negneg.negonego.nor.orc.rfirlwimirlwimi.rlwinmrlwinm.rlwnmrlwnm.slwslw.srawsrawisrawi.srwsrw.stbstbustbuxstbxsthsthusthuxsthxstmwstwstwustwuxstwxstwbrxstwcx.stfdstfdustfduxstfdxstswistswxsubfsubf.subfosubfo.subfcsubfc.subfesubficsubfzesubfze.tlbiatlbietlbsynctwixor.xorisdccciicccimfdcrmtdcrtlbretlbwe PPC32_VMTEST '%s': stopping simulation. unable to sync with system CPUs. unable to initialize the platform hardware. unable to load alternate ROM '%s', fallback to embedded ROM. failed to load ELF image '%s'. PPC32_VMTEST '%s': starting simulation (CPU0 IA=0x%8.8x), JIT %sabled. starting instance (CPU0 IA=0x%8.8x,JIT %s) stopping simulation. PPC32_VMTEST_STOPSystem CPUunable to create CPU0! romram_aliasoffPPC32_VMTEST_BOOTppc32_testPPC32_VMTESTPPC32_TESTXXXXXXXXread 0x%8.8llx: 0x%8.8x physmem_dumpCPU%u: pc=0x%8.8llx, vaddr=0x%8.8llx, size=%u, type=%s, data=%s unable to transfer from 0x%llx to 0x%llx device.cptrptr_newThis is not a sparse device.No sparse map. VM "%s" (%u) Device list: DEVICEMMAPdev_create_ghost_ram: mmapdev_create_ram: mmapdummy_console %-18s: 0x%12.12llx (0x%8.8x) Sparse information for device '%s': %u dirty pages on a total of %u pages. dev_create: insufficient memory to create device '%s'. Removal of device %s, fd=%d, host_addr=0x%llx, flags=%d unmapping of device '%s', fd=%d, host_addr=0x%llx, len=0x%x VM%u: dev_create_ram_alias: unknown device '%s'. VM%u: dev_create_ram_alias: unable to create new device %s. dev_sparse_get_host_addrEEPROM %s(%d): check_clk: check_bit(old,new,select_bit) [%8.8x, %8.8x, %d (mask = %8.8x)] = %d EEPROM %s(%d): check_cs: check_bit(old,new,select_bit) [%8.8x, %8.8x, %d (mask = %8.8x)] = %d Dumping EEPROM contents: Field 0x%2.2x: C6K-CHASSIS-6509C6K-SUP-SUP1A-2GEC6K-EARL-PFC1C6K-POWER-1000WC6K-VTTC6K-LC-WS-X6248WIC-1TWIC-2TWIC-1BWIC-4ESWWIC-1ENETPA-FE-TXPA-2FE-TXPA-GEPA-4EPA-8EPA-4T+PA-8TPA-A1PA-POS-OC3PA-4BPA-MC-8TE1NM-1ENM-4ENM-1FE-TXNM-16ESWNM-4TNM-2E2WNM-2WNM-1A-OC3MMNM-NAMNM-CIDS(:HX`pw~ @8 @@ @`@@`@  @`@+@2@WAN Interface Card (WIC)UnknownPort Adapter (PA)Network Module (NM)Available %s %s drivers: (NOT WORKING) * %s %s Invalid wic_id %u (slot %u) unable to find NIO '%s'. %s-i%u/%u/%uunknown NETIO type '%s' slot %u/%u is still active cisco_card.cdrv_array != ((void *)0)%s(%u)unable to initialize slot %u cisco_card_set_eeprom: no memory (eeprom=%p). vm add_slot_binding %s %u %u %s vm add_nio_binding %s %u %u %s unable to shutdown card type '%s' (slot %u/%u) unable to create NIO binding for interface %u/%u. a NIO already exists for interface %u/%u. unable to parse NIO description '%s'. invalid number of arguments for UNIX NIO '%s' invalid number of arguments for VDE NIO '%s' invalid number of arguments for TAP NIO '%s' invalid number of arguments for UDP NIO '%s' invalid number of arguments for TCP CLI NIO '%s' invalid number of arguments for TCP SER NIO '%s' invalid number of arguments for Linux Eth NIO '%s' invalid number of arguments for Generic Eth NIO '%s' unable to create NETIO descriptor for slot %u unable to add NETIO binding for slot %u sub-slot %u/%u is still active a card already exists in slot %u/%u (%s) no sub-slot possible for slot %u/%u. no sub-slot info for slot %u/%u. unknown card type '%s' for slot %u/%u. unable to parse slot description '%s'. unable to allocate device name. unable to initialize card type '%s' (id %u) :b vm_slot_add_binding%2d, IRQ: %d PCI Bus "%s" Device list: %-18s: ID %4.4x:%4.4x, Bus %s, Dev. %2d, Func. %2dpci_bridge_add: unable to create new PCI bridge. pci_bus_create: unable to create PCI info. pci_dev_add: bus %s, device %d, function %d already registered (device '%s'). pci_dev_add: unable to create new PCI device. PCI bridge %d,%d,%d -> pri: %2.2u, sec: %2.2u, sub: %2.2u read request at pc=0x%llx: bus=%d,device=%d,function=%d,reg=0x%2.2x write request (data=0x%8.8x) at pc=0x%llx: bus=%d,device=%d,function=%d,reg=0x%2.2x read request for unknown device at pc=0x%llx (bus=%d,device=%d,function=%d,reg=0x%2.2x). write request (data=0x%8.8x) for unknown device at pc=0x%llx (bus=%d,device=%d,function=%d,reg=0x%2.2x). pci_io_add: unable to create a new device. PCI_IO: out of memory pci_ioZERO: unable to create device. BSWAP: unable to create device. vtty: pthread_create%s: put char %d failed (%s) VTTY%s: closing FD %d %s: closing accept FD %d vtty_tcp_waitcon: socketvtty_tcp_waitcon: bindvtty_tcp_waitcon: listenVTTY: open failed error: tcgetattr failed error: unsupported baudrate error: unsupported databits error: unsupported parity error: unsupported stopbits error: tcflush failed error: tcsetattr failed VTTY: setup failed tty_create: bad vtty type %d vtty_thread: select %-15s: %s, FD %d read from vtty failedvtty_read: bad vtty type %d Instance %s (ID %d) ]0;Dynamips(%i): %s, %s%s: put char 0x%x failed (%s) vtty_put_char: bad vtty type %d VTTY: unable to create new virtual tty. vtty_tcp_waitcon: setsockopt(SO_REUSEADDR)vtty_tcp_waitcon: setsockopt(SO_KEEPALIVE)%s: waiting connection on tcp port %d (FD %d) vtty_parse_serial_option: invalid string vtty_parse_serial_option: unable to copy string vtty_tcp_conn_accept: accept on port %d failed %s %s is now connected (accept_fd=%d,conn_fd=%d) Connected to Dynamips VM "%s" (ID %u, type %s) - %s CPU0: %u JIT compiled pages [Exec Area Pages: %lu/%lu] o - Show the VM object list d - Show the device list r - Dump CPU registers t - Dump MMU information z - Dump MMU information (raw mode) m - Dump the latest memory accesses s - Suspend CPU emulation u - Resume CPU emulation q - Quit the emulator k - Reboot the virtual machine b - Show info about JIT compiled pages l - MTS cache statistics c - Write IOS configuration to disk j - Non-JIT mode statistics i - Determine an idling pointer counter x - Experimentations (can crash the box!) ^] - Send ^] Other - This helpG>HHmii_phy < 32d->mii_reg < 32MII impossible state %s (DEC21140): unable to create PCI device. %s (DEC21140): unable to create device. invalid access to offset 0x%x unicast MAC address: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x dec21140_handle_txring: descriptor not owned!  * 9 H                           ! X h h h h h h h h h h h h h h h h mii_reg_writeinvalid software style %u! %s (AM79C971): out of memory CSR0 = 0x%4.4x sending packet of %u bytes %s (AM79C971): unable to create PCI device. %s (AM79C971): unable to create device. trying to fetch init block at address 0... fetching init block at address 0x%8.8x rx_ring = 0x%8.8x (%u), tx_ring = 0x%8.8x (%u) am79c971_handle_txring: 1st desc: tmd[0]=0x%x, tmd[1]=0x%x, tmd[2]=0x%x, tmd[3]=0x%x am79c971_handle_txring: loop: tmd[0]=0x%x, tmd[1]=0x%x, tmd[2]=0x%x, tmd[3]=0x%x am79c971_handle_txring: UNDERFLOW! receiving a packet of %d bytes am79c971_handle_rxring: i=%d, addr=0x%8.8x: rmd[0]=0x%x, rmd[1]=0x%x, rmd[2]=0x%x, rmd[3]=0x%x am79c971_handle_rxring: storing %u bytes at 0x%8.8x %s (i8254x): out of memory dev_i8254x.cMII: impossible state %u! %s (i8254x): unable to create PCI device. %s (i8254x): unable to create device. O O eQ ~Q Q Q Q Q Q Q Q R R R R R P P N P P P P P P P P P P P P P P P P P P ^Q #Q *Q IQ 1Q 8Q IQ IQ IQ IQ IQ IQ IQ IQ IQ IQ BQ mii_reg_write%s (i8255x): out of memory microcode loaded %s (i8255x): unable to create PCI device. %s (i8255x): unable to create device. iaddr set to: %2.2x%2.2x.%2.2x%2.2x.%2.2x%2.2x unsupported CB command 0x%2.2x (cb_addr=0x%8.8x) unsupported CU command 0x%2.2x unsupported RU command 0x%2.2x read access to unknown offset=0x%x, pc=0x%llx (size=%u) write access to unknown offset=0x%x, pc=0x%llx, val=0x%llx (size=%u) U NV  W U NW GX .[ \ [ PZ [ PZ PZ PZ PZ PZ PZ PZ PZ PZ PZ PZ E[ Y] ]^ \ ] z^ ^ ] ] f_ }_ _ _ I_ _ _ I_ I_ I_ I_ I_ I_ I_ I_ I_ I_ _ channel %u: unknown value for CRC ctrl reg 0x%4.4x channel %u: CRC size set to 0x%4.4x %s (Mueslix): unable to create PCI device. %s (Mueslix): unable to create device. mueslix_handle_txring: descriptor not owned! %s (Mueslix): out of memory channel %u disabled channel %u enabled unknown command 0x%5x %s (WIC-SERIAL): out of memory %s (WIC): unable to create device. %s (WIC-SERIAL): unknown model %u write to unknown addr 0x%x, value=0x%llx, pc=0x%llx (size=%u) 3640PCI bus #0PCI bus #1unable to create PCI data. gt64120NM Slot %dgt64010c3600 set_chassis %s %s NVRAM file too small C3600_STOPC3600 instance '%s' (id %d): VM Status : %d RAM size : %u Mb NVRAM size : %u Kb Chassis : %s IOS image : %s no Cisco IOS image defined.unable to create CPU! no chassis defined. bootflashio_fpgaC3600_BOOTNM Slots 0,2NM Slots 1,3unknown chassis type '%s'. Leopard-2FEC3620 MainboardC3640 MainboardC3660 Backplanec3600C360036203660 -t : Select Chassis type (default: "%s") --iomem-size : IO memory (in percents, default: %u) -p : Define a Network Module -s : Bind a Network IO interface to a Network Module Available C3600 chassis drivers:unable to find IOS magic numbers (0x%x,0x%x)! unable to allocate config buffer (%u bytes) C3600 '%s': stopping simulation. failed to load Cisco IOS image '%s'. C3600 '%s': starting simulation (CPU0 PC=0x%llx), JIT %sabled. starting instance (CPU0 PC=0x%llx,idle_pc=0x%llx,JIT %s) unable to parse MAC address '%s'. c3600_burn_mac_addr: unable to handle EEPROM version %u unable to change chassis type when online. unable to set chassis EEPROM '%s'. C3600 '%s': Unable to create new instance! IO_FPGA: out of memory IO_FPGAMainboard EEPROMNM EEPROMC3600 '%s': invalid chassis ID %d 0O : Select NPE type (default: "%s") -M : Select Midplane ("std" or "vxr") -p : Define a Port Adapter -s : Bind a Network IO interface to a Port Adapter invalid configuration size (0x%x) C7200 '%s': stopping simulation. %u is not a valid RAM size for this NPE. Fallback to %u Mb. incomplete initialization (no memory?) C7200 '%s': starting simulation (CPU0 PC=0x%llx), JIT %sabled. console managed by NPE-G2 board C7200P '%s': starting simulation (CPU0 IA=0x%8.8x), JIT %sabled. starting instance (CPU0 IA=0x%8.8x,idle_pc=0x%8.8x,JIT %s) c7200_burn_mac_addr: unable to handle EEPROM version %u unable to change NPE type when online. unknown NPE "%s" (internal error)! unable to find NPE '%s' EEPROM! trying to shut down empty slot %u. unable to change Midplane type when online. unable to set midplane EEPROM. C7200 '%s': Unable to create new instance! no PEM EEPROM found for NPE type "%s"! console managed by I/O board temp_sensors: CMD = 0x%x p1 = 0x%8.8x CPU and Midplane EEPROMPEM (NPE-B) EEPROMtemp_sensors: IOS sent command 0x%x.             Z_,_Z<_MP_FPGA: out of memory MP_FPGAreading 0x78 at pc=0x%llx PA Bays (Group #1) EEPROMPA Bays (Group #2) EEPROMreading reg 0x%x at pc=0x%llx, val=0x%x writing reg 0x%x at pc=0x%llx (data=0x%llx) writing reg 0x78 at pc=0x%llx (data=0x%llx) read from addr 0x%x, pc=0x%llx write to addr 0x%x, value=0x%llx, pc=0x%llx     I I I I     I I I I  I I I I I I I  I I I I I I I I I I I I I I I  I I I I I I I  I I I I I I I  I I I I I I I  I I I I I I I  I I I I I I I Y I I I I I I I 3 I I I I I I I / I I I I I I I  I I  _ f0fPf`f_@fpff  dev_c7200_sram_init (%s): out of memory dev_c7200_sram_init: unable to create '%s' file. dev_c7200_sram_init: unable to create alias name. dev_c7200_sram_init: unable to create alias device. dev_c7200_sram_init: unable to create BS name. dev_c7200_sram_init: unable to create BS device. %s_alias%s_bswap%s: out of memory C7200-IO-2FEC7200-IO-GE-Ecannot put IOCARD in PA bay %u! gh@gi@CUi@AF IB0B00000000 7C02-0/I-OF2/EE@AF IB0B00000000 7C02-0/I-OF2/EE IP(%s_RX%s_TX%s_CSCRC size set to 0x%4.4x unknown value 0x%4.4llx written in ctrl_reg1 pos_oc3_handle_txring: descriptor not owned! 2 `2 `2 `2 2 `2 `2 `2 p2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 `2 2 M32: Fetched channel %u M32 Channel %u: Status : 0x%8.8x FRDA : 0x%8.8x FTDA : 0x%8.8x ITBS : 0x%8.8x %s: unable to create device. read PCI register 0x%x M32: data_ptr=0x%x, len=%u UNSUPPORTED(1)!!!!UNSUPPORTED(2)!!!!UNSUPPORTED(8)!!!!UNSUPPORTED (size=%u)!!! %s: unable to create PCI device. write 0x%x to PCI register 0x%x M32: TX scanner for channel %u (tx_current=0x%8.8x) M32: params=0x%8.8x, next=0x%8.8x. M32: branching on next descriptor 0x%x read access to offset = 0x%x, pc = 0x%llx (op_size=%u) write access to vaddr = 0x%x, pc = 0x%llx, val = 0x%llx (op_size=%u) +B @ @ @ @ @ @ @ wA @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ B B @ wA @ @ @ @ @ @ @ @ @ @ @ @ gB @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ IB @ @ @ A @ @ @ @ @ @ @ @ @ @ @ A  --iomem-size : IO memory (in percents, default: %u) -p : Define a Network Module -s : Bind a Network IO interface to a Network Module C2691 '%s': stopping simulation. C2691 '%s': Unable to create new instance! c2691_burn_mac_addr: unable to handle EEPROM version %u C2691 '%s': starting simulation (CPU0 PC=0x%llx), JIT %sabled. C2691_STOPGT96100-FEC2691 instance '%s' (id %d): gt96100slot0slot1C2691_BOOTC2691 Backplanec2691C26917[ FZ FZ FZ \ FZ Z FZ FZ FZ Z FZ FZ FZ FZ FZ FZ FZ [ FZ FZ FZ 0Z FZ [[ FZ [ FZ FZ FZ Z FZ Z FZ v[ FZ FZ FZ FZ FZ [ FZ FZ FZ  \ FZ $\ FZ FZ FZ m\ FZ Y FZ \ FZ FZ FZ Z FZ Z 0O : IO memory (in percents, default: %u) -t : Select Chassis type -p : Define a WIC Module -s : Bind a Network IO interface to a WIC Available C1700 chassis drivers: C1700 '%s': stopping simulation. C1700 '%s': starting simulation (CPU0 IA=0x%8.8x), JIT %sabled. C1700 '%s': Unable to create new instance! C1700_STOPc1700 set_chassis %s %s C1700 instance '%s' (id %d): C1700_BOOT17201710C1710-MB-1FE-1EC1700-MB-1ETH1721175017511760c1700C17000Odev_c1700_mb_eth_init: bad slot %u specified. -s : Bind a Network IO interface to a Port Adapter C6MSFC1 '%s': stopping simulation. C6MFC1 '%s': Unable to create new instance! C6MSFC1 instance '%s' (id %d): C6MSFC1 '%s': starting simulation (CPU0 PC=0x%llx), JIT %sabled. C6MSFC1_STOPC6MSFC1_EOBCC6MSFC1_IBCPCI Bus 0PCI Bus 1C6MSFC1_BOOTc6msfc1C6MSFC1Z setting NetIRQ for slot %u port %u reading reg 0x%x at pc=0x%llx (size=%u) writing reg 0x%x at pc=0x%llx, data=0x%llx (size=%u) read from unknown addr 0x%x, pc=0x%llx write to unknown addr 0x%x, value=0x%llx, pc=0x%llx clearing NetIRQ for slot %u port %u # D" D" D" D" D" D" D" # D" D" D" D" D" D" D" # D" D" D" D" D" D" D" # D" D" # C6SUP1 '%s': Unable to create new instance! C6SUP1 instance '%s' (id %d): C6SUP1 '%s': starting simulation (CPU0 PC=0x%llx), JIT %sabled. C6SUP1 '%s': stopping simulation. C6SUP1_EOBCC6SUP1_IBCagramC6SUP1_BOOTC6SUP1_STOPc6sup1C6SUP1Backplane EEPROMsSupervisor EEPROMsSlot EEPROMsreading reg 0x%x at pc=0x%llx, ra=0x%llx (size=%u) writing reg 0x%x at pc=0x%llx, ra=0x%llx data=0x%llx (size=%u) slot control: unknown func 0x%2.2x write to unknown addr 0x%x, value=0x%llx, pc=0x%llx (op_size=%u)  \l|̡ܡ      ARL count = %u %s: physical ports: %-10s: VLAN %u, Trunk Group %u %-10s: %s (/T%sUT) %s: dumping VLAN table: VLAN %4u: %s: trunk ports: Trunk %d: %s Mirroring status: disabled. enabled. Dest port: none set. Ingress Ports: Egress Ports: %s: dumping registers: 0x%8.8x: 0x%8.8x Fa%u/%ddev_nm_16esw.centrydst_port != ((void *)0)trunk != ((void *)0)arl_entry != ((void *)0)ttr_entry != ((void *)0)src_port != ((void *)0)arlcnt0arlcnt1arlcnt2marl0marl1marl2ptable0ptable1ptable2vtable0vtable1vtable2ttr0ttr1ttr2tbmap0tbmap1tbmap2%s: dumping bitmaps of the port table: BCM5600 registers are mapped at 0x%x unknown opcode 0x%8.8x (cmd=0x%8.8x) BCM5600: unable to create table '%s' bcm5600_handle_tx_pkt: untagged packet ? -------------------------------------------------------------------------------------------- Unspported feature: please post your current configuration on http://www.ipflow.utc.fr/blog/ --------------------------------------------------------------------------------------------no free entries in ARL table! ^ K\ ._ K\ |_ K\ ] K\ D^ K\ \ K\ K\ K\ K\ K\ K\ K\ \ rb ,b bb  b b a       bcm5600_src_mac_learningbcm5600_dst_mac_lookupbcm5600_trunk_egress_portbcm5600_forward_pktbcm5600_arl_agerti1570_acquire_rx_buffer: no free buffer available. %s: unable to create PCI device TI1570. %s: unable to create PCI device PLX 9060ES. %s: unable to create control memory. ti1570_handle_rx_cell: received cell with unknown VPI %u (VCI=%u) ti1570_handle_rx_cell: out-of-range VCI %u (VPI=%u,vci_mask=%u,vci_max=%u) ti1570_handle_rx_cell: inconsistency in RX VPI/VCI table, VPI/VCI=%u/u, bptr=0x%x ti1570_handle_rx_cell: no RX DMA table entry found! ti1570_store_rx_cell: EOP processing, not handled yet. ti1570_update_rx_cring: RX freeze... ti1570_scan_tx_dma_entry: PSR entry with OWN bit set but buffer without RDY bit set. ti1570_add_tx_padding: trying to add too large padding (avail: 0x%x, pad: 0x%x) ti1570_scan_tx_dma_entry: invalid AAL-type reset issued. invalid RX cell size (%ld) %s_ssram%s_plxDOORBELL: 0x%x read access to offset = 0x%x, pc = 0x%llx (size=%u) write access to vaddr = 0x%x, pc = 0x%llx, val = 0x%llx (size=%u) SB1: out of memory sb1_sysctrlSB1SB1_IO: out of memory sb1_ioSB1_IOSB1_PCI: unable to create device. sb1_pci_cfgHT bus #1sb1_ht_cfgSIGPIPE received.-%3d%sunable to find VM '%s'VM '%s' is not a VM type %sunable to find object '%s'fopen: %schdir: %sarg %d (len %u): "%s"%s (min/max args: %d/%d)unknown module '%s'Parse error: %sNo memoryUnknown module '%s'Unknown command '%s'hypervisorhypervisor.cmodule != ((void *)0)hypervisor_tcp_server: selecthypervisor_tcp_server: acceptversionparser_testmodule_listcmd_listworking_dirsave_configresetclosestopHypervisor: module '%s' already exists. Hypervisor: unable to register new module. At least a module and a command must be specifiedBad number of parameters (%d with min/max=%d/%d)Hypervisor: unable to create TCP sockets. Hypervisor TCP control server started (port %d). hypervisor_create_conn: fdopen/inhypervisor_create_conn: fdopen/outHypervisor: closing control sockets.Hypervisor: closing remote client connections.hypervisor_tcp_server: unable to create new connection for FD %d hypervisor_inithv_nio.cNIO '%s' deletedunable to delete NIO '%s'unable to create FIFO NIONIO '%s' createdunable to create Null NIOunable to create TAP NIOunable to create VDE NIOunable to create UNIX NIOunable to create UDP NIOUnknown filter %sNo filter previously definedcreate_udpcreate_unixcreate_vdecreate_tapcreate_gen_ethcreate_linux_ethcreate_nullcreate_fifocrossconnect_fifodeleteset_debugunbind_filtersetup_filterunable to create Linux raw ethernet NIOunable to create generic ethernet NIOhypervisor_nio_initnio_bridgehv_nio_bridge.cNIO '%s' unbound.NIO '%s' bound.NIO bridge '%s' deletedNIO bridge '%s' createdadd_nioremove_niounable to bind NIO '%s' to bridge '%s'unable to delete NIO bridge '%s'unable to create NIO bridge '%s'hypervisor_nio_bridge_initfrswhv_frsw.cFRSW '%s' deletedunable to delete FRSW '%s'FRSW '%s' createdunable to create VCVC createdunable to delete VCVC deletedcreate_vcdelete_vcunable to create frame-relay switch '%s'hypervisor_frsw_initatmswhv_atmsw.cATMSW '%s' deletedunable to delete ATMSW '%s'ATMSW '%s' createdunable to create VPCVPC createdunable to delete VPCVPC deletedunable to create VCCVCC createdunable to delete VCCVCC deletedcreate_vpcdelete_vpccreate_vccdelete_vccunable to create ATM switch '%s'hypervisor_atmsw_initatm_bridgehv_atm_bridge.cunable to unconfigure bridgeATM bridge unconfiguredATM bridge '%s' deletedATM bridge '%s' createdunable to configure bridgeATM bridge configuredunconfigureunable to delete ATM bridge '%s'unable to create ATM bridge '%s'hypervisor_atm_bridge_initethswhv_ethsw.cunable to apply port settingsPort settings OKETHSW '%s' deletedunable to delete ETHSW '%s'ETHSW '%s' createdset_access_portset_dot1q_portclear_mac_addr_tableshow_mac_addr_table%2.2x%2.2x.%2.2x%2.2x.%2.2x%2.2x %u %sunable to bind NIO '%s' to switch '%s'unable to create Ethernet switch '%s'hypervisor_ethsw_initvmhv_vm.c%s (%d)%s (%s)%u/%u: %sVM '%s' resumedVM '%s' suspendedconf '%s' %sIOS config file set for '%s'IOS image set for '%s'VM '%s' stoppedVM '%s' startedVM '%s' deletedunable to delete VM '%s'VM '%s' createdBad CPU specified0x%llx [%d]Timer Drift: %uPending Timer IRQ: %ustartset_debug_levelset_iosset_configset_ramset_nvramset_ram_mmapset_sparse_memset_clock_divisorset_blk_direct_jumpset_exec_areaset_disk0set_disk1set_conf_regset_idle_pcset_idle_pc_onlineget_idle_pc_propshow_idle_pc_propset_idle_maxset_idle_sleep_timeshow_timer_driftset_ghost_fileset_ghost_statusset_con_tcp_portset_aux_tcp_portextract_configpush_configcpu_infosuspendresumesend_con_msgsend_aux_msgslot_bindingsslot_nio_bindingsslot_add_bindingslot_remove_bindingslot_add_nio_bindingslot_remove_nio_bindingslot_enable_nioslot_disable_niolist_con_portsIOS config file pushed tm VM '%s'unable to push IOS config for VM '%s'unable to extract config of VM '%s'unable to store IOS config for router '%s'unable to store IOS image name for router '%s'unable to stop VM instance '%s'Warning: no console port defined for VM '%s'unable to start VM instance '%s'unable to create VM instance '%s'VM %s: unable to add binding for slot %u/%uVM %s: unable to remove binding for slot %u/%uVM %s: unable to remove NIO binding for slot %u/%uVM %s: unable to enable NIO for slot %u/%uVM %s: unable to disable NIO for slot %u/%uhypervisor_vm_initvm_debughv_vm_debug.c0x%4.4xBad CPU0x%8.8xBad CPU or registershow_cpu_regsshow_cpu_mmuset_cpu_regadd_cpu_breakpointremove_cpu_breakpointpmem_w32pmem_r32pmem_w16pmem_r16hypervisor_vm_debug_initobject_storehv_store.c%s (len=%ld)object store deletedunable to delete object %sobject %s deletedunable to store objectunable to decode base64delete_allunable to encode data in base64hypervisor_store_inithv_c7200.cset_npeset_midplaneset_mac_addrpa_init_onlinepa_stop_onlineshow_hardwareunable to set MAC address for router '%s'unable to set Midplane type for router '%s'unable to set NPE type for router '%s'hypervisor_c7200_inithv_c3600.cset_chassisset_iomemunable to set Chassis type for router '%s'hypervisor_c3600_inithv_c2691.chypervisor_c2691_inithv_c3725.chypervisor_c3725_inithv_c3745.chypervisor_c3745_inithv_c2600.chypervisor_c2600_inithv_c1700.chypervisor_c1700_init%s=%s %s: unable to create file %s (%s) rommon_var_update_fileMIPS64: invalid instruction in delay slot at 0x%llx (ra=0x%llx) MIPS64: unhandled opcode 0x%8.8x at 0x%llx (ra=0x%llx) mips64_x86_trans.cmips64_emit_TEQImips64_emit_TEQmips64_emit_memop_fast32mips64_emit_memop_fast64mips64_emit_SLTUmips64_emit_SLTIUmips64_emit_SLTImips64_emit_SLTmips64_try_direct_far_jumpmips64_emit_BNELmips64_emit_BNEmips64_emit_BLTZLmips64_emit_BLTZALLmips64_emit_BLTZALmips64_emit_BLTZmips64_emit_BLEZLmips64_emit_BLEZmips64_emit_BGTZLmips64_emit_BGTZmips64_emit_BGEZLmips64_emit_BGEZALLmips64_emit_BGEZALmips64_emit_BGEZmips64_emit_BEQLmips64_emit_BEQmips64_emit_BNEZmips64_emit_BEQZmips64_check_pending_irqppc32_op_insn_output: FAILURE: count=%d, size=%d ppc32_x86_trans.cset_page_jumpperf_cntmemop_fastmemop_idxmemopblrbctrbccandisppc32_emit_unknownturvwsxyz{pqppc32_emit_memop_fastppc32_emit_SRWppc32_emit_SLWppc32_emit_BCLRppc32_emit_BCppc32_try_direct_far_jumpppc32_emit_BCCeth_get_dev_index: socket: %s eth_get_dev_index: SIOCGIFINDEX: %s eth_init_socket: setsockopt: %s eth_init_socket: socket: %s eth_init_socket: bind: %s Network device list: no info provided %s : %s PCAP: unable to find device list (%s) gen_eth_init: unable to open device '%s' with PCAP (%s) elf_error.clibelfmsgidx[last_error] < sizeof (msgstr)msgidx[error == -1 ? last_error : error] < sizeof (msgstr) '4Ih 2Gh{ /Hg{ %@er no errorunknown errorunknown versionunknown typeinvalid `Elf' handleinvalid size of source operandinvalid size of destination operandinvalid encodingout of memoryinvalid file descriptorinvalid operationELF version not setinvalid commandoffset out of rangeinvalid fmag field in archive headerinvalid archive filedescriptor is not for an archiveno index availablecannot read data from filecannot write data to fileinvalid binary classinvalid section indexinvalid operandinvalid sectioninvalid commandexecutable header not created firstfile descriptor disabledarchive/member fildes mismatchoffset out of rangecannot manipulate null sectiondata/scn mismatchinvalid section headerinvalid dataunknown data encodingsection `sh_size' too small for datainvalid section alignmentinvalid section entry sizeupdate() for write on read-only fileno such fileonly relocatable files can contain section groupsprogram header only allowed in executables, shared objects, and core filesfile has no program headerinvalid offsetelf_errmsg` / // ! ELFelf_begin.cmaxsize != ~((size_t) 0)map_address != ((void *) -1)OrOOOOOOOrOOObOread_fileelf_end.clist == ((void *)0) || oldp->cnt == oldp->maxelf_endelf32_getshdr.cresult != ((void *)0)ehdr->e_ident[5] != 1 || (! 1 && ((uintptr_t) file_shdr & (__alignof__ (Elf32_Shdr) - 1)) != 0)elf32_getshdr    4 ( @8@ adgfafehef`h@e0c`k i__^^bajb0cansl al ps`tnhtcqi__^^c@b0r@dp]ehdr->e_ident[5] != 1 || (! 1 && ((uintptr_t) file_shdr & (__alignof__ (Elf64_Shdr) - 1)) != 0)elf64_getshdranySIOCGIFHWADDR: %sSIOCGIFINDEX: %spcap_stats: %smalloc: %sstrdup: %ssocket: %sisdnisdYclose: %sbind: %sgetsockopt: %ssetsockopt: %sunknown arptype %dSIOCGIFFLAGS: %satexit failedSIOCSIFFLAGS: %s2.0SIOCGIFMTU: %srecv: %ssend: %srecvfrom: %sSIOCGSTAMP: %sSetting direction is not supported on SOCK_PACKET socketsCan't restore interface flags (SIOCGIFFLAGS failed: %s). Please adjust manually. Hint: This can't happen with Linux >= 2.2.0. Can't restore interface flags (SIOCSIFFLAGS failed: %s). Please adjust manually. Hint: This can't happen with Linux >= 2.2.0. Promiscuous mode not supported on the "any" devicearptype %d not supported by libpcap - falling back to cooked socketpcap_open_live: The "any" device isn't supported on 2.0[.x]-kernel systemssetfilter: No filter specifiedWarning: Filter too complex for kernel Warning: Kernel filter failed: %s Sending packets isn't supported on the "any" deviceSending packets isn't supported in cooked modeYfsPseudo-device that captures on all interfacesgetifaddrs: %sStatistics aren't available from a pcap_open_dead pcap_tSetting direction is not implemented on this platform%s is not one of the DLTs supported by this deviceDLT %d is not one of the DLTs supported by this deviceRFC 2625 IP-over-Fibre Channel802.11 plus BSD radio information header802.11 plus AVS radio information headerPPP for pppd, with direction flagJuniper Multi-Link Frame RelayEthernet with Endace ERF headerPacket-over-SONET with Endace ERF headerJuniper Encryption Services PICArinc 653 Interpartition CommunicationBluetooth HCI UART transport layerController Area Network (CAN) v. 2.0BF_GETFL: %sF_SETFL: %s%s: %s DLT_NULLDLT_EN10MBDLT_IEEE802Token ringDLT_ARCNETDLT_SLIPDLT_PPPDLT_FDDIDLT_ATM_RFC1483RFC 1483 LLC-encapsulated ATMDLT_RAWRaw IPDLT_SLIP_BSDOSBSD/OS SLIPDLT_PPP_BSDOSBSD/OS PPPDLT_ATM_CLIPLinux Classical IP-over-ATMDLT_PPP_SERIALPPP over serialDLT_PPP_ETHERDLT_C_HDLCCisco HDLCDLT_IEEE802_11802.11DLT_FRELAYDLT_LOOPOpenBSD loopbackDLT_ENCOpenBSD encapsulated IPDLT_LINUX_SLLLinux cookedDLT_LTALKLocaltalkDLT_PFLOGOpenBSD pflog fileDLT_PRISM_HEADER802.11 plus Prism headerDLT_IP_OVER_FCDLT_SUNATMSun raw ATMDLT_IEEE802_11_RADIODLT_APPLE_IP_OVER_IEEE1394Apple IP-over-IEEE 1394DLT_ARCNET_LINUXLinux ARCNETDLT_DOCSISDLT_LINUX_IRDALinux IrDADLT_LINUX_LAPDLinux vISDN LAPDDLT_IEEE802_11_RADIO_AVSDLT_SYMANTEC_FIREWALLSymantec FirewallDLT_JUNIPER_ATM1Juniper ATM1 PICDLT_JUNIPER_ATM2Juniper ATM2 PICDLT_JUNIPER_MLPPPJuniper Multi-Link PPPDLT_PPP_PPPDDLT_JUNIPER_PPPOEJuniper PPPoEDLT_JUNIPER_PPPOE_ATMJuniper PPPoE/ATMDLT_GPRS_LLCGPRS LLCDLT_GPF_TGPF-TDLT_GPF_FGPF-FDLT_JUNIPER_PIC_PEERJuniper PIC PeerDLT_JUNIPER_MLFRDLT_ERF_ETHDLT_ERF_POSDLT_JUNIPER_GGSNJuniper GGSN PICDLT_JUNIPER_ESDLT_JUNIPER_MONITORJuniper Passive Monitor PICDLT_JUNIPER_SERVICESJuniper Advanced Services PICDLT_JUNIPER_MFRJuniper FRF.16 Frame RelayDLT_JUNIPER_ETHERJuniper EthernetDLT_JUNIPER_PPPJuniper PPPDLT_JUNIPER_FRELAYJuniper Frame RelayDLT_JUNIPER_CHDLCJuniper C-HDLCDLT_MFRDLT_JUNIPER_VPJuniper Voice PICDLT_MTP2SS7 MTP2DLT_A429Arinc 429DLT_A653_ICMDLT_USBDLT_BLUETOOTH_HCI_H4DLT_CAN20BDLT_MTP2_WITH_PHDRSS7 MTP2 with Pseudo-headerlibpcap version 0.9.7  !"#$%&'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~%s: no IPv4 address assignedSIOCGIFADDR: %s: %sSIOCGIFNETMASK: %s: %sinet class for 0x%x unknownno suitable device foundtoo many registers needed to evaluate expressionsnaplen of 0 rejects all packetssyntax error in filter expressionexpression rejects all packetssio value %u too big; max value = 255opc value %u too big; max value = 16383dpc value %u too big; max value = 16383sls value %u too big; max value = 15'vpi' supported only on raw ATM'vci' supported only on raw ATM'callref' supported only on raw ATM'metac' supported only on raw ATM'bcc' supported only on raw ATM'oam4sc' supported only on raw ATM'oam4ec' supported only on raw ATM'sc' supported only on raw ATM'ilmic' supported only on raw ATM'lane' supported only on raw ATM'llc' supported only on raw ATM'oam' supported only on raw ATM'oamf4' supported only on raw ATM'connectmsg' supported only on raw ATM'metaconnect' supported only on raw ATMno VLAN support for data link type %daction not supported on linktype 0x%xreason not supported on linktype 0x%xsrnr not supported on linktype 0x%xrnr not supported on linktype 0x%xARCnet address used in non-arc expressionruleset not supported on linktype 0x%xruleset names can only be %ld charactersifname not supported on linktype 0x%xifname interface names can only be %d charactersethernet addresses supported only on ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channelethernet address used in non-ether expressionunsupported protocol over mplsIrDA link-layer type filtering not implementedDOCSIS link-layer type filtering not implementedLAPD link-layer type filtering not implementedno MPLS support for data link type %dlink-layer multicast filters supported only on ethernet/FDDI/token ring/ARCNET/802.11/ATM LANE/Fibre Channelonly link-layer/IP broadcast filters supportedarp does not encapsulate another protocolrarp does not encapsulate another protocolatalk encapsulation is not specifiabledecnet encapsulation is not specifiablesca does not encapsulate another protocollat does not encapsulate another protocolmoprc does not encapsulate another protocolmopdl does not encapsulate another protocolbad protocol applied for 'protochain''protochain' not supported with radiotap headers'protochain' not supported with PPI headersunsupported proto to gen_protochainlink layer applied in wrong context'radio' is not a valid protocol typeradio information not present in captureIPv6 upper-layer protocol is not supported by proto[x]inbound/outbound not supported on linktype %dISO host filtering not implemented'ip' modifier applied to ip6 %s'rarp' modifier applied to ip6 %s'arp' modifier applied to ip6 %sATALK host filtering not implementedAARP host filtering not implemented'decnet' modifier applied to ip6 %sSCA host filtering not implementedLAT host filtering not implementedMOPDL host filtering not implementedMOPRC host filtering not implemented'icmp6' modifier applied to %sIPX host filtering not implemented'netbeui' modifier applied to %s'radio' modifier applied to %s%s resolved to multiple addressnon-network bits set in "%s/%d"invalid qualifier against IPv6 address'ip6' modifier applied to ip hostillegal qualifier of 'portrange'non-network bits set in "%s mask %s"unknown Fibre Channel host '%s'only ethernet/FDDI/token ring/802.11/ATM LANE/Fibre Channel supports link-level host name'gateway' not supported in this configurationunknown ip proto '%s'unknown ether proto '%s'esisisisclnpunknown osi proto '%s'out of memoryunknown data link type %d'sio' supported only on SS7'opc' supported only on SS7'dpc' supported only on SS7'sls' supported only on SS7'fisu' supported only on MTP2'lssu' supported only on MTP2'msu' supported only on MTP2no VLAN match after MPLSnot a broadcast linkdirection applied to 'proto''udp proto' is bogus'tcp proto' is bogus'sctp proto' is bogus'icmp proto' is bogus'igmp proto' is bogus'igrp proto' is bogus'pim proto' is bogus'vrrp proto' is bogus'icmp6 proto' is bogus'ah proto' is bogus'stp proto' is bogus'ipx proto' is bogus'netbeui proto' is bogus'radio proto' is bogusdata size must be 1, 2, or 4unsupported index operationhost'sctp' modifier applied to %s'tcp' modifier applied to %s'udp' modifier applied to %s'icmp' modifier applied to %s'igmp' modifier applied to %s'igrp' modifier applied to %s'pim' modifier applied to %s'vrrp' modifier applied to %s'ah' modifier applied to %s'esp' modifier applied to %s'esis' modifier applied to %s'isis' modifier applied to %s'clnp' modifier applied to %s'stp' modifier applied to %sno mask %s supportedinvalid ip6 address %smask length must be <= %uMask syntax for networks onlyillegal link layer addressillegal qualifier of 'port''gateway' requires a namemask length must be <= 32unknown network '%s'unknown ether host '%s'unknown FDDI host '%s'unknown token ring host '%s'unknown 802.11 host '%s'unknown host '%s' for specified address familyunknown host '%s'%sunknown port '%s'port '%s' is tcpport '%s' is sctpport '%s' is udpunknown port in range '%s'port in range '%s' is tcpport in range '%s' is sctpport in range '%s' is udpunknown protocol: %s0lcCCCC>'CCwCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC@CCCCTC'cCCC'CCCCC_CCCTCIIItQ. aCCggCCCCCCCCCCCCCCCCCCJClCCCCCCCCglIII&CCggCCCCTPC%F rq 5 l l & aqL\\,Q| ,4! ,#"\#,#" $#<$ $#$$%$$.9+****L++/+L+L+/**/-**L+******************************++****************************************************c-L+*,..***z-.**,*L+**L+5,***L+*+_+_+_+_+_+_+_+_+*****++******************L+_+*+_+_+********+_+_+_+_+*_+********L+;xENU^enu %/9CQ[?)?Uk1G]s `[Y   !"#$%&'()*+,-./01234___````hh`````cg9hkebdaf!"Q:K:giihkhkkk9F]#*<D$YZ-;G\S[^%) NMihlkkkkk6(&W, C4X.@/'RT?iiiiihkkklkkkkkkL EH1ihkkklkklkkkkkkkkkkV<ABUiiiiihkkkkklkkkklkkkkkk35=+IJihkkkkkklkkkkkkkkkkkkkkkkkon>iiihkkkkkkklkkkklkkkklkkkkkkkk7t{80hkkkkkkkkklkkkkkkkkkkkkkkkkkkkkkkkkO2jhkkkkkkkjkklkkkklkkkklkkkklkkkkkkkkkyPjhmkkkkkkkkkkkkjlkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk}qhkkkkkkkkkkklkkkklkkkklkkkklkkkklkkkkkkkkkswkkkkkkkkkkkkkkklkkkkkkkkkkkkkkkkkkkkkkkkkkkkp|~xkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkzkkkkkkkkkkkkkkkkkkkurkkkkkkkkkkkkkkkkvkkkkkkkkkkkk\\\\\\\]\\\\\\\\\^\\\_\`2\\\\\\1^^2@@@@\\a\6\bcde\fg\\\h5;i\jk\\\\Clmn\\J\Lohw;}dp\q\rs\ftu\\\vl\\wx\\\\yz}z\\\{|\\\\}\~\\\\\w\\\\y\\\\!\\&\(}\~\\\2\4\\\\\\?]\\\a\\d\\\\k\\\\\t\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\&\\\\\4\6\J\M\P\S\\\Y\\^\`\\\\j\l\\\\\y\{\\\\\\\\\\\\\\\\\\\\\\\\\ \\\  \ \ \\\\\\\\\\\\\\ \!\"\\\#$%%%%%%%%%%&\\'\ (\)\*\+\\\,-./\\ 012\3\4\\*567\89\:\;\\7<=>?\@A\B\C\\EDEFG\HI\J\K\\SLMN\O\PQ\\\R_STTTTTTTT\kUV\Wo\Xr\Yu\Zx\[{\\\]^_`\ab\c\d\ef\gh\i\jk\lm\n\op\qr\s\tu\vwx\yz\{\|\\}~\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\   4  5 ; ? P17 >j$7fo q   ! 7X     Ho( g &   q g o f e j r a g U V V V 1a O Z S : .8 E7 C 5 3 8 ? 6 ! 0  v9 ? W7  "       %  ' @  ~ { m o l m B Xnt _ ^ ] X ,@ 5 : 7 6 ' &      C * 3 A W m '.  o l c g _ h V (U ^ [ < 4 B : @ 9 - %    5/ +& $ B# "   j  hY`  )  z  d c g b Z f ` \ I G L Q P &e =d] z\ 4 CKQ3 W.59 <CJah1 7         ]"<Ja=>9@Sw}}~tvufsna 8}Ne{&-|m  l  + B H N kT [ q T q o % Ugm f~ @? @Vg  VU! WSI @Pq RA>;9 S8g8 ? i` g   j t   ? . V 4 l r ~ h~H   + 2 H _ f |  : # ) / 5 < R i o u {  o j  ST6I7$:K+)*Q'y+%A$#f4 7@uGFh]n   5; <tvz m !;}  r>PNe{2EO M 6H=^ dkHu`ly k&z -4KRa,2$st<)yc(&0hXoNosxvJP;%5GN,Mu&,2r8?VMi^ x0t_^J6G<B.HNRTZS`fpls_zU# qK h"(//0=CI  P^e V k w }  = FIJ_ ^A    $'*-037;>BDGJMPSWY]bfilorux{ !%*.269<?CEJNQTWZ^`cfjloruy{~  $&+/258;>AEGJMPTVY\_bfhknqtxz} "'+048<?BEIKNSWZ]`cfimqtx{~ !$'*/38;>AFJORUX]afilorvx}\    R  A A\ IAX=9"X"!'!5#&O!!'&!&!&##&#&&#O 1&OF L F  %$L% $$)$$Q%# )%,%),),Q],4444444,======,111111a]`1a]|`1111112222222d|d2di222222666666>i>6>w>~6666667>~7w77>7777777-7-7777777@@@@@@@@6M6HM<H<Hqq|"|")8888888 1)f1 1f11155<<<<<<<5555555#55#555555BBBBBBEEEEEEED577777777D777777:::::::{{{{{{:IIIIIIIKKKKKKKxxxxxxx$,0:;;;;;;;$,0;;;;;;;>>>>>>>$,0>>>>>>AAAAAAAAAAAAAACCCCCCCCCnCCCCCCDDDDDDD]+DDDDDDDJJJJJJJJVJU+JJJJJJLLLLLLLLOLL7LHKLLLLLL||||||~~~~~~~G7LXAKXCX>XXXXXwwwwwwCw>ACwwwwwwzzzzzz:N>Az>EAzzzzzz}}}}}}9E3}NQG0}}}}}}GT-,QT\Z&#\"Z=amp==amp||      .cc<Jl.dede<Jfglfgg~}uron%%%%%%%''''''')fcb!)[W-------///////+!!!!!!!!!VUR!O!+LI!!!!!!11111113333333@!&&&&&&&&H/9&37@8&&&&&&((((((((@0(/(-37((((((888888::::::.?$(22222222. 2;??F22222244444444?F4.4;444444>>>>>>AAAAAAA2:;4?????????2?G:;??????@@@@@@:;P@?2G@@@@@@YYYYYYYYPYYYYYYZZZZZZ\\\\\\jjjjjj\^^^^^^^cccccccfffffff\<Bd\]]]]]]\]d<B]]]]]]``````<<B`\d``````aaaaaaaaa}rhhaaaaaabbbbbbhg_VbUTRQNbbbbbbddddddddMLhdhKJIHddddddeeeeeehGFEeDC=7heeeeeeiiiiiii6.+i*# iiiiiikkkkkkkkk kkkkkkllllllllllllllmmmmmmmoooooosssssstttttttttttttttuuuuuuuuuuuuuuvvvvvvvxxxxxxzzzzzz~~~~~~sswswwyvutsrqponmljhgeda`^\[ZWVTSRPONG@?=920+)'&%$#"! *  **}{zyxvutsrqomlkjihgfecb[ZYWVUTSRPNMKJIHGED      C3+*( !!!!!!%%%%%%&&&&&&&&&&&&&&&''''''''''''''(((((((,,,,,,///////1111111333333344444444444444455555556666666666666666]]]]]]]_______6FFFFFFFFeeeeeeeFJJJJJJJJJJJJJJJJgggggggiiiiiiiJMMMMMMMMMMMMMMMMkkkkkkkqqqqqqMPPPPPPPPPPPPPPPPtttttttvvvvvvvPSSSSSSSSSSSSSSSSxxxxxxxzzzzzzzSXXXXXXXXXXXXXXYYYYYYYYYYYYYYYY$Y^^^^^^^^$^^^^^^^`````````$````````jjjjjjjjjjjjjjjllllllllllllllll(lyyyyyyyy(yyyyyyy{{{{{{{{{({{{{{{{1{1155ii5i???CCCMMMQQQ~~~!!!!!!!                %%%%%%%''''''' )))))))+++++++//////222222244444446666666               ***************7777777777777778888888======@@@@@@@BBBBBBBDDDDDDDEEEEEEEEEEEEEEEFFFFFFFKKKKKKNNNNNNNPPPPPPPRRRRRRRSSSSSSSSSSSSSSSTTTTTTTXXXXXXZZZZZZ^^^^^^_________j______aaaaaaajqqqqqqqjkkkkkkkkkkkkkkkktttttttwwwwwwwkooooooooooooooorrrrrrrrrrrrrrruuuuuuuuuuuuuuuxxxxxxxxxxxxxxxzzzzzzz{{{{{{{{{{{{{{{}}}}}}}             """"""$%%%%%%%$'''''''------000000444444$888888<<<<<<@@@@@@CCCCCCHHHHHHQQQQQQ]]]]^^^^^^^^__```aaabbbcccdddeeefffggghhiiijjjkkkllmmmnnnooopppqqqrrrssstttuuuvvvwwxxxyyzzz{{{|||}}~~               !!!"""###$$$%%%%%&&&'''((()))***+++,,,--...///00011122233344455566677888999:::;;;<<<===>>??@@@AAABBBCCCDDDEEEFFGGHHHIIIJJJKKKLLLMMMNNOOPPQQQRRSSTTTTTUUVVVWWXXYYZZ[[\\\]]]^^^___```aabbbcccddeefffggghhiijjkkklllmmnnoopppqqqrrssttuuuvvvwwxxyyyzzz{{{|||}}~~~\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\    !"#$%&'()*+,,,,,,,,,,,,F,,,,,,589C,,,G,;<5,H,0122222235OP456-0444444555555555555555565,Q@,A,RS,BkC>7D>E>lT>,=444444>LIeJ5f>KMm|Ngh}i~jn1opq55555555\^_5 2555555V`WXaY5Zb[c\wr]5xdstuvy`z,{,,5,=,0,5015>>>5>,>,,0,>,m\n0,=50\58888880B\5\777777:88888\5\\\\5\\\\\5\\\b>\\e@5<<<<<<HIIIII\\^5\KKKKKK|888888jp\00q566666rst7u00777777999999Z\\9\000999999;;;;;;000<\\\<<<<<<BCCCCCCDXE|F00XEEEEEEY5~~~~~~008Z:0FJJJJJJ9;K[000yKKKKKKLMMMMM00N9;0NNNNNNwxxxxxxs~0yzvyyyyyy\00z{yyyyyysy00yyyyyy|888888IIIIII\woxz0}}}}}}py{~\p0~~~~~~\\py{\\\\\0BD\0\\0:0\;0000<>00\@\5%\\000000AC00\0000\\00B00\F\\ \F\ \ 00B\\000?0\\\0\\00=0|\0\y0\pv5\0\sp`0sf$%%%%%z\'''''',-----011111\ZZZZZzW\\000 000W\0\Bg0 \000000\0i\!"""""0\c#d\0\######&&&&&&0e'\0\''''''()))))0*\00******22222200300\333333455555006666666\3333338:<<<<<<=vy======\======>??????@AB%|AAAAAAZZZZZZ5^^^^^^00BYYYYYY!Y000YYYYYY[[[[[[B0[000![[[[[[]]]]]]"000^^^^^^^aaaaaab^"c`cccccco%%%%%%\rrrrrr0dddddde fB0Xffffffx------B//////0BjkkkkkklImn0mmmmmmz111111\}}}}}}00nqqqqqqbIJrKL00rrrrrrsttttttuDvJwKLvvvvvv00w||||||e}0M00}}}}}}~0XIM\00>@NIS@00~Y'N0zSx0sYoj+ZZZZZZZZZZZZ5\''''''\3333330000&&&&&&b>:'8eb''''''222222e303333330uli jleb`XWVUTSRQPON\suMLKJIHGFEDC@ \~     ,\>@\000000050/00Bjn{ \      nsww~n\ 0 j       0|      volkji!0hsgfedc0ba`_)^]\W\$$$$$$+,,,,,0V~######U$TS0RQ$$$$$$%&&&&&&'PDF()A((((((./////233333XZ>0)444444Y[54300555555677777/.8Y[0-,888888\55555500EEEEEE+*)(E'0&0EEEEEEFFFFFF0%$#G"! *GGGGGG5GGGGGGJKKKKKLLLLLLLj  MNNNNN   OOOOOOO\sPQQQQQRRRRRRR\~STTTTTUUUUUUU\YZZZZZ[[[[[[[\]]]]]^^^^^^_______`aaaaabbbbbbb\______deeeeehiiiiijjjjjjkU:/kkkkkklmmmmm-\\n\\\\\nnnnnn\kkkkkkpqqqqqstttttwxxxxxyyyyyy\\\z\\\\\zzzzzz{|||||\\\}\\\\\}}}}}}\zzzzzz%'\\\\\\\\\\\\\\\\\,,,,,,//////>111111333333\\\\\\\\\\\\\\\\]]]]]]\\00eeeeee0\0\\\ \\\jggggggiiiiii\ \\\\\\\qqqqqq\\\\\\\\\ttttttsvvvvvv\\%\\\\)\\\xxxxxx\\0)\\\\\\\0j\\\\\\\\\\\\\\\\\\\\\~\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\%\\\\\\\\\\\\\\\______\\\\\\0\0\\0\\\\0\kkkkkk\\00\zzzzzz00     \\h\ \\\\      ^^^^^^\\\_\\\______      \\\ \\\\\      jjjjjj\\k\\\\kkkkkk\\\\\\\\yyyyyy\\z\\\\zzzzzz\\\\\\\\%\\\\\\\\\\\\\\\\\\\\\\\\\!!!!!!\\\      \\\!\\\\\!!!!!!$%%%%%()))))******\\\+\\\\\++++++\++++++./////122222566666777777\\\8\\\\\888888\888888<=====?@@@@@CDDDDDEEEEEE\\\F\\\\\FFFFFF\FFFFFFJKKKKKMNNNNNQRRRRRSSSSSS\\\T\\\\\TTTTTT\TTTTTTXZ\\\\\\\\\]\\\\\]]]]]]\]]]]]]^______`\\\a\b\\\aaaaaa~\\\bklllllm\\\n\\\\nnnnnnoooooop\\\q\\\qqqqqq\\\rrrrrrs\\\t\\\\tttttt%%%%%%''''''\\uuuuuuv\\\w\\\\wwwwww))))))\\xxxxxxy\\z\\\\zzzzzz//////222222\\{{{{{{|\\\}\\\\}}}}}}444444666666\\\\\\\\p\\\\\\\s\\\\\\\\v\\\\\\\\\======@@@@@@BBBBBBDDDDDDy\\\\\\\\\KKKKKKNNNNNN%PPPPPPRRRRRR|\\\\\\\\\^`\\\\0\\\\0\!!!!!!\\\\\\\\\\\++++++\888888 \      p\\!\\\\\!!!!!!******s\\\+\\\\++++++777777v\\\8\\\\\888888EEEEEEy\\\F\\\\\FFFFFF\FFFFFFSSSSSS|\\\T\\\\\TTTTTT\TTTTTT\\\\\\\\\^`\\\\\\\\\\\\\\\\\\ \\\\\\\\\\\\\\\\\!"""""$%%%%%-\\\\\/00000.-      344444\\\\\.788888;<<<<<?@@@@@""""""CC%%%%%%\\\\\D^''''''GHHHHH000000444444D888888<<<<<<@@@@@@PQQQQQHHHHHHQQQQQQ.\\\\...?\???????\===???@@@GGGEEEO\O\II\\I\\\\+\+.\.///7\7\\\\AAA___cccfffggghhhmmm%%\\%vvv--\\-11\\1\\\\\\\\\\\\\\\\\\555\55ggg\\\\\\\\\\\\\\\\\(((\*\*-\-0\01119\9555\55HHHVVVWWWc\cf\fgggo\or\ru\uvvv~\~\\\\*\*,\\,--\-//\\/00\033\\399\9555\55]]\\]cc\cee\\eff\fii\\ioo\oq\\qrr\rtt\\tuu\uxx\\x~~\~\\\\\\\\\\\\\\555\55"""#\#&\&''',,,-\-0\03\3444999:\:;\;>\>A\ABBBGGGH\HI\IL\LO\OPPPUUUV\V\\\\\\\\\aaa\555\55qqqtttwwwzzz}}}\\\##\#%%\\%&&\&))\\)--\-/\\/00\022\\233\366\\6::\:;\;=\\=>>\>@@\\@AA\ADD\\DHH\HI\IK\\KLL\LNN\\NOO\ORR\\RVV\V\\\\\555\55\\\\\\\\GGG\\\\\\\\\\\\\\\\\\\\\\\\555\55\\\\\\ \        \ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ \ #\#&\&'''(\(555\55,\,\\\\\\\\  \ \1\12\25\56\69\9:\:=\=>\>A\A"\\"%%\\%E\E \ I\I0\\04\\48\\8<\\<@\\@O\OR\RH\\HT\TU\UV\VW\WX\XQ\\QZ\Z[\[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\matchbad-offsetfragmentshortnormalizepassblockunknown PF actionsyntax errormemory exhaustedunknown PF reason'5o9s .x-2<_%Rn>_(Bc}!1AQaq !1AQaq!1AQaq)=JYi*!1AQi-T{&2AQaq=W PKKKKKKKKKKKKKKKKKKKKKKK ,#KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK)KKKKKKKK KKK>KKKKKKKKKKKKKK**KKKKKKKMRKKKKKKKKKKKKKKKKKKNQYKKK_lqKKKKKKKxK**KKKKKKpKKP)KAAbKKKKKKKKK.KKKKKKKKKKNK_KK`KKKgipoljkmvsrqtuh  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefnWT()$U$67lm$67f112345ob$dyz$()yztf$efU$Wo$./0obQd1hijklm1hijklmuvqg$tTU1WyzpTUTUptbodefeftmoqmo$o$tyzpqrs$yzyz$ef$ef$67$o3 hi $jklmqrsef./0ef$$"#o67ijklm$ u !$%&'()*+,-pqrsjklm89:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdgk p !$%&'()*+,-1234589:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdgk p !$%&'()*+,- 89:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdgkp !$./0-6789:;<ABCDEFGHIJKLMN]hijklmkqrspU{rsTZl}xmefqq}xwx~gjvhiPk~UUoRTTZZR{q}RZZqwxUZZS  !"R#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQR  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQR  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQR "#$%&',-./0123456789HQR3AB@CDEFGHIJKLMNOQPjk?RSTUmopqVW`XYZ[\]_^abcd332,r-.0ghstuvyzw{xln 33 ' 54:>;<=$%ef"#&}|~/133 (!*+i9786wxxyzzzzz{|}}}~~~~~~~~~KKK2LKKKKKKkKKKKKKKKKKiKKKKoK|yztVWXYu[\np]^_`abcd;4LTzR| DAB E<AB E=W     '6BP[h2>3hikl m"0q=GrQ[unwz{$(/>IXi,cX$6DZly|"6Rg(7?N`ir{0TL+  hL L t  o@ooؘ,&6FVfvơ֡&6FVfvƢ֢&6FVfvƣ֣&6FVfvƤ֤&6FVfvƥ֥&6FVfvƦ֦&6FVfvƧ֧&6FVfvƨ֨&6FVfvƩ֩&6 7>k_LSmy?"2MbǠc[J${8+)VNCOQ+{qs܂CU HqC_Y,?z/i]{\u 7~<~D֝#`! graG4RiQ6&L)̘~Wu畕r>̷u #CHA'h4*<) )nq;bx޷ɎtOLzg=ؗ ,-{4|="cWA-gXX3sƒUX+4K"2] v~TMQz%5}-aOOrGiQLi:~J\gއ<%촌Tѻ&9^) ŧS!Vf6/Z!bdο!欎-^*R~?5)ѡZE88`b9/6"; -m,Hr2*\t_/c2#\|N qE;}Vj_̷R3UDfsa&Y튻 9JJЈ!xI',Cˈ -8z(868˩Bl HC[Xfit! 0!F.)ZdžRu>Cبm(qs]'- XI+m15;=$[L>+Gu-86MAVq??GK(}dK4ł.s7,N3cc@q5agoYD=IpRpŞfu TMN>eJ! U,R⯛3aj #[COI_+ބk31=4z9di>`6{-5(:FNհAQu7AߺL@B?>LV @behknqtwz}OYQ>R "*26@GNVz>P\XT |0$0!z>   @   ` 0$!]$`00P`  @  ` \ p X    0  T? p@@ P`@d-@ % @+p D1P@70D=?8Bp?<IO?;T0??[a`?:f?>ms@/yB  ~ ? p? _Ph0lpݾ<0p&@p@,Dp2@8D  ppPc'd%F@4Lp m@>?JP*(P, +P?\`b0?n"t#?0 ?? &н?4*` /B4pB9`B?PBt&E8|g |l {|q 0 |w  ||} |  | | 0| | @| |  | | | |8 0 P4  < | @| | |]`8|9|Ox| y| 0p tz>H HsH`H@@ @@@ L !L L%й!L,p`|0`,5`@|:``(@ 4|GLM0LTBLZLaBLgPLlBLrLx|}|,|вl|p||| |||V8|аt|u|`4|5|Я||,LP||0Э||`n|p.|  ,|`n|%.|*p(|0@49|?P|D|I*|NcLSp&|XP|^|d`|i0&|pB |v0B || |@$||`|||| |`|Н|| |\||p| || |c||d`x|y|n8|9|F``@d |dLPPpTT0\p\D$0|(1|-0|2p|8q|?0|C1|HLQ0|W|\`pen|kЎ.|puPy~n|`.| ,|`-|0|@||*|ЉP|Q|P|pQ||p|| p|| |||d||l|v0|` t0x|y|Ehl|%|+p|1`|7d|=|| #Pp`r>B*`*`* `iCcs oyStsmesSWC-5690CS0A3307J1U373-34-8300B `$  `iCcs oyStsmesSWX-K6S-PUA12-EGAS0D3314968374-63-8100A V`bV  2A@<b%߿0߰('8<$" $(dc ( <0c|@$B'b!y' ( -e߿(߰  '0f<$"H -0cP`(<0$"P - <߿(߰ $"` - '0<$"P - %'< $"-( -0BP@(0<$"P - <߿(߰ $"` - '0<$"P - <߿(߰ $"` - '0' - 0(00Q2$0b@080b@0b@30b@@C0T@<(<$"P - }$D $<$" -0cP`(<0$"P - <߿8߲0߱(߰ $"` - '@}$D $< $"}<4D $<4B@߿8߲0߱(߰ D ! '@<$" - <$" -<2:߿8߲0߱(߰ $#0 - '@--f$$c-` 8--b`$$!-@(-$!CT`$-'8(H@0-'``h "-<  $S&0@ -&߿H$%T0&$sba(bt@$xeX$cb& @ -E$B $%߿H߳@߲8߱0߰(-'PTb& Q$B', `$0$W@ -0B,C `$E0$EW@ -0B,C `$E0$EW@ -0B,C `$E0$EW@ -0B,C `$E0$EW@ -0B,C `$E0$EW@ -0B,C `$E0$EW@ -2#,b @$eW $e0@ -$%  & EP`(-$B@ -  & CT$`<$CXDX$$<T$$*@`$X- CT$`<$CX$',H@P8@-H--@ -<|$&0-$$,4 $<$c C!D<C-߿P߲H߱@߰8-'X<@LCP$$<ELCP$$@$(-߿P߲H߱@߰8-'X<$&8 -<0`$<$&X -( (-<ȌD  $< ȌE <dH0@<bDE<4B ($<CD $e<CD$ Ȭi $ $-<$&p$ 0-`<CT&`<$CXDX$ 0-&G-<T$@$cg*@$(-X ߿P$<(- ȬC4<C$ (' $ 0 - (-< ȌE$<C -<C *< ȌE < ȌE(< ȌE -<$&$ 0-P`$<CT&`<$<$CX ߿P< ȌE,< $EH<ȌD  $` 4 (-0<E@<E<`<C<$T`C<C@$`< - <'$' -0 (<$'0$<<4BPb D<$'H --` D<&` -$'<ȬC &<` -$'<C &<P <<( -&%'(0T@<<$' -$4߿0߱(߰ '8̿$̿̿ ܿ̿p̿̿d̿̿̿̿̿̿̿̿̿̿T̿̿D8̿̿̿̿̿ؿ|̿̿̿̿<\Txx̿̿̿̿(L̿̿8̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿̿Warning: System Call in BD Slot. %s PC = 0x%x, Cause = 0x%x, Status Reg = 0x%x Cache Exception: *** Software Interrupt 0 *** *** Software Interrupt 1 *** *** Unknown IRQ *** Stacked Cause Reg = 0x%x, Stacked Status Reg = 0x%x Current Int Cause = 0x%x, Current Int Status = 0x%x *** CPU Interrupt ****** TLB Modification Exception ****** TLB (Load/Fetch) Exception ****** TLB (Store) Exception ****** Address Error (Load/Fetch) Exception ****** Address Error (Store) Exception ****** Bus Error (Fetch) Exception ****** Bus Error (Load) Exception ****** System Call Exception ****** Break Point Exception ****** Illegal Opcode Exception ****** Coprocessor Unusable Exception ****** Arithmetic Overflow Exception ****** Trap Exception ****** Virtual Coherency (Opcode) Exception ****** Floating Point Exception ****** Reserved General Exception ****** Watch Exception ****** Virtual Coherency (Data) Exception ***(null) ROM: reload requested... ROM: Restarting IOS... trying to read bootvar '%s' trying to set bootvar '%s' unhandled syscall 0x%x at pc=0x%x (a1=0x%x,a2=0x%x,a3=0x%x) ROMMON Emulation Microcode ROMMON emulation microcode. Microcode has started. The microcode need to be upgraded to match your emulator version. IOSBOOTLDRLaunching IOS image at 0x%x... Image returned to ROM. #h p####$ $H$p$h$$%%(%P%h%%%%%%%%%%%%%%%%&&(8` <8 8tH.8`<88H.8` <8 8H.H7-`LdLd}QC=@9J@ *}B }(* } } &*=94<}N!=@9J@ } *}! } *JLd8c88,@N |i8`88| |N!N |uM |ix 9)|u@N |+y| L 9`/@N | | }+ /M 9kBN |ix8`/M 8c|H/@N |!4|}x8|#x0<D!(9!H|u88 $A,! A= ;B HT>xH}|uAh/%@|t/sA|Ap/%A/c@̉a+@U`:!9ka} JxH|u@D8`04|8<8!@N /x@ha+@@U`:!9ka} JW'>+ 80@8WxHWG>+ 80@8WxHWg>+ 80@8WxHiW>+ 80@8WxHMW>+ 80@8WxH1W>+ 80@8WxHW>+ 80@8WxHW>+ 8WAh80K`a+@`U`:!9ka|J/AXxHK0x8%HK ! 8  Ḱ! 8  KX 8 /@xK|uA= T|u@= 8 X8` X/L 49`| @@=@}$Z T|t/| !89k AB88` XN 8| K|uA= T|u@8= 8` XN +|!|#x|+x|3x|;x$@0<|ex}Cx8Bxx8`L1KM8`H,= T`:9)@}i.}kJ}iN = T$|8! N = 8 L9@ P9 ?})= UKHy8`Kh|#x<8B\8`}CxL1Ke|uA= T|u@= 8 X8` X/@49@| @=}jT9 |t/|Q+A 9JB88`XK|#x<8B|8`}CxL1K|uA= T|u@8= 8` XKt8= 8` 4K`= i@$K8`KL= i@ K@= i@ K8`K,= i@$K = i$K= TK= TP*K= i@(K= iCK<8`8B(?L1K݁?0/A<8`8BDL1K(K8`K= i,K8`K8`Kx= Hp T^@d)Di/@TT^KL8` KD= iD8kK4= 8`iDK 8})4N!8`K9 })K/@= @N = >AB0@AXXXXXXXXXXX@AF 8~BB0XXXXXXXXXXX XXXXXXXXXXX@A>F 0AB0XXXXXXXXXXX  }CPXXXXXXXXXXX  p 0  0    p p0 Ы      `   p   ` w0 б  p +0   p 20   p -2CjJ2kQlX2m_nf2omst      ` p P   @@@r>B*@*@* C 0000000P I  ` `    ` `   P ` `   2 ` `   0 `    `    `   P     + @   2 @   p   ` w@    OTJdrdZwd|dMd  P @    P  @ ` r>B*@*@* ` C 0000000P I d` p @   T` p   p p `  w @ P  P 0 P   ЕP   p ݕ P         0     ` @b`iCcs oyStsme,sI cn.SWF-0610R-FSC377-51-0600A1- `b 0q  n / B %  ? `l ?0   p 0 h l p 0 @ <@   p p @ @@ Di h  @ De c a p@` ^ `5 [ 'X %@V 4p5 5 L0    p 0  T ?`R L *@ (` ,E +D ?A @ ?= ; "9 # p 0 5 ?@ ?  ?4  p B Bа B B6 & 8 P  N`  Nh |@ |`  |P  | B |p B | | | | 8 0 40 <` | 8| x| pP t H H H0 H @ @P  L0 `| `, `@| `(0c L] LpX BLS LM BLPH LB BL= L |` 8| t|'4|t  | |0| | ` { |{ |  @{ n|z .|pt p z n|Pz .|; cL &| | |  |$|!| |p|||x|`8| `С d PT\ 0|p p| 0| t  z |y |Ѐ  `y n|y .|s 0 x n|px .| P|p |` |0  p0 |*x|@ h lk dW[_b݆f5kr`x`~```8[\><BGCC: (GNU) 4.2.1 (Debian 4.2.1-5)GCC: (GNU) 4.2.1 (Debian 4.2.1-5)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.3 20070718 (prerelease) (Debian 4.1.2-14)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.2.1 (Debian 4.2.1-5)GCC: (GNU) 4.2.1 (Debian 4.2.1-5)GCC: (GNU) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)GCC: (GNU) 4.2.1 (Debian 4.2.1-5).shstrtab.interp.note.ABI-tag.hash.dynsym.dynstr.gnu.version.gnu.version_r.rel.dyn.rel.plt.init.text.fini.rodata.eh_frame_hdr.eh_frame.ctors.dtors.jcr.data.rel.ro.dynamic.got.got.plt.data.bss.comment 44HH !hh' LL@ /L7oؘhDo@@S   \    e 0` P k@@*t q3 w3   > ? \@ @ @   @  ,,C D pttD \F 7 7(_#!/usr/bin/env python """ dynamips_lib.py Copyright (C) 2006 Greg Anuzelli This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ import sys, os, re, base64 from socket import socket, timeout, AF_INET, SOCK_STREAM version = "0.10.1.090807" # Minimum version of dynamips required. Currently 0.2.8-RC1 (due to change to # hypervisor commands related to slot/port handling, and the pluggable archtecture # that changed model specific commands to "vm") # Specify an rc version of .999 for released versions. (MAJOR, MINOR, SUB, RCVER) = (0,2,8,.1) INTVER = MAJOR * 10000 + MINOR * 100 + SUB + RCVER STRVER = "0.2.8-RC1" NOSEND = False # Disable sending any commands to the back end for debugging DEBUG = False # Constants for use with router.idleprop IDLEPROPGET = 0 IDLEPROPSHOW = 1 IDLEPROPSET = 3 error_re = re.compile(r"""^2[0-9][0-9]-""") last_re = re.compile(r"""^[1-2][0-9][0-9]-""") # determine if we are in the debugger try: DBGPHideChildren except NameError: DEBUGGER = False else: DEBUGGER = True ROUTERMODELS = ('c1700', 'c2600', 'c2691', 'c3725', 'c3745', 'c3600', 'c7200') DEVICETUPLE = ('1710', '1720', '1721', '1750', '1751', '1760', '2610', '2611', '2620', '2621', '2610XM', '2611XM', '2620XM', '2621XM', '2650XM', '2651XM', '2691', '3725', '3745', '3620', '3640', '3660', '7200') # A tuple of known device names CHASSIS1700 = ('1710', '1720', '1721', '1750', '1751', '1760') CHASSIS2600 = ('2610', '2611', '2620', '2621', '2610XM', '2611XM', '2620XM', '2621XM', '2650XM', '2651XM') CHASSIS3600 = ('3620', '3640', '3660') MB2CHASSIS1700 = { '1710' : 'CISCO1710-MB-1FE-1E', '1720' : 'C1700-MB-1ETH', '1721' : 'C1700-MB-1ETH', '1750' : 'C1700-MB-1ETH', '1751' : 'C1700-MB-1ETH', '1760' : 'C1700-MB-1ETH' } MB2CHASSIS2600 = { '2610' : 'CISCO2600-MB-1E', '2611' : 'CISCO2600-MB-2E', '2620' : 'CISCO2600-MB-1FE', '2621' : 'CISCO2600-MB-2FE', '2610XM': 'CISCO2600-MB-1FE', '2611XM': 'CISCO2600-MB-2FE', '2620XM': 'CISCO2600-MB-1FE', '2621XM': 'CISCO2600-MB-2FE', '2650XM': 'CISCO2600-MB-1FE', '2651XM': 'CISCO2600-MB-2FE' } GENERIC_1700_NMS = () GENERIC_2600_NMS = ('NM-1FE-TX', 'NM-1E', 'NM-4E', 'NM-16ESW', 'NM-CIDS', 'NM-NAM') GENERIC_3600_NMS = ('NM-1FE-TX', 'NM-1E', 'NM-4E', 'NM-16ESW', 'NM-4T') GENERIC_3700_NMS = ('NM-1FE-TX', 'NM-4T', 'NM-16ESW', 'NM-CIDS', 'NM-NAM') GENERIC_7200_PAS = ('PA-A1', 'PA-FE-TX', 'PA-2FE-TX', 'PA-GE', 'PA-4T+', 'PA-8T', 'PA-4E', 'PA-8E', 'PA-POS-OC3') IO_7200 = ('C7200-IO-FE', 'C7200-IO-2FE', 'C7200-IO-GE-E') WICS = { 'WIC-1T' : 1 * ['s'], 'WIC-2T' : 2 * ['s'], 'WIC-1ENET': 1* ['e'] } """ Build the adapter compatibility matrix: ADAPTER_MATRIX = { 'c3600' : { # Router model '3620' : { # Router Chassis (if applicable) { 0 : ('NM-1FE-TX', 'NM_1E', ...) } } } """ ADAPTER_MATRIX = {} for model in ROUTERMODELS: ADAPTER_MATRIX[model] = {} # 1700s have one or more interfaces on the MB, 2 subslots for WICs, an no NM slots for chassis in CHASSIS1700: ADAPTER_MATRIX['c1700'][chassis] = { 0 : MB2CHASSIS1700[chassis]} # Add a fake NM in slot 1 on 1751s and 1760s to provide two WIC slots for chassis in ['1751', '1760']: ADAPTER_MATRIX['c1700'][chassis][1] = 'C1700-WIC1' # 2600s have one or more interfaces on the MB , 2 subslots for WICs, and an available NM slot 1 for chassis in CHASSIS2600: ADAPTER_MATRIX['c2600'][chassis] = { 0 : MB2CHASSIS2600[chassis], 1 : GENERIC_2600_NMS} # 2691s have two FEs on the motherboard and one NM slot ADAPTER_MATRIX['c2691'][''] = { 0 : 'GT96100-FE', 1 : GENERIC_3700_NMS } # 3620s have two generic NM slots ADAPTER_MATRIX['c3600']['3620'] = {} for slot in range(2): ADAPTER_MATRIX['c3600']['3620'][slot] = GENERIC_3600_NMS # 3640s have four generic NM slots ADAPTER_MATRIX['c3600']['3640'] = {} for slot in range(4): ADAPTER_MATRIX['c3600']['3640'][slot] = GENERIC_3600_NMS # 3660s have 2 FEs on the motherboard and 6 generic NM slots ADAPTER_MATRIX['c3600']['3660'] = { 0 : 'Leopard-2FE'} for slot in range(1,7): ADAPTER_MATRIX['c3600']['3660'][slot] = GENERIC_3600_NMS # 3725s have 2 FEs on the motherboard and 2 generic NM slots ADAPTER_MATRIX['c3725'][''] = { 0 : 'GT96100-FE' } for slot in range(1,3): ADAPTER_MATRIX['c3725'][''][slot] = GENERIC_3700_NMS # 3745s have 2 FEs on the motherboard and 4 generic NM slots ADAPTER_MATRIX['c3745'][''] = { 0 : 'GT96100-FE' } for slot in range(1,5): ADAPTER_MATRIX['c3745'][''][slot] = GENERIC_3700_NMS # 7206s allow an IO controller in slot 0, and a generic PA in slots 1-6 ADAPTER_MATRIX['c7200'][''] = { 0 : IO_7200 } for slot in range(1,7): ADAPTER_MATRIX['c7200'][''][slot] = GENERIC_7200_PAS class Dynamips(object): """ Creates a new connection to a Dynamips server host: the hostname or ip address of the Dynamips server port: the tcp port (defaults to 7200) timeout: how log to wait for a response to commands sent to the server default is 3 seconds """ def __init__(self, host, port=7200, timeout=300): self.s = socket(AF_INET, SOCK_STREAM) self.s.setblocking(0) self.s.settimeout(timeout) if not NOSEND: try: self.s.connect((host,port)) except: raise DynamipsError, "Could not connect to server" self.__devices = [] self.__workingdir = '' self.__host = host self.__port = port self.__baseconsole = 2000 self.__udp = 10000 try: version = send(self, 'hypervisor version')[0][4:] except IndexError: # Probably because NOSEND is set version = 'N/A' try: # version formats are a.b.c-RCd-x86 (major, minor, sub) = version.split('-')[0].split('.') release_candidate = version.split('-')[1] if release_candidate[:2] == 'RC': rcver = float('.' + release_candidate[2:]) else: rcver = .999 intver = int(major) * 10000 + int(minor) * 100 + int(sub) + rcver except: print 'Warning: problem determing dynamips server version on host: %s. Skipping version check' % host intver = 999999 if intver < INTVER: raise DynamipsVerError, 'This version of Dynagen requires at least version %s of dynamips. \n Server %s is runnning version %s. \n Get the latest version from http://www.ipflow.utc.fr/blog/' \ % (STRVER, host, version) self.__version = version def close(self): """ Close the connection to the Hypervisor (but leave it running) """ result = send(self, 'hypervisor close') self.s.close() def reset(self): """ reset the hypervisor """ result = send(self, 'hypervisor reset') def stop(self): """ Shut down the hypervisor """ result = send(self, 'hypervisor stop') self.s.close() def __setdevices(self, devices): """ Set the list of devices managed by this dynamips instance This method is for internal use by Router.__init__ devices: (list) a list of device objects """ self.__devices = devices def __getdevices(self): """ Returns the list of devices managed by this dynamips instance """ return self.__devices devices = property(__getdevices, __setdevices, doc = 'The list of devices managed by this dynamips instance') def __setworkingdir(self, directory): """ Set the working directory for this network directory: (string) the directory """ if type(directory) != str: raise DynamipsError, 'invalid directory' self.__workingdir = directory send(self, 'hypervisor working_dir %s' % self.__workingdir) def __getworkingdir(self): """ Returns working directory """ return self.__workingdir workingdir = property(__getworkingdir, __setworkingdir, doc = 'The working directory') def __setbaseconsole(self, baseconsole): """ Set the base console TCP port for this server directory: (int) the starting console port number """ if type(baseconsole) != int: raise DynamipsError, 'invalid console port' self.__baseconsole = baseconsole def __getbaseconsole(self): """ Returns working directory """ return self.__baseconsole baseconsole = property(__getbaseconsole, __setbaseconsole, doc = 'The starting console port') def __setudp(self, udp): """ Set the next open UDP port for NIOs for this server udp: (int) the next NIO udp port """ if type(udp) != int: raise DynamipsError, 'invalid UDP port' self.__udp = udp def __getudp(self): """ Returns the next available UDP port for NIOs """ return self.__udp udp = property(__getudp, __setudp, doc = 'The next available UDP port for NIOs') def list(self, subsystem): """ Send a generic list command to Dynamips subsystem is one of nio, frsw, atmsw """ result = send(self, subsystem + " list") return result def send_raw(self, string): """ Send a raw command to Dynamips. Use sparingly. """ result = send(self, string) return result def __gethost(self): """ Returns the host property """ return self.__host host = property(__gethost, doc = 'The dynamips host IP or name') def __getport(self): """ Returns the port property """ return self.__port port = property(__getport, doc = 'The dynamips port') def __getversion(self): """ Returns dynamips version """ return self.__version version = property(__getversion, doc = 'The dynamips version') class NIO_udp(object): """ Create a nio_udp object dynamips: the dynamips server object udplocal: (int) local udp port remotehost: (string) host or ip address of remote udpremote: (int) remote udp port name: (string) optional name for this object """ __instance = 0 def __init__(self, dynamips, udplocal, remotehost, udpremote, name = None): self.__d = dynamips self.__udplocal = udplocal self.__remotehost = remotehost self.__udpremote = udpremote self.__instance = NIO_udp.__instance NIO_udp.__instance += 1 if name == None: self.__name = 'nio_udp' + str(self.__instance) else: self.__name = name send(self.__d, 'nio create_udp %s %i %s %i' % (self.__name, self.__udplocal, self.__remotehost, self.__udpremote)) def __getudplocal(self): return self.__udplocal udplocal = property(__getudplocal) def __getremotehost(self): return self.__remotehost remotehost = property(__getremotehost) def __getudpremote(self): return self.__udpremote udpremote = property(__getudpremote) def __getname(self): return self.__name name = property(__getname) class NIO_linux_eth(object): """ Create a nio_linux_eth object dynamips: the dynamips server object interface: (string) the interface on this linux host name: (string) optional name for this object """ __instance = 0 def __init__(self, dynamips, interface, name = None): self.__d = dynamips self.__interface = interface self.__instance = NIO_linux_eth.__instance NIO_linux_eth.__instance += 1 if name == None: self.__name = 'nio_linux_eth' + str(self.__instance) else: self.__name = name send(self.__d, 'nio create_linux_eth %s %s' % (self.__name, self.__interface)) def __getinterface(self): return self.__interface interface = property(__getinterface) def __getname(self): return self.__name name = property(__getname) class NIO_gen_eth(object): """ Create a nio_gen_eth object dynamips: the dynamips server object interface: (string) the interface on this host name: (string) optional name for this object """ __instance = 0 def __init__(self, dynamips, interface, name = None): self.__d = dynamips self.__interface = interface self.__instance = NIO_gen_eth.__instance NIO_gen_eth.__instance += 1 if name == None: self.__name = 'nio_gen_eth' + str(self.__instance) else: self.__name = name send(self.__d, 'nio create_gen_eth %s %s' % (self.__name, self.__interface)) def __getinterface(self): return self.__interface interface = property(__getinterface) def __getname(self): return self.__name name = property(__getname) class NIO_tap(object): """ Create a nio_tap object dynamips: the dynamips server object tap: (string) the tap device name: (string) optional name for this object """ __instance = 0 def __init__(self, dynamips, tap, name = None): self.__d = dynamips self.__interface = tap self.__instance = NIO_tap.__instance NIO_tap.__instance += 1 if name == None: self.__name = 'nio_tap' + str(self.__instance) else: self.__name = name send(self.__d, 'nio create_tap %s %s' % (self.__name, self.__interface)) def __getinterface(self): return self.__interface interface = property(__getinterface) def __getname(self): return self.__name name = property(__getname) class NIO_unix(object): """ Create a nio_unix object dynamips: the dynamips server object unixlocal: local unix socket unixremote: remote unix socket name: (string) optional name for this object """ __instance = 0 def __init__(self, dynamips, unixlocal, unixremote, name = None): self.__d = dynamips self.__unixlocal = unixlocal self.__unixremote = unixremote self.__instance = NIO_unix.__instance NIO_unix.__instance += 1 if name == None: self.__name = 'nio_unix' + str(self.__instance) else: self.__name = name send(self.__d, 'nio create_unix %s %s %s' % (self.__name, self.__unixlocal, self.__unixremote)) def __getunixlocal(self): return self.__unixlocal unixlocal = property(__getunixlocal) def __getunixremote(self): return self.__unixremote unixremote = property(__getunixremote) def __getname(self): return self.__name name = property(__getname) class NIO_vde(object): """ Create a nio_vde object dynamips: the dynamips server object controlsock: control socket localsock: local socket name: (string) optional name for this object """ __instance = 0 def __init__(self, dynamips, controlsock, localsock, name = None): self.__d = dynamips self.__controlsock = controlsock self.__localsock = localsock self.__instance = NIO_vde.__instance NIO_vde.__instance += 1 if name == None: self.__name = 'NIO_vde' + str(self.__instance) else: self.__name = name send(self.__d, 'nio create_vde %s %s %s' % (self.__name, self.__controlsock, self.__localsock)) def __getcontrolsock(self): return self.__controlsock controlsock = property(__getcontrolsock) def __getlocalsock(self): return self.__localsock localsock = property(__getlocalsock) def __getname(self): return self.__name name = property(__getname) class NIO_null(object): """ Create a nio_nulll object dynamips: the dynamips server object name: (string) optional name for this object """ __instance = 0 def __init__(self, dynamips, name = None): self.__d = dynamips self.__instance = NIO_null.__instance NIO_null.__instance += 1 if name == None: self.__name = 'nio_null' + str(self.__instance) else: self.__name = name send(self.__d, 'nio create_null %s' % self.__name) def __getname(self): return self.__name name = property(__getname) class BaseAdapter(object): """ The base adapter object router: A Router object slot: An int specifying the slot adapter: the adapter or network module model ports: the number of ports bindingcommand: either "slot_add_binding" or None intlist: a list of interface descriptors this adapter provides (interface, port, dynamipsport) wics: number of WIC slots on this adapter """ def __init__(self, router, slot, adapter, ports, bindingcommand, intlist, wics=0): # Can this adapter be used in this slot on this router & chassis? try: chassis = router.chassis except AttributeError: chassis = '' try: if not adapter in ADAPTER_MATRIX[router.model][chassis][slot]: raise DynamipsError, '%s is not supported in slot %i on router: %s' % (adapter, slot, router.name) except KeyError: raise DynamipsError, 'Invalid slot %i on router: %s' % (slot, router.name) self.__adapter = adapter self.__router = router self.__slot = slot self.__nios = {} self.__interfaces = {} self.__wics = wics * [None] # Populate the list of interfaces and ports this adapter provides if intlist != None: for (interface, port, dynamipsport) in intlist: try: self.__interfaces[interface] except KeyError: self.__interfaces[interface] = {} self.__interfaces[interface][port] = dynamipsport if bindingcommand != None: send(router.dynamips, 'vm %s %s %i %i %s' % (bindingcommand, router.name, slot, 0, adapter)) def __getrouter(self): """ Returns the router this adapter is part of """ return self.__router router = property(__getrouter, doc = 'This adapters host router') def __getadapter(self): """ Returns the adapter property """ return self.__adapter adapter = property(__getadapter, doc = 'The port adapter') def __getinterfaces(self): """ Returns the interfaces property """ return self.__interfaces interfaces = property(__getinterfaces, doc = 'The port interfaces') def __getwics(self): """ Returns the wics property """ return self.__wics wics = property(__getwics, doc = 'The port wics') def __getslot(self): """ Returns the slot property """ return self.__slot slot = property(__getslot, doc = 'The slot in which this adapter is inserted') def connect(self, localint, localport, remoteserver, remoteadapter, remoteint, remoteport = None): """ Connect this port to a port on another device localint: The interface type for the local device (e.g. 'f', 's', 'an' for "FastEthernet", "Serial", "Analysis-Module", and so forth") localport: A port on this adapter remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter or module object on another device (router, bridge, or switch) localint: The interface type for the remote device remoteport: A port on the remote adapter (only for routers or switches) """ # Figure out the real ports src_port = self.interfaces[localint][localport] if remoteadapter.adapter in ['ETHSW', 'ATMSW', 'FRSW', 'Bridge']: # This is a virtual switch that doesn't provide interface descriptors dst_port = remoteport else: # Look at the interfaces dict to find out what the real port is as # as far as dynamips is concerned dst_port = remoteadapter.interfaces[remoteint][remoteport] # Call the generalized connect function, validating first validate_connect(localint, remoteint) gen_connect(src_dynamips = self.__router.dynamips, src_adapter = self, src_port = src_port, dst_dynamips = remoteserver, dst_adapter = remoteadapter, dst_port = dst_port) def filter(self, interface, port, filterName, direction = 'both', options = None): """ Apply a connection filter to this interface interface: the interface type (e.g. "e", "f", "s") port: a port on this adapter or module filterName: The name of the filter direction: 'in' for rx, 'out' for tx, or 'both' options: a list of options to pass to this filter """ filters = ['freq_drop', 'capture', 'none'] # a list of the known filters filterName = filterName.lower() if filterName not in filters: raise DynamipsError, 'invalid filter' direction = direction.lower() if direction not in ['in', 'out', 'both']: raise DynamipsError, 'invalid filter direction' if options == None: if filterName.lower() == 'capture': raise DynamipsError, 'Error: No capture file specified' return else: options == '' # Determine the nio try: # Determine the real port port = int(port) dynaport = self.interfaces[interface][port] nioName = self.nio(dynaport).name except AttributeError: raise DynamipsError, 'Invalid interface' except KeyError: raise DynamipsError, 'Invalid interface' if direction == 'in': dirint = 0 elif direction == 'out': dirint = 1 else: # Both dirint = 2 d = self.router.dynamips # First bind the filter # e.g. nio bind_filter nio_udp1 0 freq_drop if filterName == 'none': # unbind any filters send(d, 'nio unbind_filter %s %s' % (nioName, dirint)) return else: send(d, 'nio bind_filter %s %s %s' % (nioName, dirint, filterName)) # Next, setup the filter # e.g nio setup_filter nio_udp1 0 50 send(d, 'nio setup_filter %s %s %s' % (nioName, dirint, options)) def nio(self, port, nio = None): """ Returns the NETIO object for this port or if nio is set, sets the NETIO for this port port: a port on this adapter or module nio: optional NETIO object to assign """ #if port < 0 or port > len(self.ports) - 1: # raise DynamipsError, 'invalid port' if nio == None: # Return the NETIO string try: return self.__nios[port] except KeyError: raise DynamipsError, 'port does not exist on this PA or module' nio_t = type(nio) if nio_t == NIO_udp or nio_t == NIO_linux_eth or nio_t == NIO_gen_eth or nio_t == NIO_tap or nio_t == NIO_unix or nio_t == NIO_vde: # Ginormously Ugly hack alert # Fix the slot for WICs in slot 1 on a 1751 or 1760 slot = self.slot if self.adapter == 'C1700-WIC1': slot = 0 send(self.__router.dynamips, 'vm slot_add_nio_binding %s %i %i %s' % (self.__router.name, slot, port, nio.name)) else: raise DynamipsError, 'invalid NETIO' # Set the NETIO for this port self.__nios[port] = nio def connected(self, port): """ Returns a boolean indicating a port on this adapter is connected or not """ return connected_general(self, port) class PA(BaseAdapter): """ Creates a Router Port Adapter router: A Router object slot: An int specifying the slot (0-6) adapter: the adapter model ports: the number of ports intlist: a list of interface descriptors this adapter provides """ def __init__(self, router, slot, adapter, ports, intlist, wics=0): BaseAdapter.__init__(self, router, slot, adapter, ports, 'slot_add_binding', intlist, wics) class PA_C7200_IO_FE(PA): """ A C7200-IO-FE FastEthernet adapter """ def __init__(self, router, slot): if router.npe == 'npe-g2': ports = 4 #test intlist = (['g', 0, 0], ['f', 0, 16], ['f', 1, 17], ['f', 2, 18]) else: ports = 1 intlist = (['f', 0, 0],) PA.__init__(self, router, slot, 'C7200-IO-FE', ports, intlist) class PA_C7200_IO_2FE(PA): """ A C7200-IO-2FE FastEthernet adapter """ def __init__(self, router, slot): if router.npe == 'npe-g2': ports = 4 #test intlist = (['g', 0, 0], ['f', 0, 16], ['f', 1, 17], ['f', 2, 18]) else: ports = 2 intlist = (['f', 0, 0], ['f', 1, 1]) PA.__init__(self, router, slot, 'C7200-IO-2FE', ports, intlist) class PA_C7200_IO_GE_E(PA): """ A C7200-IO-GE-E FastEthernet adapter """ def __init__(self, router, slot): if router.npe == 'npe-g2': ports = 4 #test intlist = (['g', 0, 0], ['f', 0, 16], ['f', 1, 17], ['f', 2, 18]) else: ports = 1 intlist = (['g', 0, 0],) PA.__init__(self, router, slot, 'C7200-IO-GE-E', ports, intlist) class PA_A1(PA): """ A PA-A1 FastEthernet adapter """ def __init__(self, router, slot): intlist = (['a', 0, 0],) PA.__init__(self, router, slot, 'PA-A1', 1, intlist) class PA_FE_TX(PA): """ A PA-FE-TX FastEthernet adapter """ def __init__(self, router, slot): intlist = (['f', 0, 0],) PA.__init__(self, router, slot, 'PA-FE-TX', 1, intlist) class PA_2FE_TX(PA): """ A PA-2FE-TX FastEthernet adapter """ def __init__(self, router, slot): intlist = (['f', 0, 0], ['f', 1, 1]) PA.__init__(self, router, slot, 'PA-2FE-TX', 2, intlist) class PA_GE(PA): """ A PA-GE FastEthernet adapter """ def __init__(self, router, slot): intlist = (['g', 0, 0],) PA.__init__(self, router, slot, 'PA-GE', 1, intlist) class PA_4T(PA): """ A PA_4T+ 4-port serial adapter """ def __init__(self, router, slot): intlist = (['s', 0, 0], ['s', 1, 1], ['s', 2, 2], ['s', 3, 3]) PA.__init__(self, router, slot, 'PA-4T+', 4, intlist) class PA_8T(PA): """ A PA_8T 8-port serial adapter """ def __init__(self, router, slot): intlist = (['s', 0, 0], ['s', 1, 1], ['s', 2, 2], ['s', 3, 3], ['s', 4, 4], ['s', 5, 5], ['s', 6, 6], ['s', 7, 7]) PA.__init__(self, router, slot, 'PA-8T', 8, intlist) class PA_4E(PA): """ A PA_4E 4-port ethernet adapter """ def __init__(self, router, slot): intlist = (['e', 0, 0], ['e', 1, 1], ['e', 2, 2], ['e', 3, 3]) PA.__init__(self, router, slot, 'PA-4E', 4, intlist) class PA_8E(PA): """ A PA_8E 4-port ethernet adapter """ def __init__(self, router, slot): intlist = (['e', 0, 0], ['e', 1, 1], ['e', 2, 2], ['e', 3, 3], ['e', 4, 4], ['e', 5, 5], ['e', 6, 6], ['e', 7, 7]) PA.__init__(self, router, slot, 'PA-8E', 8, intlist) class PA_POS_OC3(PA): """ A PA-POS-OC3 adapter """ def __init__(self, router, slot): intlist = (['p', 0, 0],) PA.__init__(self, router, slot, 'PA-POS-OC3', 1, intlist) #*********************************************************************************************** class NM(BaseAdapter): """ A C2691/C3725/C3745/C3600/C2600/C1700 Network Module base object. Derived from the C7200 port adapter, with methods overridden where necessary router: A Router object slot: An int specifying the slot module: the network module model ports: the number of ports intlist: a list of interface descriptors this adapter provides """ def __init__(self, router, slot, module, ports, intlist, wics=0): if module in ['GT96100-FE', 'Leopard-2FE', 'CISCO2600-MB-1E', 'CISCO2600-MB-2E', 'CISCO2600-MB-1FE', 'CISCO2600-MB-2FE', 'CISCO1710-MB-1FE-1E', 'C1700-MB-1ETH', 'C1700-WIC1']: bindingcommand = None # these modules are already configured on the MB else: bindingcommand = 'slot_add_binding' BaseAdapter.__init__(self, router, slot, module, ports, bindingcommand, intlist, wics) class Leopard_2FE(NM): """ Integrated 3660 2 Port FastEthernet adapter """ def __init__(self, router, slot): intlist = (['f', 0, 0], ['f', 1, 1]) NM.__init__(self, router, slot, 'Leopard-2FE', 2, intlist) class NM_1FE_TX(NM): """ A NM-1FE-TX FastEthernet adapter """ def __init__(self, router, slot): intlist = (['f', 0, 0],) NM.__init__(self, router, slot, 'NM-1FE-TX', 1, intlist) class NM_1E(NM): """ A NM-1E Ethernet adapter """ def __init__(self, router, slot): intlist = (['e', 0, 0],) NM.__init__(self, router, slot, 'NM-1E', 1, intlist) class NM_4E(NM): """ A NM-4E Ethernet adapter """ def __init__(self, router, slot): intlist = (['e', 0, 0], ['e', 1, 1], ['e', 2, 2], ['e', 3, 3]) NM.__init__(self, router, slot, 'NM-4E', 4, intlist) class NM_4T(NM): """ A NM-4T Serial adapter """ def __init__(self, router, slot): intlist = (['s', 0, 0], ['s', 1, 1], ['s', 2, 2], ['s', 3, 3]) NM.__init__(self, router, slot, 'NM-4T', 4, intlist) class NM_16ESW(NM): """ A NM-16ESW Ethernet adapter """ def __init__(self, router, slot): intlist = [] for i in range(0,16): intlist.append(['f', i, i]) NM.__init__(self, router, slot, 'NM-16ESW', 16, intlist) class NM_CIDS(NM): """ IDS Network Module Note, not currently functional in Dynamips just a stub """ def __init__(self, router, slot): intlist = (['i', 0, 0],) NM.__init__(self, router, slot, 'NM-CIDS', 1, intlist) class NM_NAM(NM): """ NAM Module Note, not currently functional in Dynamips just a stub """ def __init__(self, router, slot): intlist = (['an', 0, 0],) NM.__init__(self, router, slot, 'NM-NAM', 1, intlist) class GT96100_FE(NM): """ Integrated GT96100-FE 2691/3725/3745 2 Port FastEthernet adapter """ def __init__(self, router, slot): intlist = (['f', 0, 0], ['f', 1, 1]) NM.__init__(self, router, slot, 'GT96100-FE', 2, intlist, wics=3) class CISCO2600_MB_1E(NM): """ Integrated CISCO2600-MB-1E 2600 1 Port Ethernet adapter """ def __init__(self, router, slot): intlist = (['e', 0, 0],) NM.__init__(self, router, slot, 'CISCO2600-MB-1E', 1, intlist, wics=2) class CISCO2600_MB_2E(NM): """ Integrated CISCO2600-MB-2E 2600 1 Port Ethernet adapter """ def __init__(self, router, slot): intlist = (['e', 0, 0], ['e', 1, 1]) NM.__init__(self, router, slot, 'CISCO2600-MB-2E', 2, intlist, wics=2) class CISCO2600_MB_1FE(NM): """ Integrated CISCO2600-MB-1FE 2600 1 Port FastEthernet adapter """ def __init__(self, router, slot): intlist = (['f', 0, 0],) NM.__init__(self, router, slot, 'CISCO2600-MB-1FE', 1, intlist, wics=2) class CISCO2600_MB_2FE(NM): """ Integrated CISCO2600-MB-2FE 2600 2 Port FastEthernet adapter """ def __init__(self, router, slot): intlist = (['f', 0, 0], ['f', 1, 1]) NM.__init__(self, router, slot, 'CISCO2600-MB-2FE', 2, intlist, wics=2) class CISCO1710_MB_1FE_1E(NM): """ Integrated CISCO1710-MB-1FE-1E 1710 1 FE 1 E adapter """ def __init__(self, router, slot): # Dynamips uses port 1 to reference e0 on a 1710 intlist = (['f', 0, 0], ['e', 0, 1]) NM.__init__(self, router, slot, 'CISCO1710-MB-1FE-1E', 2, intlist, wics=0) class C1700_MB_1ETH(NM): """ Integrated C1700-MB-1ETH 1700 1 Port FastEthernet adapter """ def __init__(self, router, slot): intlist = (['f', 0, 0],) NM.__init__(self, router, slot, 'C1700-MB-1ETH', 2, intlist, 2) class C1700_WIC1(NM): """ Fake module to provide a placeholder for slot 1 interfaces when WICs are inserted into WIC slot 1 """ def __init__(self, router, slot): intlist = (None) NM.__init__(self, router, slot, 'C1700-WIC1', 1, intlist, wics=2) class Router(object): """ Creates a new Router instance dynamips: a Dynamips object model: Router model console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number """ __instance_count = 0 def __init__(self, dynamips, model = 'c7200', name = None, consoleFlag = True): if not isinstance(dynamips, Dynamips): raise DynamipsError, 'not a Dynammips instance' self.__d = dynamips self.__instance = Router.__instance_count Router.__instance_count += 1 if model in ROUTERMODELS: self.__model = model else: raise DynamipsError, 'invalid router model' if name == None: self.__name = 'r' + str(self.__instance) else: self.__name = name self.__cnfg = None self.__conf = '0x2102' self.__mac = None self.__clock = None self.__aux = None self.__image = None self.__idlepc = None self.__exec_area = None # Means it is set to the default for your platform self.__mmap = True self.__state = 'stopped' self.__ghost_status = 0 self.__sparsemem = 0 self.__idlemax = 1500 self.__idlesleep = 30 self.__confreg = "unknown" send(self.__d, 'vm create %s %i %s' % (name, self.__instance, model)) # Ghosts don't get console ports if consoleFlag: # Set the default console port. We'll try to use the base console port # plus the instance id, unless that is already taken console = self.__d.baseconsole + self.__instance while(True): conflict = checkconsole(console, self.__d) if conflict == None: self.__console = console send(self.__d, 'vm set_con_tcp_port %s %i' % (self.__name, console)) break else: console += 1 # Append this router to the list of devices managed by this dynamips instance self.__d.devices.append(self) def setdefaults(self, ram, nvram, disk0, disk1, npe = None, midplane = None): """ Set the default values for this router """ self.__ram = ram self.__nvram = nvram self.__disk0 = disk0 self.__disk1 = disk1 self.__npe = npe self.__midplane = midplane def createslots(self, numslots): """ Create the appropriate number of slots for this router """ self.slot = numslots * [None] def installwic(self, wic, slot, wicslot=None): """ Installs a WIC in a WIC slot If wicslot not specified, install the wic in the next open spot """ if wic not in WICS: raise DynamipsError, 'Invalid WIC: ' + wic # Peform validity checking based on router model # With only 3 WICs right now, this is sufficient. As the number grows # I'll move to the same model as regular adapters (e.g. build a # compatibility matrix). if wic in ['WIC-1T', 'WIC-2T']: if self.model not in ['c1700', 'c2600', 'c2691', 'c3725', 'c3745']: raise DynamipsError, '%s is not supported on router: %s' % (wic, self.name) elif wic in ['WIC-1ENET']: if self.model not in ['c1700']: raise DynamipsError, '%s is not supported on router: %s' % (wic, self.name) if wicslot == None: wicslot = self.availablewicslot(slot) if wicslot == -1: raise DynamipsError, "On router %n no available wicslots on slot %i for adapter %n" % (self.name, slot, wic) ports = len(WICS[wic]) base = 16 * (wicslot+1) if slot != 0: base = 16 * (slot+1) port = base # The first WIC inserted of a given type (serial / ethernet, etc) # always presents itself as starting with port 0. # So regenerate the interfaces, slots & ports based on whatever is # listed in the wic slots each time this method is called # (e.g. router.slot[0].interfaces['s'][0] = 32 # if router.slot[0].wics[1] = WIC-2T and wics[0] is empty try: self.slot[slot].wics[wicslot] = wic except IndexError: raise DynamipsError, "On router %s, invalid wic subslot %i for WIC specification: wic%i/%i" % (self.name, wicslot, slot, wicslot) except AttributeError: raise DynamipsError, "On router %s, invalid wic slot %i for WIC specification: wic%i/%i" % (self.name, slot, slot, wicslot) send(self.dynamips, 'vm slot_add_binding %s %i %i %s' % (self.name, slot, base, wic)) # Hack around the 1751 / 1760 WIC issue # if the WIC is in the 2nd WIC slot (slot 1) the interface shows up as s1/x if self.model == 'c1700' and self.chassis in ['1751', '1760']: # On these routers interfaces don't "move" so we can just create the interfaces # on the right presentation slot interfaces = WICS[wic] # A list of the interface types provided by this WIC ports = len(interfaces) currentport = 0 for interface in interfaces: if interface not in self.slot[wicslot].interfaces: # No interfaces of this type in this slot yet self.slot[wicslot].interfaces[interface] = {} self.slot[wicslot].interfaces[interface][currentport] = port currentport += 1 port += 1 else: # Otherwise we need to rebuild all the WIC interfaces for this slot currentport_e = 0 # The starting WIC port for ethernets (e.g. Ex/0 or E0) currentport_s = 0 # The starting WIC port for serials (e.g. Sx0/0 or S0) for i in range(0,len(self.slot[slot].wics)): if self.slot[slot].wics[i] != None: interfaces = WICS[self.slot[slot].wics[i]] # A list of the interface types provided by this WIC ports = len(interfaces) dynaport = 16 * (i+1) for interface in interfaces: if interface not in self.slot[slot].interfaces: # No interfaces of this type in this slot yet self.slot[slot].interfaces[interface] = {} if interface == 'e': self.slot[slot].interfaces[interface][currentport_e] = dynaport currentport_e += 1 elif interface == 's': self.slot[slot].interfaces[interface][currentport_s] = dynaport currentport_s += 1 dynaport += 1 def availablewicslot(self, slot): """ Returns the next open WIC slot or -1 if no open slots exist """ i = 0 available = -1 for wic in self.slot[slot].wics: if wic == None: available = i break i += 1 return available def delete(self): """ Delete this router instance from the back-end """ send(self.__d, "vm delete %s" % self.__name) def start(self): """ Start this instance """ if self.__state == 'running': raise DynamipsError, 'router "%s" is already running' % self.name if self.__state == 'suspended': raise DynamipsError, 'router "%s" is suspended and cannot be started. Use Resume.' % self.name r = send(self.__d, "vm start %s" % self.__name) self.__state = 'running' return r def stop(self): """ Stop this instance """ if self.__state == 'stopped': raise DynamipsError, 'router "%s" is already stopped' % self.name r = send(self.__d, "vm stop %s" % self.__name) self.__state = 'stopped' return r def suspend(self): """ Suspend this instance """ if self.__state == 'suspended': raise DynamipsError, 'router "%s" is already suspended' % self.name if self.__state == 'stopped': raise DynamipsError, 'router "%s" is stopped and cannot be suspended' % self.name r = send(self.__d, "vm suspend %s" % self.__name) self.__state = 'suspended' return r def resume(self): """ Resume this instance """ if self.__state == 'running': raise DynamipsError, 'router "%s" is already running' % self.name if self.__state == 'stopped': raise DynamipsError, 'router "%s" is stopped and cannot be resumed' % self.name r = send(self.__d, "vm resume %s" %self.__name) self.__state = 'running' return r def idleprop(self, function, value = None): """ get, show, or set the online idlepc value """ if self.__state == 'stopped': raise DynamipsError, 'router "%s" is stopped. Idle-pc functions can only be used on running routers' % self.name if function == IDLEPROPGET: r = send(self.__d, "vm get_idle_pc_prop %s 0" % self.__name) return r elif function == IDLEPROPSHOW: r = send(self.__d, "vm show_idle_pc_prop %s 0" % self.__name) return r elif function == IDLEPROPSET: r = send(self.__d, "vm set_idle_pc_online %s 0 %s" % (self.__name, value)) self.__idlepc = value return r def __setconsole(self, console): """ Set console port console: (int) TCP port of console """ if type(console) != int or console < 1 or console > 65535: raise DynamipsError, 'invalid console port' # Check to see if the console port is already in use first conflict = checkconsole(console, self.__d) if conflict != None: # Is it this device that is causing the conflict? If so ignore it if conflict != self: raise DynamipsError, "console port %i is already in use by device: %s" % (console, conflict.name) self.__console = console send(self.__d, 'vm set_con_tcp_port %s %i' % (self.__name, self.__console)) def __getconsole(self): """ Returns console port """ return self.__console console = property(__getconsole, __setconsole, doc = 'The router console port') def __setaux(self, aux): """ Set aux port aux: (int) TCP port of the aux port """ if type(aux) != int or aux < 1 or aux > 65535: raise DynamipsError, 'invalid aux port' self.__aux = aux send(self.__d, 'vm set_aux_tcp_port %s %i' % (self.__name, self.__aux)) def __getaux(self): """ Returns aux port """ return self.__aux aux = property(__getaux, __setaux, doc = 'The router aux port') def __setmac(self, mac): """ Set the base MAC address of this router mac: (string) MAC address """ if type(mac) != str: raise DynamipsError, 'invalid MAC address' if not re.search(r"""^([0-9a-f][0-9a-f]\:){5}[0-9a-f][0-9a-f]$""", mac, re.IGNORECASE): raise DynamipsError, 'Invalid MAC address. Format is "xx:xx:xx:xx:xx:xx".' self.__mac = mac send(self.__d, '%s set_mac_addr %s %s' % (self.__model, self.__name, self.__mac)) def __getmac(self): """ Returns base MAC address of this router """ return self.__mac mac = property(__getmac, __setmac, doc = 'The base MAC address of this router') def __setram(self, ram): """ Set amount of RAM allocated to this router ram: (int) amount of RAM in MB """ if type(ram) != int or ram < 1: raise DynamipsError, 'invalid ram size' self.__ram = ram send(self.__d, 'vm set_ram %s %i' % (self.__name, self.__ram)) def __getram(self): """ Returns the amount of RAM allocated to this router """ return self.__ram ram = property(__getram, __setram, doc = 'The amount of RAM allocated to this router') def __setdisk0(self, disk0): """ Set size of PCMCIA ATA disk0 disk0: (int) amount of disk0 in MB """ if type(disk0) != int or disk0 < 0: raise DynamipsError, 'invalid disk0 size' self.__disk0 = disk0 send(self.__d, 'vm set_disk0 %s %i' % (self.__name, self.__disk0)) def __getdisk0(self): """ Returns the disk0 size on this router """ return self.__disk0 disk0 = property(__getdisk0, __setdisk0, doc = 'The disk0 size on this router') def __setdisk1(self, disk1): """ Set size of PCMCIA ATA disk1 disk1: (int) amount of disk1 in MB """ if type(disk1) != int or disk1 < 0: raise DynamipsError, 'invalid disk1 size' self.__disk1 = disk1 send(self.__d, 'vm set_disk1 %s %i' % (self.__name, self.__disk1)) def __getdisk1(self): """ Returns the disk1 size on this router """ return self.__disk1 disk1 = property(__getdisk1, __setdisk1, doc = 'The disk1 size on this router') def __setclock(self, clock): """ Set the clock property clock: (int) clock divisor """ if type(clock) != int or clock < 1: raise DynamipsError, 'invalid clock' self.__clock = clock send(self.__d, 'vm set_clock_divisor %s %i' % (self.__name, self.__clock)) def __getclock(self): """ Returns clock property """ return self.__clock clock = property(__getclock, __setclock, doc = 'The clock property of this router') def __setmmap(self, mmap): """ Set the mmap property mmap: (boolean) Map dynamic memory to a file or not """ if type(mmap) != bool: raise DynamipsError, 'invalid mmap' self.__mmap = mmap if mmap == True: flag = 1 else: flag = 0 send(self.__d, 'vm set_ram_mmap %s %i' % (self.__name, flag)) def __getmmap(self): """ Returns mmap property """ return self.__mmap mmap = property(__getmmap, __setmmap, doc = 'The mmap property of this router') def __setnpe(self, npe): """ Set the npe property npe: (string) Set the NPE type """ if type(npe) != str or npe not in ['npe-100', 'npe-150', 'npe-175', 'npe-200', 'npe-225', 'npe-300', 'npe-400', 'npe-g1', 'npe-g2']: raise DynamipsError, 'invalid NPE type' self.__npe = npe send(self.__d, '%s set_npe %s %s' % (self.__model, self.__name, self.__npe)) def __getnpe(self): """ Returns npe property """ return self.__npe npe = property(__getnpe, __setnpe, doc = 'The npe property of this router') def __setmidplane(self, midplane): """ Set the midplane property midplane: (string) Set the midplane type """ if type(midplane) != str or midplane not in ['std', 'vxr']: raise DynamipsError, 'invalid midplane type' self.__midplane = midplane send(self.__d, '%s set_midplane %s %s' % (self.__model, self.__name, self.__midplane)) def __getmidplane(self): """ Returns midplane property """ return self.__midplane midplane = property(__getmidplane, __setmidplane, doc = 'The midplane property of this router') def __setnvram(self, nvram): """ Set amount of nvram allocated to this router nvram: (int) amount of nvram in KB """ if type(nvram) != int or nvram < 1: raise DynamipsError, 'invalid nvram size' self.__nvram = nvram send(self.__d, 'vm set_nvram %s %i' % (self.__name, self.__nvram)) def __getnvram(self): """ Returns the amount of nvram allocated to this router """ return self.__nvram nvram = property(__getnvram, __setnvram, doc = 'The amount of nvram allocated to this router') def __setimage(self, image): """ Set the IOS image for this router image: path to IOS image file """ self.__image = image # Can't verify existance of image because path is relative to backend send(self.__d, 'vm set_ios %s %s' % (self.__name, self.__image)) def __getimage(self): """ Returns path of the image being used by this router """ return self.__image image = property(__getimage, __setimage, doc = 'The IOS image file for this router') def __getimagename(self): """ Returns just the name of the image file used """ if self.__image == None: return None image = os.path.basename(self.__image).strip('"') return image imagename = property(__getimagename, doc = 'The name of the IOS image file for this router') def __setcnfg(self, cnfg): """ Import an IOS configuration file into NVRAM cnfg: path to configuration file to be imported """ self.__cnfg = cnfg # Can't verify existance of cnfg because path is relative to backend send(self.__d, 'vm set_config %s %s' % (self.__name, self.__cnfg)) def __getcnfg(self): """ Returns path of the cnfg being used by this router """ return self.__cnfg cnfg = property(__getcnfg, __setcnfg, doc = 'The IOS configuration file to import into NVRAM') def __setconfreg(self, confreg): """ Set the configuration register confreg: confreg string """ self.__confreg = confreg send(self.__d, 'vm set_conf_reg %s %s' % (self.__name, self.__confreg)) def __getconfreg(self): """ Returns the confreg """ return self.__confreg confreg = property(__getconfreg, __setconfreg, doc = 'The configuration register of this router') def __set_config_b64(self, conf64): """ Set the config to this base64 encoded configuration""" if DEBUGGER: return # Work around an annoying bug in the Komodo debugger send(self.__d, 'vm push_config %s %s' % (self.__name, conf64)) def __get_config_b64(self): """Get the base64 encoded config from the router's nvram""" if DEBUGGER: return # Work around an annoying bug in the Komodo debugger cf = send(self.__d, 'vm extract_config %s' % (self.__name)) b64config = cf[0].split(' ')[2].strip() return b64config config_b64 = property(__get_config_b64, __set_config_b64, doc = 'The configuration of this router in base64 encoding') def __setidlepc(self, pc): """ Set the Idle Pointer Counter for this instance pc: idle-pc string """ self.__idlepc = pc send(self.__d, 'vm set_idle_pc %s %s' % (self.__name, self.__idlepc)) def __getidlepc(self): """ Returns the current idlepc """ return self.__idlepc idlepc = property(__getidlepc, __setidlepc, doc = 'The Idle Pointer Counter assigned to this instance') def __getidlepcdrift(self): """ Returns the current idlepcdrift """ if not DEBUGGER: result = send(self.__d, 'vm show_timer_drift %s 0' % (self.__name)) if result[-1] == '100-OK': result.pop() return result idlepcdrift = property(__getidlepcdrift, doc = 'The idle-pc drift valueof instance') def __getcpuinfo(self): """ Returns the current cpuinfo """ if not DEBUGGER: result = send(self.__d, 'vm cpu_info %s 0' % (self.__name)) if result[-1] == '100-OK': result.pop() return result cpuinfo = property(__getcpuinfo, doc = 'The cpu info for this instance') def __setidlemax(self, val): """ Set the idlemax value for this instance val: (integer) idlemax counter """ self.__idlemax = val send(self.__d, 'vm set_idle_max %s 0 %i' % (self.__name, self.__idlemax)) def __getidlemax(self): """ Returns the current idlemax """ return self.__idlemax idlemax = property(__getidlemax, __setidlemax, doc = 'The Idle Pointer Counter assigned to this instance') def __setidlesleep(self, val): """ Set the idle_sleep_time for this instance val: (integer) sleep time in ms """ self.__idlesleep = val send(self.__d, 'vm set_idle_sleep_time %s 0 %i' % (self.__name, self.__idlesleep)) def __getidlesleep(self): """ Returns the current idlesleep value for this instance """ return self.__idlesleep idlesleep = property(__getidlesleep, __setidlesleep, doc = 'The idle sleep time of this instance') def __setoldidle(self, state): """ Set oldidle to True to use pre 0.2.7-RC1 idlepc values. It disables direct jumps between JIT blocks state: (bool) True to use old idlepc values, false to use RC2 and later values """ if type(state) != bool: raise DynamipsError, 'invalid oldidle status' self.__oldidle = state if state == True: val = 1 else: val = 0 send(self.__d, 'vm set_blk_direct_jump %s %i' % (self.__name, val)) def __getoldidle(self): """ Returns the current oldidle value """ return self.__oldidle oldidle = property(__getoldidle, __setoldidle, doc = 'Enable or disable legacy idle pc value option. Setting to True disables direct jumps between JIT blocks, allowing use of pre 0.2.7-RC2 idlepc values.') def __setexec_area(self, exec_area): """ Set the Exec Area size for this instance pc: Exec area integer """ self.__exec_area = exec_area send(self.__d, 'vm set_exec_area %s %s' % (self.__name, str(self.__exec_area))) def __getexec_area(self): """ Returns the exec_area """ return self.__exec_area exec_area = property(__getexec_area, __setexec_area, doc = 'The Exec Area size assigned to this instance') def __setghost_status(self, status): """ Set the ghost_status of this instance status: (int) Tristate flag indicating status 0 -> Do not use IOS ghosting 1 -> This is a ghost instance 2 -> Use an existing ghost instance """ self.__ghost_status = status send(self.__d, 'vm set_ghost_status %s %s' % (self.__name, str(self.__ghost_status))) def __getghost_status(self): """ Returns the ghost_status """ return self.__ghost_status ghost_status = property(__getghost_status, __setghost_status, doc = 'The ghost status of this instance') def __setghost_file(self, ghost_file): """ Set the ghost file for this instance ghost_file: (string) ghost file name to create (or reference) """ self.__ghost_file = ghost_file send(self.__d, 'vm set_ghost_file %s %s' % (self.__name, str(self.__ghost_file))) def __getghost_file(self): """ Returns the ghost_file """ return self.__ghost_file ghost_file = property(__getghost_file, __setghost_file, doc = 'The ghost file associated with this instance') def __setsparsemem(self, status): """ Set the sparsemem of this instance status: (int) Flag indicating enabled or disabled false -> Do not use sparsemem true -> Turn on sparsemem """ self.__sparsemem = status if status == True: flag = '1' else: flag = '0' send(self.__d, 'vm set_sparse_mem %s %s' % (self.__name, flag)) def __getsparsemem(self): """ Returns the sparsemem """ return self.__sparsemem sparsemem = property(__getsparsemem, __setsparsemem, doc = 'The sparsemem status of this instance') def __getdynamips(self): """ Returns the dynamips server on which this device resides """ return self.__d dynamips = property(__getdynamips, doc = 'The dynamips object associated with this device') def __getmodel(self): """ Returns model of this router """ return self.__model model = property(__getmodel, doc = 'The model of this router') def __getname(self): """ Returns the name of this router """ return self.__name name = property(__getname, doc = 'The name of this router') def __getstate(self): """ Returns the state of this router """ return self.__state state = property(__getstate, doc = 'The state of this router') def __getisrouter(self): """ Returns true if this device is a router """ return True isrouter = property(__getisrouter, doc = 'Returns true if this device is a router') class C7200(Router): """ Creates a new 7200 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number """ def __init__(self, dynamips, name = None): Router.__init__(self, dynamips, model = 'c7200', name = name) # Set defaults for properties Router.setdefaults(self, ram = 256, nvram = 128, disk0 = 64, disk1 = 0, npe = "npe-200", midplane = "vxr") # generate the slots for port adapters Router.createslots(self, 7) class C2691(Router): """ Creates a new 2691 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number """ def __init__(self, dynamips, name = None): Router.__init__(self, dynamips, model = 'c2691', name = name) # Set defaults for properties Router.setdefaults(self, ram = 128, nvram = 55, disk0 = 16, disk1 = 0) # generate the slots for network modules Router.createslots(self, 2) self.slot[0] = GT96100_FE(self, 0) class C2600(Router): """ Creates a new 2600 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number """ def __init__(self, dynamips, chassis, name = None): self.__d = dynamips self.__chassis = chassis self.__name = name Router.__init__(self, dynamips, model = 'c2600', name = name) # Set defaults for properties # Fix disk values for the XMs Router.setdefaults(self, ram = 64, nvram = 128, disk0 = 8, disk1 = 8) self.chassis = chassis Router.createslots(self, 2) # Insert the MB controller chassis2600transform = { "2610" : CISCO2600_MB_1E, "2611" : CISCO2600_MB_2E, "2620" : CISCO2600_MB_1FE, "2621" : CISCO2600_MB_2FE, "2610XM": CISCO2600_MB_1FE, "2611XM": CISCO2600_MB_2FE, "2620XM": CISCO2600_MB_1FE, "2621XM": CISCO2600_MB_2FE, "2650XM": CISCO2600_MB_1FE, "2651XM": CISCO2600_MB_2FE } self.slot[0] = chassis2600transform[chassis](self, 0) def __setchassis(self, chassis): """ Set the chassis property chassis: (string) Set the chassis type """ if type(chassis) not in [str, unicode] or chassis not in CHASSIS2600: debug("Invalid chassis passed to __setchassis") debug("chassis -> '" + str(chassis) +"'") debug("chassis type -> " + str(type(chassis))) raise DynamipsError, 'invalid chassis type' self.__chassis = chassis send(self.__d, 'c2600 set_chassis %s %s' % (self.__name, self.__chassis)) def __getchassis(self): """ Returns chassis property """ return self.__chassis chassis = property(__getchassis, __setchassis, doc = 'The chassis property of this router') class C3725(Router): """ Creates a new 3725 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number """ def __init__(self, dynamips, name = None): Router.__init__(self, dynamips, model = 'c3725', name = name) # Set defaults for properties Router.setdefaults(self, ram = 128, nvram = 55, disk0 = 16, disk1 = 0) # generate the slots for network modules Router.createslots(self, 3) self.slot[0] = GT96100_FE(self, 0) class C3745(Router): """ Creates a new 3745 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number """ def __init__(self, dynamips, name = None): Router.__init__(self, dynamips, model = 'c3745', name = name) # Set defaults for properties Router.setdefaults(self, ram = 128, nvram = 151, disk0 = 16, disk1 = 0) # generate the slots for network modules Router.createslots(self, 5) self.slot[0] = GT96100_FE(self, 0) class C3600(Router): """ Creates a new 3620 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number """ def __init__(self, dynamips, chassis, name = None): self.__d = dynamips self.__chassis = chassis self.__name = name Router.__init__(self, dynamips, model = 'c3600', name = name) # Set defaults for properties Router.setdefaults(self, ram = 128, nvram = 128, disk0 = 0, disk1 = 0) self.chassis = chassis # generate the slots for port adapters if chassis == '3620': Router.createslots(self, 2) elif chassis == '3640': Router.createslots(self, 4) elif chassis == '3660': Router.createslots(self, 7) else: debug("Unable to match chassis type. Chassis -> " + str(chassis)) raise DynamipsError, 'invalid chassis type' def __setchassis(self, chassis): """ Set the chassis property chassis: (string) Set the chassis type """ if type(chassis) not in [str, unicode] or chassis not in ['3620', '3640', '3660']: debug("Invalid chassis passed to __setchassis") debug("chassis -> '" + str(chassis) +"'") debug("chassis type -> " + str(type(chassis))) raise DynamipsError, 'invalid chassis type' self.__chassis = chassis send(self.__d, 'c3600 set_chassis %s %s' % (self.__name, self.__chassis)) def __getchassis(self): """ Returns chassis property """ return self.__chassis chassis = property(__getchassis, __setchassis, doc = 'The chassis property of this router') def __setiomem(self, iomem): """ Set the iomem property iomem: (string) Set the iomem value """ try: iomem = int(iomem) except ValueError: raise DynamipsError, 'invalid iomem type, must be an integer' if iomem % 5 != 0: raise DynamipsError, 'iomem must be a multiple of 5' self.__iomem = iomem send(self.__d, 'c3600 set_iomem %s %s' % (self.__name, self.__iomem)) def __getiomem(self): """ Returns iomem property """ return self.__iomem iomem = property(__getiomem, __setiomem, doc = 'The iomem size of this router') class C1700(Router): """ Creates a new 1700 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number """ def __init__(self, dynamips, chassis, name = None): self.__d = dynamips self.__chassis = chassis self.__name = name Router.__init__(self, dynamips, model = 'c1700', name = name) # Set defaults for properties Router.setdefaults(self, ram = 64, nvram = 32, disk0 = 0, disk1 = 0) self.chassis = chassis if chassis in ['1751', '1760']: Router.createslots(self,2) else: Router.createslots(self,1) # Insert the MB controller chassis1700transform = { "1710" : CISCO1710_MB_1FE_1E, "1720" : C1700_MB_1ETH, "1721" : C1700_MB_1ETH, "1750" : C1700_MB_1ETH, "1751" : C1700_MB_1ETH, "1760" : C1700_MB_1ETH } self.slot[0] = chassis1700transform[chassis](self, 0) # Hack for 1751 and 1760 # On these platforms, WICs in WIC slot 1 show up as in slot 1, not 0 # E.g. s1/0 not s0/2 like other platforms. I'm sure there's a good reason # why is works that way. Whatever. Hack around it. if chassis in ['1751', '1760']: self.slot[1] = C1700_WIC1(self, 1) def __setchassis(self, chassis): """ Set the chassis property chassis: (string) Set the chassis type """ if type(chassis) not in [str, unicode] or chassis not in CHASSIS1700: debug("Invalid chassis passed to __setchassis") debug("chassis -> '" + str(chassis) +"'") debug("chassis type -> " + str(type(chassis))) raise DynamipsError, 'invalid chassis type' self.__chassis = chassis send(self.__d, 'c1700 set_chassis %s %s' % (self.__name, self.__chassis)) def __getchassis(self): """ Returns chassis property """ return self.__chassis chassis = property(__getchassis, __setchassis, doc = 'The chassis property of this router') def __setiomem(self, iomem): """ Set the iomem property iomem: (string) Set the iomem value """ try: iomem = int(iomem) except ValueError: raise DynamipsError, 'invalid iomem type, must be an integer' if iomem % 5 != 0: raise DynamipsError, 'iomem must be a multiple of 5' self.__iomem = iomem send(self.__d, 'c1700 set_iomem %s %s' % (self.__name, self.__iomem)) def __getiomem(self): """ Returns iomem property """ return self.__iomem iomem = property(__getiomem, __setiomem, doc = 'The iomem size of this router') class DynamipsError(Exception): pass class DynamipsErrorHandled(Exception): pass class DynamipsVerError(Exception): pass class DynamipsWarning(Exception): pass ############################################################################### class Bridge(object): """ Creates a new Ethernet bridge instance dynamips: a Dynamips object name: An optional name """ __instance_count = 0 def __init__(self, dynamips, name = None, create = True): self.__d = dynamips self.__instance = Bridge.__instance_count Bridge.__instance_count += 1 if name == None: self.__name = 'b' + str(self.__instance) else: self.__name = name self.__nios = [] # A list NETIO objects that are associated with this bridge if create: send(self.__d, "nio_bridge create " + self.__name) def delete(self): """ Delete this Frame Relay switch instance from the back end """ pass def nio(self, nio = None): """ Adds an NIO to this bridge nio: A nio object """ if nio == None: # Return the NETIO string try: return self.__nios except KeyError: raise DynamipsError, 'port does not exist on this switch' nio_t = type(nio) if nio_t == NIO_udp or nio_t == NIO_linux_eth or nio_t == NIO_gen_eth or nio_t == NIO_tap or nio_t == NIO_unix: send(self.__d, 'nio_bridge add_nio %s %s' % (self.__name, nio.name)) # Add the NETIO to the list self.__nios.append(nio) def __getadapter(self): """ Returns the adapter property """ return "Bridge" adapter = property(__getadapter, doc = 'The port adapter') def __getname(self): """ Returns the name property """ return self.__name name = property(__getname, doc = 'The device name') def __getdynamips(self): """ Returns the dynamips server on which this device resides """ return self.__d dynamips = property(__getdynamips, doc = 'The dynamips object associated with this device') def __getisrouter(self): """ Returns true if this device is a router """ return False isrouter = property(__getisrouter, doc = 'Returns true if this device is a router') ######################################################################################## class FRSW(object): """ Creates a new Frame Relay switch instance dynamips: a Dynamips object name: An optional name """ __instance_count = 0 def __init__(self, dynamips, name = None, create = True): self.__d = dynamips self.__instance = FRSW.__instance_count FRSW.__instance_count += 1 if name == None: self.__name = 'f' + str(self.__instance) else: self.__name = name self.__dlcis = {} # A dict of DLCIs (tuple) indexed by switch port self.__nios = {} # A dict of NETIO objects indexed by switch port if create: send(self.__d, "frsw create " + self.__name) def delete(self): """ Delete this Frame Relay switch instance from the back end """ pass def map(self, port1, dlci1, port2, dlci2): """ Tell the switch to switch between port1 / dlci1 and port 2 / dlci2 NOTE: both ports must be connected to something before map can be applied port1, port2: Two different ports on this switch dlci1, dlci2: DLCIs assigned to the respective ports on this switch """ # Also note: if you change connections you need to reapply maps that # are associated with those ports if type(port1) != int or port1 < 0: raise DynamipsError, 'invalid port1. Must be an int >= 0' if type(port2) != int or port2 < 0: raise DynamipsError, 'invalid port2. Must be an int >= 0' if type(dlci1) != int or dlci1 < 0: raise DynamipsError, 'invalid dlci1. Must be an int >= 0' if type(dlci2) != int or dlci2 < 0: raise DynamipsError, 'invalid dlci1. Must be an int >= 0' try: nio1 = self.nio(port1).name except KeyError: raise DynamipsError, 'port1 does not exist on this switch' try: nio2 = self.nio(port2).name except KeyError: raise DynamipsError, 'port2 does not exist on this switch' send(self.__d, 'frsw create_vc %s %s %i %s %i' % (self.__name, nio1, dlci1, nio2, dlci2)) # Now track the dlcis if self.__dlcis.has_key(port1): self.__dlcis[port1].append(dlci1) else: self.__dlcis[port1] = [dlci1] if self.__dlcis.has_key(port2): self.__dlcis[port2].append(dlci2) else: self.__dlcis[port2] = [dlci2] def connect(self, localport, remoteserver, remoteadapter, remoteport): """ Connect this switch to a port on another device remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter object on a router remoteport: A port on the remote adapter """ # Call the generalized connect function, validating first validate_connect(localint, remoteint) gen_connect(src_dynamips = self.__d, src_adapter = self, src_port = localport, dst_dynamips = remoteserver, dst_adapter = remoteadapter, dst_port = remoteport) def connected(self, port): """ Returns a boolean indicating if this port is connected or not """ return connected_general(self, port) def nio(self, port, nio = None): """ Returns the NETIO object for this port or if nio is set, sets the NETIO for this port port: a port on this adapter nio: optional NETIO object to assign """ if nio == None: # Return the NETIO string try: return self.__nios[port] except KeyError: raise DynamipsWarning, 'Frame-Relay switchport ' + str(port) + ' on device "' + self.name + '" is defined, but not used' # as of 0.2.5pre5 add_nio has been removed. For now I'm just removing sending the nio command #nio_t = type(nio) # is it kosher to connect a frame relay switch to a linux or gen interface? I don't know... How about chained FRSW switches? #if nio_t == NIO_udp or nio_t == NIO_linux_eth or nio_t == NIO_gen_eth or nio_t == NIO_tap or nio_t == NIO_unix: # send(self.__d, 'frsw add_nio %s %s' % (self.__name, nio.name)) # Set the NETIO for this port self.__nios[port] = nio def dlci(self, port): """ Returns the DLCIs assigned to this port (as a list) port: (int) a port on this switch dlcis: one or more DLCIs """ # Return the DLCIs assigned to this port try: return self.__dlcis[port] except KeyError: raise DynamipsError, 'invalid port' def __getadapter(self): """ Returns the adapter property """ return "FRSW" adapter = property(__getadapter, doc = 'The port adapter') def __getname(self): """ Returns the name property """ return self.__name name = property(__getname, doc = 'The device name') def __getdynamips(self): """ Returns the dynamips server on which this device resides """ return self.__d dynamips = property(__getdynamips, doc = 'The dynamips object associated with this device') def __getisrouter(self): """ Returns true if this device is a router """ return False isrouter = property(__getisrouter, doc = 'Returns true if this device is a router') ############################################################################### class ATMSW(object): """ Creates a new ATM switch instance dynamips: a Dynamips object name: An optional name """ __instance_count = 0 def __init__(self, dynamips, name = None, create = True): self.__d = dynamips self.__instance = ATMSW.__instance_count ATMSW.__instance_count += 1 if name == None: self.__name = 'a' + str(self.__instance) else: self.__name = name self.__vpis = {} # A dict of vpis (tuple) indexed by switch port self.__nios = {} # A dict of NETIO objects indexed by switch port if create: send(self.__d, "atmsw create " + self.__name) def delete(self): """ Delete this ATM switch instance from the back end """ pass def mapvp(self, port1, vpi1, port2, vpi2): """ Tell the switch to switch between port1 / vpi1 and port 2 / vpi2 NOTE: both ports must be connected to something before map can be applied port1, port2: Two different ports on this switch vpi1, vpi2: vpis assigned to the respective ports on this switch """ # Also note: if you change connections you need to reapply maps that # are associated with those ports if type(port1) != int or port1 < 0: raise DynamipsError, 'invalid port1. Must be an int >= 0' if type(port2) != int or port2 < 0: raise DynamipsError, 'invalid port2. Must be an int >= 0' if type(vpi1) != int or vpi1 < 0: raise DynamipsError, 'invalid vpi1. Must be an int >= 0' if type(vpi2) != int or vpi2 < 0: raise DynamipsError, 'invalid vpi2. Must be an int >= 0' try: nio1 = self.nio(port1).name except KeyError: raise DynamipsError, 'port1 does not exist on this switch' try: nio2 = self.nio(port2).name except KeyError: raise DynamipsError, 'port2 does not exist on this switch' send(self.__d, 'atmsw create_vpc %s %s %i %s %i' % (self.__name, nio1, vpi1, nio2, vpi2)) # Now track the vpis if self.__vpis.has_key(port1): self.__vpis[port1].append(vpi1) else: self.__vpis[port1] = [vpi1] if self.__vpis.has_key(port2): self.__vpis[port2].append(vpi2) else: self.__vpis[port2] = [vpi2] def mapvc(self, port1, vpi1, vci1, port2, vpi2, vci2): """ Tell the switch to switch between port1 / vpi1 / vci1 and port 2 / vpi2 / vci2 NOTE: both ports must be connected to something before map can be applied port1, port2: Two different ports on this switch vpi1, vpi2: vpis assigned to the respective ports on this switch vci1, vci2: vcis """ # Also note: if you change connections you need to reapply maps that # are associated with those ports if type(port1) != int or port1 < 0: raise DynamipsError, 'invalid port1. Must be an int >= 0' if type(port2) != int or port2 < 0: raise DynamipsError, 'invalid port2. Must be an int >= 0' if type(vpi1) != int or vpi1 < 0: raise DynamipsError, 'invalid vpi1. Must be an int >= 0' if type(vpi2) != int or vpi2 < 0: raise DynamipsError, 'invalid vpi2. Must be an int >= 0' if type(vci1) != int or vci1 < 0: raise DynamipsError, 'invalid vci1. Must be an int >= 0' if type(vci2) != int or vci2 < 0: raise DynamipsError, 'invalid vci2. Must be an int >= 0' try: nio1 = self.nio(port1).name except KeyError: raise DynamipsError, 'port1 does not exist on this switch' try: nio2 = self.nio(port2).name except KeyError: raise DynamipsError, 'port2 does not exist on this switch' send(self.__d, 'atmsw create_vcc %s %s %i %i %s %i %i' % (self.__name, nio1, vpi1, vci1, nio2, vpi2, vci2)) # Now track the vpis if self.__vpis.has_key(port1): self.__vpis[port1].append(vpi1) else: self.__vpis[port1] = [vpi1] if self.__vpis.has_key(port2): self.__vpis[port2].append(vpi2) else: self.__vpis[port2] = [vpi2] def connect(self, localport, remoteserver, remoteadapter, remoteport): """ Connect this switch to a port on another device remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter object on a router remoteport: A port on the remote adapter """ # Call the generalized connect function, validating first validate_connect(localint, remoteint) gen_connect(src_dynamips = self.__d, src_adapter = self, src_port = localport, dst_dynamips = remoteserver, dst_adapter = remoteadapter, dst_port = remoteport) def connected(self, port): """ Returns a boolean indicating if this port is connected or not """ return connected_general(self, port) def nio(self, port, nio = None): """ Returns the NETIO object for this port or if nio is set, sets the NETIO for this port port: a port on this adapter nio: optional NETIO object to assign """ if nio == None: # Return the NETIO string try: return self.__nios[port] except KeyError: raise DynamipsWarning, 'ATM switchport ' + str(port) + ' on device "' + self.name + '" is defined, but not used' # as of 0.2.5pre5 add_nio has been removed. For now I'm just removing sending the nio command #nio_t = type(nio) # is is kosher to connect an ATM switch to a linux or gen interface? I don't know... How about chained ATM switches? #if nio_t == NIO_udp or nio_t == NIO_linux_eth or nio_t == NIO_gen_eth or nio_t == NIO_tap or nio_t == NIO_unix: # send(self.__d, 'atmsw add_nio %s %s' % (self.__name, nio.name)) # Set the NETIO for this port self.__nios[port] = nio def vpi(self, port): """ Returns the vpis assigned to this port (as a list) port: (int) a port on this switch vpis: one or more vpis """ # Return the vpis assigned to this port try: return self.__vpis[port] except KeyError: raise DynamipsError, 'invalid port' def __getadapter(self): """ Returns the adapter property """ return "ATMSW" adapter = property(__getadapter, doc = 'The port adapter') def __getname(self): """ Returns the name property """ return self.__name name = property(__getname, doc = 'The device name') def __getdynamips(self): """ Returns the dynamips server on which this device resides """ return self.__d dynamips = property(__getdynamips, doc = 'The dynamips object associated with this device') def __getisrouter(self): """ Returns true if this device is a router """ return False isrouter = property(__getisrouter, doc = 'Returns true if this device is a router') ############################################################################### class ETHSW(object): """ Creates a new Ethernet switch instance dynamips: a Dynamips object name: An optional name """ __instance_count = 0 def __init__(self, dynamips, name = None, create = True): self.__d = dynamips self.__instance = ETHSW.__instance_count ETHSW.__instance_count += 1 if name == None: self.__name = 's' + str(self.__instance) else: self.__name = name self.__nios = {} # A dict of NETIO objects indexed by switch port if create: send(self.__d, "ethsw create " + self.__name) def delete(self): """ Delete this Frame Relay switch instance from the back end """ pass def set_port(self, port, porttype, vlan): """ Define a port as an access port or trunk port, and it's vlan port: the switchport porttype: string of the value "access" or "dot1q" vlan: the vlan """ if type(port) != int: raise DynamipsError, 'invalid port. Must be an int >= 0' if type(vlan) != int: raise DynamipsError, 'invalid vlan. Must be an int >= 0' try: nio = self.nio(port).name except KeyError: raise DynamipsError, 'port1 does not exist on this switch' porttype = porttype.lower() if porttype != 'access' and porttype != 'dot1q': raise DynamipsError, 'invalid porttype' send(self.__d, "ethsw set_" + porttype + "_port " + self.__name + " " + nio + " " + str(vlan)) def show_mac(self): """ Show this switch's mac address table """ return send(self.__d, "ethsw show_mac_addr_table " + self.__name) def clear_mac(self): """ Clear this switch's mac address table """ return send(self.__d, "ethsw clear_mac_addr_table " + self.__name) def connect(self, localport, remoteserver, remoteadapter, remoteport): """ Connect this switch to a port on another device remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter object on a router remoteport: A port on the remote adapter """ # Call the generalized connect function, validating first validate_connect(localint, remoteint) gen_connect(src_dynamips = self.__d, src_adapter = self, src_port = localport, dst_dynamips = remoteserver, dst_adapter = remoteadapter, dst_port = remoteport) def connected(self, port): """ Returns a boolean indicating if this port is connected or not """ return connected_general(self, port) def nio(self, port, nio = None, porttype = None, vlan = None): """ Returns the NETIO object for this port or if nio is set, sets the NETIO for this port port: a port on this adapter nio: optional NETIO object to assign porttype: either access or dot1q """ if nio == None: # Return the NETIO string try: return self.__nios[port] except KeyError: raise DynamipsWarning, 'Ethernet switchport ' + str(port) + ' on device "' + self.name + '" is defined, but not used' nio_t = type(nio) if nio_t == NIO_udp or nio_t == NIO_linux_eth or nio_t == NIO_gen_eth or nio_t == NIO_tap or nio_t == NIO_unix: send(self.__d, 'ethsw add_nio %s %s' % (self.__name, nio.name)) else: raise DynamipsError, 'invalid NIO type' # Set the NETIO for this port self.__nios[port] = nio if porttype != None: porttype = porttype.lower() if porttype != 'access' and porttype != 'dot1q': raise DynamipsError, 'invalid porttype' send(self.__d, "ethsw set_" + porttype + "_port " + self.__name + " " + nio.name + " " + str(vlan)) def __getadapter(self): """ Returns the adapter property """ return "ETHSW" adapter = property(__getadapter, doc = 'The port adapter') def __getname(self): """ Returns the name property """ return self.__name name = property(__getname, doc = 'The device name') def __getdynamips(self): """ Returns the dynamips server on which this device resides """ return self.__d dynamips = property(__getdynamips, doc = 'The dynamips object associated with this device') def __getisrouter(self): """ Returns true if this device is a router """ return False isrouter = property(__getisrouter, doc = 'Returns true if this device is a router') ############################################################################### # Functions used by all classes def send(dynamips, command): """ Sends raw commands to the Dynamips process dynamips: a dynamips object command: raw commands returns results as a list """ # Dynamips responses are of the form: # 1xx yyyyyy\r\n # 1xx yyyyyy\r\n # ... # 100-yyyy\r\n # or # 2xx-yyyy\r\n # # Where 1xx is a code from 100-199 for a sucess or 200-299 for an error # The result might be multiple lines, and might be less than the buffer size # but still have more data. The only thing we know for sure is the last line # will begin with "100-" or a "2xx-" and end with '\r\n' SIZE = 1024 # Match to Dynamips' buffer size resultset = [] debug('sending to ' + dynamips.host + ':' + str(dynamips.port) + ' -> ' + command) if not NOSEND: try: dynamips.s.sendall(command.strip() + '\n') except timeout: print "Error: lost communication with dynamips server %s" % dynamips.host print "Dynamips may have crashed. Check the Dynamips server output." print "Exiting..." raise DynamipsErrorHandled # Now retrieve the result data = [] buf = '' while True: try: chunk = dynamips.s.recv(SIZE) #debug('Chunk: ' + chunk) buf += chunk except timeout, message: print "Error: timed out communicating with dynamips server %s" % dynamips.host print message print "Exiting..." raise DynamipsErrorHandled except: print "Error: could not communicate with dynamips server %s" % dynamips.host print "Dynamips may have crashed. Check the Dynamips server output." print "Exiting..." raise DynamipsErrorHandled # if the buffer doesn't end in '\n' then we can't be done try: if buf[-1] != '\n': continue except IndexError: print "Error: could not communicate with dynamips server %s" % dynamips.host print "Dynamips may have crashed. Check the Dynamips server output." print "Exiting..." raise DynamipsErrorHandled data += buf.split('\r\n') if data[-1] == '': data.pop() buf = '' # Does the last line begin with "100-"? Then we are done: if data[-1][:4] == '100-': break # Or does it contain an error code? if error_re.search(data[-1]): raise DynamipsError, data[-1] # Otherwise loop throught again and get the the next line of data if len(data) == 0: print "Error: no data returned from dynamips server %s. Server crashed?" % dynamips.host raise DynamipsError, "no data" debug('returned -> ' + str(data)) return data else: return '' # NOSEND, so return empty string def gen_connect(src_dynamips, src_adapter, src_port, dst_dynamips, dst_adapter, dst_port): """ Generalized connect function called by all connect methods. Connects a souce interface / port to a destination interface / port src_dynamips: the dynamips object that hosts the source connection src_adapter: the source adapter src_port: the source port dst_dynamips: the dynamips object that hosts the destination connection dst_adapter: the destination adatper dst_port: the destination port (set to none if the destination is a bridge) """ if src_dynamips.host == dst_dynamips.host: # source and dest adapters are on the same dynamips server, perform loopback binding optimization src_ip = '127.0.0.1' dst_ip = '127.0.0.1' else: # source and dest are on different dynamips servers src_ip = src_dynamips.host dst_ip = dst_dynamips.host # Dynagen connect currently always uses UDP NETIO # Allocate a UDP port for the local side of the NIO src_udp = src_dynamips.udp src_dynamips.udp = src_dynamips.udp + 1 debug("source NIO udp is now: " + str(src_dynamips.udp)) # Now allocate one for the destination side dst_udp = dst_dynamips.udp dst_dynamips.udp = dst_dynamips.udp + 1 debug ("dest NIO udp is now: " + str(dst_dynamips.udp)) # Create the NIOs src_nio = NIO_udp(src_dynamips, src_udp, dst_ip, dst_udp) dst_nio = NIO_udp(dst_dynamips, dst_udp, src_ip, src_udp) # Tie the NIOs to the source and destination ports / bridges src_adapter.nio(port=src_port, nio=src_nio) if isinstance(dst_adapter, Bridge): # Bridges don't use ports dst_adapter.nio(nio=dst_nio) else: dst_adapter.nio(port=dst_port, nio=dst_nio) def validate_connect(i1, i2): """ Check to see if a given adapter can be connected to another adapter i1: interface type 1 i2: interface type 2 """ """ try: a1 = int1.adapter a2 = int2.adapter except AttributeError: raise DynamipsError, 'invalid adapter or no adapter present' """ # Question: can we daisy-chain switches? Validate this. #ethernets = ('C7200-IO-FE', 'PA-2FE-TX', 'PA-GE', 'C7200-IO-2FE', 'C7200-IO-GE-E', 'PA-FE-TX', 'PA-4E', 'PA-8E', 'NM-1FE-TX', 'NM-1E', 'NM-4E', 'NM-16ESW', 'Leopard-2FE', 'GT96100-FE', 'CISCO2600-MB-1E', 'CISCO2600-MB-2E', 'CISCO2600-MB-1FE', 'CISCO2600-MB-2FE', 'Bridge', 'ETHSW') #serials = ('PA-4T+', 'PA-8T', 'NM-4T', 'FRSW') #atms = ('PA-A1', 'ATMSW') #poss = ('PA-POS-OC3') ethernets = ('e', 'f', 'g', 'n', 'i') serials = ('s') atms = ('a') poss = ('p') #if a1 == 'Bridge' and a2 == 'Bridge': # raise DynamipsError, 'attempt to connect two bridges' if i1 in ethernets and i2 in ethernets: return elif i1 in serials and i2 in serials: return elif i1 in atms and i2 in atms: return elif i1 in poss and i2 in poss: return """ # Corner case: POS to FRSW is ok elif a1 in poss and a2 == 'FRSW': return elif a2 in poss and a1 == 'FRSW': return """ else: raise DynamipsError, 'attempt to connect %s to %s' % (i1, i2) def connected_general(obj, port): """ Returns a boolean indicating if this port is connected or not """ # If it's got an nio, I guess it's connected try: nio1 = obj.nio(port).name except AttributeError: return False return True def checkconsole(console, dynamips): """ Returns the device that uses the console port Returns None if no device has that console port """ # Hunt through the console ports in use to see if there is a conflict for device in dynamips.devices: try: con2 = device.console except AttributeError: # This device has no console value continue if console == con2: return device return None def nosend(flag): """ If true, don't actually send any commands to the back end. """ global NOSEND if flag == True or flag == False: NOSEND = flag def setdebug(flag): """ If true, print out debugs """ global DEBUG if flag == True or flag == False: DEBUG = flag def debug(string): """ Print string if debugging is true """ global DEBUG if DEBUG: print ' DEBUG: ' + str(string) if __name__ == "__main__": # Testing DEBUG = True IMAGE = '/opt/ios-images/c1710-k9o3sy-mz.124-16.image' d = Dynamips('localhost', 7200) d.reset() #d.workingdir = '"/Users/greg/Documents/Mac Dynagen labs/dev tests/0.2.8"' d.workingdir = '/tmp' r1 = C1700(d, chassis = '1750', name='r1') r1.image = IMAGE r1.ram = 128 #r1.slot[0] = CISCO2600_MB_1E(r1,0) #r1.slot[16] = WIC_1T(r1,16) #r1.slot[0] = CISCO2600_MB_1E(r1,0) r1.installwic('WIC-1T', 0, 0) #r1.installwic('WIC-2T', 0, 1) #r1.installwic('WIC-2T', 0, 2) #r1.idlepc = ' 0x8046b940' #r1.slot[0].connect(0, d, esw.slot[1], 0) #r2 = C2600(d, chassis = '2610', name='r2') #r2.image = IMAGE #r2.slot[0].install(CISCO2600_MB_1E(r2,0)) #r2.installwic('WIC-2T', 0, 0) #r2.idlepc = ' 0x8046b940' #r1.slot[0].connect('s', 0, d, r2.slot[0], 's', 0) # r1 s0/0 = r2 s0/0 r1.start() #r2.start() d.reset() m fFc@s dZdkZdkZdkZdkZdklZlZlZlZdZ ddddf\Z Z Z Z e de d e e Zd ZeaeadZd Zd Zeid ZeidZyeWnej o eZnXeZdddddddfZddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,fZddddddfZddddd d!d"d#d$d%f Z d)d*d+fZ!hdd-<dd.<dd.<dd.<dd.<dd.d?d@dAdBf Z(dCdDdEfZ)hdFd dGg<dHddGg<dId dJgdne:fdoYZ?dpe:fdqYZ@dre:fdsYZAdte:fduYZBdve:fdwYZCdxe:fdyYZDdze:fd{YZEd|e:fd}YZFd~e9fdYZGdeGfdYZHdeGfdYZIdeGfdYZJdeGfdYZKdeGfdYZLdeGfdYZMdeGfdYZNdeGfdYZOdeGfdYZPdeGfdYZQdeGfdYZRdeGfdYZSdeGfdYZTdeGfdYZUdeGfdYZVdeGfdYZWde0fdYZXdeXfdYZYdeXfdYZZdeXfdYZ[deXfdYZ\deXfdYZ]deXfdYZ^deXfdYZ_de`fdYZade`fdYZbde`fdYZcde`fdYZdde0fdYZede0fdYZfde0fdYZgde0fdYZhdZidZjdZkdZldZmdZndZodZpeqdjoeadZre1ddZsesitdes_ue_esddddZverev_wdev_xeviydFddevizesitndS(s dynamips_lib.py Copyright (C) 2006 Greg Anuzelli This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. N(ssocketstimeoutsAF_INETs SOCK_STREAMs 0.10.1.090807iiif0.10000000000000001i'ids 0.2.8-RC1iis ^2[0-9][0-9]-s^[1-2][0-9][0-9]-tc1700tc2600tc2691tc3725tc3745tc3600tc7200t1710t1720t1721t1750t1751t1760t2610t2611t2620t2621t2610XMt2611XMt2620XMt2621XMt2650XMt2651XMt2691t3725t3745t3620t3640t3660t7200sCISCO1710-MB-1FE-1Es C1700-MB-1ETHsCISCO2600-MB-1EsCISCO2600-MB-2EsCISCO2600-MB-1FEsCISCO2600-MB-2FEs NM-1FE-TXsNM-1EsNM-4EsNM-16ESWsNM-CIDSsNM-NAMsNM-4TsPA-A1sPA-FE-TXs PA-2FE-TXsPA-GEsPA-4T+sPA-8TsPA-4EsPA-8Es PA-POS-OC3s C7200-IO-FEs C7200-IO-2FEs C7200-IO-GE-EsWIC-1TtssWIC-2Ts WIC-1ENETtes C1700-WIC1s GT96100-FEtis Leopard-2FEiitDynamipscBs7tZdZdddZdZdZdZdZdZe eed d Z d Z d Z e e e d d Z dZdZe eed dZdZdZe eed dZdZdZdZe ed dZdZe ed dZdZe ed dZRS(s Creates a new connection to a Dynamips server host: the hostname or ip address of the Dynamips server port: the tcp port (defaults to 7200) timeout: how log to wait for a response to commands sent to the server default is 3 seconds i i,c Csttt|_|iid|ii|tp1y|ii ||fWqjt dqjXng|_ d|_||_||_d|_d|_yt|ddd}Wntj o d}nXy|id did \}}}|id d } | d d jotd | d }nd}t|dt|dt||} Wnd|GHd} nX| tjot dt!||fn||_"dS(NisCould not connect to serverR ii'shypervisor versionisN/At-t.iitRCf0.999idsVWarning: problem determing dynamips server version on host: %s. Skipping version checki?BsThis version of Dynagen requires at least version %s of dynamips. Server %s is runnning version %s. Get the latest version from http://www.ipflow.utc.fr/blog/(#tsockettAF_INETt SOCK_STREAMtselfRt setblockingt settimeoutttimeouttNOSENDtconnectthosttportt DynamipsErrort_Dynamips__devicest_Dynamips__workingdirt_Dynamips__hostt_Dynamips__portt_Dynamips__baseconsolet_Dynamips__udptsendtversiont IndexErrortsplittmajortminortsubtrelease_candidatetfloattrcvertinttintvertINTVERtDynamipsVerErrortSTRVERt_Dynamips__version( R(R.R/R+R;R@R=R8R<RBR>((t/usr/bin/dynamips_lib.pyt__init__s>       %0   cCs t|d}|iidS(sG Close the connection to the Hypervisor (but leave it running) shypervisor closeN(R7R(tresultRtclose(R(RI((RGRJscCst|d}dS(s reset the hypervisor shypervisor resetN(R7R(RI(R(RI((RGtresetscCs t|d}|iidS(s" Shut down the hypervisor shypervisor stopN(R7R(RIRRJ(R(RI((RGtstopscCs ||_dS(s Set the list of devices managed by this dynamips instance This method is for internal use by Router.__init__ devices: (list) a list of device objects N(tdevicesR(R1(R(RM((RGt __setdevicesscCs|iS(sG Returns the list of devices managed by this dynamips instance N(R(R1(R(((RGt __getdevicesstdocs5The list of devices managed by this dynamips instancecCsAt|tjo tdn||_t|d|idS(sb Set the working directory for this network directory: (string) the directory sinvalid directoryshypervisor working_dir %sN(ttypet directorytstrR0R(R2R7(R(RR((RGt__setworkingdirs   cCs|iS(s# Returns working directory N(R(R2(R(((RGt__getworkingdirssThe working directorycCs-t|tjo tdn||_dS(su Set the base console TCP port for this server directory: (int) the starting console port number sinvalid console portN(RQt baseconsoleRAR0R(R5(R(RV((RGt__setbaseconsoles cCs|iS(s# Returns working directory N(R(R5(R(((RGt__getbaseconsolessThe starting console portcCs-t|tjo tdn||_dS(sj Set the next open UDP port for NIOs for this server udp: (int) the next NIO udp port sinvalid UDP portN(RQtudpRAR0R(R6(R(RY((RGt__setudp s cCs|iS(s6 Returns the next available UDP port for NIOs N(R(R6(R(((RGt__getudpss$The next available UDP port for NIOscCst||d}|S(sb Send a generic list command to Dynamips subsystem is one of nio, frsw, atmsw s listN(R7R(t subsystemRI(R(R\RI((RGtlistscCst||}|S(s8 Send a raw command to Dynamips. Use sparingly. N(R7R(tstringRI(R(R^RI((RGtsend_raw"scCs|iS(s# Returns the host property N(R(R3(R(((RGt __gethost)ssThe dynamips host IP or namecCs|iS(s# Returns the port property N(R(R4(R(((RGt __getport0ssThe dynamips portcCs|iS(s" Returns dynamips version N(R(RF(R(((RGt __getversion8ssThe dynamips version(t__name__t __module__t__doc__RHRJRKRLt_Dynamips__setdevicest_Dynamips__getdevicestpropertyRMt_Dynamips__setworkingdirt_Dynamips__getworkingdirt workingdirt_Dynamips__setbaseconsolet_Dynamips__getbaseconsoleRVt_Dynamips__setudpt_Dynamips__getudpRYR]R_t_Dynamips__gethostR.t_Dynamips__getportR/t_Dynamips__getversionR8(((RGR!s2 *               tNIO_udpcBsttZdZdZedZdZeeZdZ ee Z dZ ee Z dZ ee ZRS(s  Create a nio_udp object dynamips: the dynamips server object udplocal: (int) local udp port remotehost: (string) host or ip address of remote udpremote: (int) remote udp port name: (string) optional name for this object icCs||_||_||_||_t i |_ t i d7_ |djodt |i |_n ||_t|id|i|i|i|ifdS(Nitnio_udpsnio create_udp %s %i %s %i(tdynamipsR(t _NIO_udp__dtudplocalt_NIO_udp__udplocalt remotehostt_NIO_udp__remotehostt udpremotet_NIO_udp__udpremoteRst_NIO_udp__instancetnametNoneRSt_NIO_udp__nameR7(R(RuRwRyR{R~((RGRHJs       cCs|iS(N(R(Rx(R(((RGt __getudplocalYscCs|iS(N(R(Rz(R(((RGt__getremotehost]scCs|iS(N(R(R|(R(((RGt__getudpremoteascCs|iS(N(R(R(R(((RGt __getnamees(RcRdReR}RRHt_NIO_udp__getudplocalRhRwt_NIO_udp__getremotehostRyt_NIO_udp__getudpremoteR{t_NIO_udp__getnameR~(((RGRs@s         t NIO_linux_ethcBsJtZdZdZedZdZeeZdZ ee Z RS(s Create a nio_linux_eth object dynamips: the dynamips server object interface: (string) the interface on this linux host name: (string) optional name for this object icCs||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |ifdS(Nit nio_linux_ethsnio create_linux_eth %s %s( RuR(t_NIO_linux_eth__dt interfacet_NIO_linux_eth__interfaceRt_NIO_linux_eth__instanceR~RRSt_NIO_linux_eth__nameR7(R(RuRR~((RGRHrs     cCs|iS(N(R(R(R(((RGt__getinterfacescCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_linux_eth__getinterfaceRhRt_NIO_linux_eth__getnameR~(((RGRjs    t NIO_gen_ethcBsJtZdZdZedZdZeeZdZ ee Z RS(s Create a nio_gen_eth object dynamips: the dynamips server object interface: (string) the interface on this host name: (string) optional name for this object icCs||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |ifdS(Nit nio_gen_ethsnio create_gen_eth %s %s( RuR(t_NIO_gen_eth__dRt_NIO_gen_eth__interfaceRt_NIO_gen_eth__instanceR~RRSt_NIO_gen_eth__nameR7(R(RuRR~((RGRHs     cCs|iS(N(R(R(R(((RGRscCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_gen_eth__getinterfaceRhRt_NIO_gen_eth__getnameR~(((RGRs    tNIO_tapcBsJtZdZdZedZdZeeZdZ ee Z RS(s Create a nio_tap object dynamips: the dynamips server object tap: (string) the tap device name: (string) optional name for this object icCs||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |ifdS(Nitnio_tapsnio create_tap %s %s( RuR(t _NIO_tap__dttapt_NIO_tap__interfaceRt_NIO_tap__instanceR~RRSt_NIO_tap__nameR7(R(RuRR~((RGRHs     cCs|iS(N(R(R(R(((RGRscCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_tap__getinterfaceRhRt_NIO_tap__getnameR~(((RGRs    tNIO_unixcBs_tZdZdZedZdZeeZdZ ee Z dZ ee Z RS(s Create a nio_unix object dynamips: the dynamips server object unixlocal: local unix socket unixremote: remote unix socket name: (string) optional name for this object icCs||_||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |i|ifdS(Nitnio_unixsnio create_unix %s %s %s(RuR(t _NIO_unix__dt unixlocalt_NIO_unix__unixlocalt unixremotet_NIO_unix__unixremoteRt_NIO_unix__instanceR~RRSt_NIO_unix__nameR7(R(RuRRR~((RGRHs      cCs|iS(N(R(R(R(((RGt__getunixlocalscCs|iS(N(R(R(R(((RGt__getunixremotescCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_unix__getunixlocalRhRt_NIO_unix__getunixremoteRt_NIO_unix__getnameR~(((RGRs       tNIO_vdecBs_tZdZdZedZdZeeZdZ ee Z dZ ee Z RS(s Create a nio_vde object dynamips: the dynamips server object controlsock: control socket localsock: local socket name: (string) optional name for this object icCs||_||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |i|ifdS(NiRsnio create_vde %s %s %s(RuR(t _NIO_vde__dt controlsockt_NIO_vde__controlsockt localsockt_NIO_vde__localsockRt_NIO_vde__instanceR~RRSt_NIO_vde__nameR7(R(RuRRR~((RGRHs      cCs|iS(N(R(R(R(((RGt__getcontrolsockscCs|iS(N(R(R(R(((RGt__getlocalsockscCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_vde__getcontrolsockRhRt_NIO_vde__getlocalsockRt_NIO_vde__getnameR~(((RGRs       tNIO_nullcBs5tZdZdZedZdZeeZRS(s Create a nio_nulll object dynamips: the dynamips server object name: (string) optional name for this object icCso||_ti|_tid7_|djodt|i|_n ||_t |id|idS(Nitnio_nullsnio create_null %s( RuR(t _NIO_null__dRt_NIO_null__instanceR~RRSt_NIO_null__nameR7(R(RuR~((RGRHs    cCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_null__getnameRhR~(((RGRs  t BaseAdaptercBstZdZddZdZeeddZdZeeddZdZ ee dd Z d Z ee dd Z d Z ee dd ZedZdedZedZdZRS(s The base adapter object router: A Router object slot: An int specifying the slot adapter: the adapter or network module model ports: the number of ports bindingcommand: either "slot_add_binding" or None intlist: a list of interface descriptors this adapter provides (interface, port, dynamipsport) wics: number of WIC slots on this adapter ic Csxy |i} Wntj o d} nXy=|t|i| |jotd|||ifnWn)t j otd||ifnX||_ ||_ ||_ h|_h|_|dg|_|djoax^|D]R\} }} y|i| Wn t j oh|i| dddgdddgf}ti|||dd|dS(NRiis PA-2FE-TXi(RR RHR(RR(R(RRR((RGRH9s(RcRdReRH(((RGR6s tPA_GEcBstZdZdZRS(s" A PA-GE FastEthernet adapter cCs2dddgf}ti|||dd|dS(NR isPA-GEi(RR RHR(RR(R(RRR((RGRHAs(RcRdReRH(((RGR>s tPA_4TcBstZdZdZRS(s$ A PA_4T+ 4-port serial adapter cCsVdddgdddgdddgdddgf}ti|||dd|dS(NRiiiisPA-4T+i(RR RHR(RR(R(RRR((RGRHIs6(RcRdReRH(((RGRFs tPA_8TcBstZdZdZRS(s# A PA_8T 8-port serial adapter c Csdddgdddgdddgdddgdddgdddgdddgdd d gf}ti|||d d |dS( NRiiiiiiiisPA-8Ti(RR RHR(RR(R(RRR((RGRHQsf(RcRdReRH(((RGRNs tPA_4EcBstZdZdZRS(s% A PA_4E 4-port ethernet adapter cCsVdddgdddgdddgdddgf}ti|||dd|dS(NRiiiisPA-4Ei(RR RHR(RR(R(RRR((RGRHYs6(RcRdReRH(((RGRVs tPA_8EcBstZdZdZRS(s% A PA_8E 4-port ethernet adapter c Csdddgdddgdddgdddgdddgdddgdddgdd d gf}ti|||d d |dS( NRiiiiiiiisPA-8Ei(RR RHR(RR(R(RRR((RGRHasf(RcRdReRH(((RGR^s t PA_POS_OC3cBstZdZdZRS(s A PA-POS-OC3 adapter cCs2dddgf}ti|||dd|dS(Ntpis PA-POS-OC3i(RR RHR(RR(R(RRR((RGRHis(RcRdReRH(((RGRfs tNMcBstZdZddZRS(sx A C2691/C3725/C3745/C3600/C2600/C1700 Network Module base object. Derived from the C7200 port adapter, with methods overridden where necessary router: A Router object slot: An int specifying the slot module: the network module model ports: the number of ports intlist: a list of interface descriptors this adapter provides ic Cs^|ddddddddd g jo d}nd }ti||||||||dS( Ns GT96100-FEs Leopard-2FEsCISCO2600-MB-1EsCISCO2600-MB-2EsCISCO2600-MB-1FEsCISCO2600-MB-2FEsCISCO1710-MB-1FE-1Es C1700-MB-1ETHs C1700-WIC1R ( tmoduleRRRRHR(RRRRR(R(RRRRRRR((RGRHys( (RcRdReRH(((RGRps t Leopard_2FEcBstZdZdZRS(s1 Integrated 3660 2 Port FastEthernet adapter cCs>dddgdddgf}ti|||dd|dS(NRiis Leopard-2FEi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGRs t NM_1FE_TXcBstZdZdZRS(s& A NM-1FE-TX FastEthernet adapter cCs2dddgf}ti|||dd|dS(NRis NM-1FE-TXi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR s tNM_1EcBstZdZdZRS(s A NM-1E Ethernet adapter cCs2dddgf}ti|||dd|dS(NRisNM-1Ei(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR!s tNM_4EcBstZdZdZRS(s A NM-4E Ethernet adapter cCsVdddgdddgdddgdddgf}ti|||dd|dS(NRiiiisNM-4Ei(RRRHR(RR(R(RRR((RGRHs6(RcRdReRH(((RGR"s tNM_4TcBstZdZdZRS(s A NM-4T Serial adapter cCsVdddgdddgdddgdddgf}ti|||dd|dS(NRiiiisNM-4Ti(RRRHR(RR(R(RRR((RGRHs6(RcRdReRH(((RGR#s tNM_16ESWcBstZdZdZRS(s! A NM-16ESW Ethernet adapter cCsVg}x-tddD]}|id||gqWti|||dd|dS(NiiRsNM-16ESW( RtrangetitappendRRHR(RR(R(RRR&R((RGRHs (RcRdReRH(((RGR$s tNM_CIDScBstZdZdZRS(sW IDS Network Module Note, not currently functional in Dynamips just a stub cCs2dddgf}ti|||dd|dS(NR&isNM-CIDSi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR(s tNM_NAMcBstZdZdZRS(sO NAM Module Note, not currently functional in Dynamips just a stub cCs2dddgf}ti|||dd|dS(NtanisNM-NAMi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR)s t GT96100_FEcBstZdZdZRS(sF Integrated GT96100-FE 2691/3725/3745 2 Port FastEthernet adapter c CsDdddgdddgf}ti|||dd|dddS(NRiis GT96100-FEiRi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR+s tCISCO2600_MB_1EcBstZdZdZRS(s= Integrated CISCO2600-MB-1E 2600 1 Port Ethernet adapter c Cs8dddgf}ti|||dd|dddS(NRisCISCO2600-MB-1EiRi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR,s tCISCO2600_MB_2EcBstZdZdZRS(s= Integrated CISCO2600-MB-2E 2600 1 Port Ethernet adapter c CsDdddgdddgf}ti|||dd|dddS(NRiisCISCO2600-MB-2EiR(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR-s tCISCO2600_MB_1FEcBstZdZdZRS(sB Integrated CISCO2600-MB-1FE 2600 1 Port FastEthernet adapter c Cs8dddgf}ti|||dd|dddS(NRisCISCO2600-MB-1FEiRi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR.s tCISCO2600_MB_2FEcBstZdZdZRS(sB Integrated CISCO2600-MB-2FE 2600 2 Port FastEthernet adapter c CsDdddgdddgf}ti|||dd|dddS(NRiisCISCO2600-MB-2FEiR(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR/s tCISCO1710_MB_1FE_1EcBstZdZdZRS(s: Integrated CISCO1710-MB-1FE-1E 1710 1 FE 1 E adapter c CsDdddgdddgf}ti|||dd|dddS(NRiRisCISCO1710-MB-1FE-1EiR(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR0s t C1700_MB_1ETHcBstZdZdZRS(s? Integrated C1700-MB-1ETH 1700 1 Port FastEthernet adapter cCs5dddgf}ti|||dd|ddS(NRis C1700-MB-1ETHi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR1s t C1700_WIC1cBstZdZdZRS(so Fake module to provide a placeholder for slot 1 interfaces when WICs are inserted into WIC slot 1 c Cs,d}ti|||dd|dddS(Ns C1700-WIC1iRi(RRRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR2s tRoutercBstZdZdZdeedZeedZdZedZ dZ dZ d Z d Z d Zd Zed ZdZdZeeeddZdZdZeeeddZdZdZeeeddZdZdZeeeddZdZdZeeeddZ dZ!dZ"ee"e!dd Z#d!Z$d"Z%ee%e$dd#Z&d$Z'd%Z(ee(e'dd&Z)d'Z*d(Z+ee+e*dd)Z,d*Z-d+Z.ee.e-dd,Z/d-Z0d.Z1ee1e0dd/Z2d0Z3d1Z4ee4e3dd2Z5d3Z6ee6dd4Z7d5Z8d6Z9ee9e8dd7Z:d8Z;d9Z<ee<e;dd:Z=d;Z>d<Z?ee?e>dd=Z@d>ZAd?ZBeeBeAdd@ZCdAZDeeDddBZEdCZFeeFddDZGdEZHdFZIeeIeHdd@ZJdGZKdHZLeeLeKddIZMdJZNdKZOeeOeNddLZPdMZQdNZReeReQddOZSdPZTdQZUeeUeTddRZVdSZWdTZXeeXeWddUZYdVZZdWZ[ee[eZddXZ\dYZ]ee]ddZZ^d[Z_ee_dd\Z`d]Zaeeadd^Zbd_Zceecdd`ZddaZeeeeddbZfRS(csB Creates a new Router instance dynamips: a Dynamips object model: Router model console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number iRcCst|tp tdn||_ti|_tid7_|t jo ||_ n td|djodt|i|_n ||_d|_d|_d|_d|_d|_d|_d|_d|_t|_d|_d|_d|_d|_d |_d |_t |id ||i|f|oz|ii"|i}xdtoXt$||i}|djo+||_&t |id |i|fPqX|d7}qXWn|ii'i(|dS( Nsnot a Dynammips instanceisinvalid router modeltrt0x2102tstoppediiitunknownsvm create %s %i %ssvm set_con_tcp_port %s %i()t isinstanceRuR!R0R(t _Router__dR3t_Router__instance_countt_Router__instanceRt ROUTERMODELSt_Router__modelR~RRSt _Router__namet _Router__cnfgt _Router__conft _Router__mact_Router__clockt _Router__auxt_Router__imaget_Router__idlepct_Router__exec_areatTruet _Router__mmapt_Router__statet_Router__ghost_statust_Router__sparsememt_Router__idlemaxt_Router__idlesleept_Router__confregR7t consoleFlagRVtconsolet checkconsoletconflictt_Router__consoleRMR'(R(RuRR~RORPRR((RGRH sL                          cCs:||_||_||_||_||_ ||_ dS(s0 Set the default values for this router N( tramR(t _Router__ramtnvramt_Router__nvramtdisk0t_Router__disk0tdisk1t_Router__disk1Rt _Router__npetmidplanet_Router__midplane(R(RTRVRXRZRR]((RGt setdefaults>s     cCs|dg|_dS(s@ Create the appropriate number of slots for this router N(tnumslotsRR(R(R(R`((RGt createslotsIscCs|tjotd|n|ddgjo=|idddddgjotd ||ifqnB|d gjo1|idgjotd ||ifqn|djo=|i|}|d jotd |i||fqnt t|} d |d}|djod |d}n|}y||i |i|(R(((RGtdeletescCsn|idjotd|in|idjotd|int|id|i}d|_|S(s Start this instance trunningsrouter "%s" is already runningt suspendeds;router "%s" is suspended and cannot be started. Use Resume.s vm start %sN(R(RIR0R~R7R9R>R4(R(R4((RGtstarts cCsJ|idjotd|int|id|i}d|_|S(s Stop this instance R6srouter "%s" is already stoppeds vm stop %sN(R(RIR0R~R7R9R>R4(R(R4((RGRLs  cCsn|idjotd|in|idjotd|int|id|i}d|_|S(s Suspend this instance Ros router "%s" is already suspendedR6s.router "%s" is stopped and cannot be suspendeds vm suspend %sN(R(RIR0R~R7R9R>R4(R(R4((RGtsuspends cCsn|idjotd|in|idjotd|int|id|i}d|_|S(s Resume this instance Rnsrouter "%s" is already runningR6s,router "%s" is stopped and cannot be resumeds vm resume %sN(R(RIR0R~R7R9R>R4(R(R4((RGtresumes cCs|idjotd|in|tjo!t|id|i}|Snl|t jo!t|id|i}|Sn>|t jo0t|id|i|f}||_ |SndS(s3 get, show, or set the online idlepc value R6sMrouter "%s" is stopped. Idle-pc functions can only be used on running routerssvm get_idle_pc_prop %s 0svm show_idle_pc_prop %s 0svm set_idle_pc_online %s 0 %sN(R(RIR0R~tfunctiont IDLEPROPGETR7R9R>R4t IDLEPROPSHOWt IDLEPROPSETtvalueRE(R(RsRwR4((RGtidleprops    cCst|tjp|djp |djo tdnt||i}|djo+||jotd||i fqn||_ t |id|i |i fdS(sI Set console port console: (int) TCP port of console iisinvalid console ports/console port %i is already in use by device: %ssvm set_con_tcp_port %s %iN( RQRPRAR0RQR(R9RRRR~RSR7R>(R(RPRR((RGt __setconsoles-    cCs|iS(s Returns console port N(R(RS(R(((RGt __getconsolesRPsThe router console portcCsgt|tjp|djp |djo tdn||_t|id|i|ifdS(sF Set aux port aux: (int) TCP port of the aux port iisinvalid aux portsvm set_aux_tcp_port %s %iN( RQtauxRAR0R(RCR7R9R>(R(R{((RGt__setaux s -  cCs|iS(s Returns aux port N(R(RC(R(((RGt__getauxssThe router aux portcCsyt|tjo tdntid|tip tdn||_t |i d|i |i |ifdS(sW Set the base MAC address of this router mac: (string) MAC address sinvalid MAC addresss)^([0-9a-f][0-9a-f]\:){5}[0-9a-f][0-9a-f]$s3Invalid MAC address. Format is "xx:xx:xx:xx:xx:xx".s%s set_mac_addr %s %sN( RQtmacRSR0tretsearcht IGNORECASER(RAR7R9R=R>(R(R~((RGt__setmacs   cCs|iS(s1 Returns base MAC address of this router N(R(RA(R(((RGt__getmac&ss#The base MAC address of this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(s_ Set amount of RAM allocated to this router ram: (int) amount of RAM in MB isinvalid ram sizesvm set_ram %s %iN( RQRTRAR0R(RUR7R9R>(R(RT((RGt__setram.s    cCs|iS(s< Returns the amount of RAM allocated to this router N(R(RU(R(((RGt__getram7ss*The amount of RAM allocated to this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(sU Set size of PCMCIA ATA disk0 disk0: (int) amount of disk0 in MB isinvalid disk0 sizesvm set_disk0 %s %iN( RQRXRAR0R(RYR7R9R>(R(RX((RGt __setdisk0?s    cCs|iS(s/ Returns the disk0 size on this router N(R(RY(R(((RGt __getdisk0HssThe disk0 size on this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(sU Set size of PCMCIA ATA disk1 disk1: (int) amount of disk1 in MB isinvalid disk1 sizesvm set_disk1 %s %iN( RQRZRAR0R(R[R7R9R>(R(RZ((RGt __setdisk1Ps    cCs|iS(s/ Returns the disk1 size on this router N(R(R[(R(((RGt __getdisk1YssThe disk1 size on this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(sG Set the clock property clock: (int) clock divisor is invalid clocksvm set_clock_divisor %s %iN( RQtclockRAR0R(RBR7R9R>(R(R((RGt __setclock`s    cCs|iS(s Returns clock property N(R(RB(R(((RGt __getclockiss!The clock property of this routercCsgt|tjo tdn||_|tjo d}nd}t|i d|i |fdS(s_ Set the mmap property mmap: (boolean) Map dynamic memory to a file or not s invalid mmapiisvm set_ram_mmap %s %iN( RQtmmaptboolR0R(RHRGtflagR7R9R>(R(RR((RGt __setmmapqs    cCs|iS(s Returns mmap property N(R(RH(R(((RGt __getmmap~ss The mmap property of this routerc Cs{t|tjp(|ddddddddd g jo td n||_t|id |i|i |ifd S( sI Set the npe property npe: (string) Set the NPE type snpe-100snpe-150snpe-175snpe-200snpe-225snpe-300snpe-400snpe-g1snpe-g2sinvalid NPE types%s set_npe %s %sN( RQRRSR0R(R\R7R9R=R>(R(R((RGt__setnpes ;  cCs|iS(s Returns npe property N(R(R\(R(((RGt__getnpessThe npe property of this routercCsft|tjp|ddgjo tdn||_t|id|i|i |ifdS(sX Set the midplane property midplane: (string) Set the midplane type tstdtvxrsinvalid midplane types%s set_midplane %s %sN( RQR]RSR0R(R^R7R9R=R>(R(R]((RGt __setmidplanes &  cCs|iS(s# Returns midplane property N(R(R^(R(((RGt __getmidplaness$The midplane property of this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(se Set amount of nvram allocated to this router nvram: (int) amount of nvram in KB isinvalid nvram sizesvm set_nvram %s %iN( RQRVRAR0R(RWR7R9R>(R(RV((RGt __setnvrams    cCs|iS(s> Returns the amount of nvram allocated to this router N(R(RW(R(((RGt __getnvramss,The amount of nvram allocated to this routercCs-||_t|id|i|ifdS(sU Set the IOS image for this router image: path to IOS image file svm set_ios %s %sN(timageR(RDR7R9R>(R(R((RGt __setimages cCs|iS(s= Returns path of the image being used by this router N(R(RD(R(((RGt __getimagess"The IOS image file for this routercCs:|idjodSntii|iid}|S(s6 Returns just the name of the image file used t"N(R(RDRtostpathtbasenametstripR(R(R((RGt__getimagenames s.The name of the IOS image file for this routercCs-||_t|id|i|ifdS(sq Import an IOS configuration file into NVRAM cnfg: path to configuration file to be imported svm set_config %s %sN(tcnfgR(R?R7R9R>(R(R((RGt __setcnfgs cCs|iS(s< Returns path of the cnfg being used by this router N(R(R?(R(((RGt __getcnfgss/The IOS configuration file to import into NVRAMcCs-||_t|id|i|ifdS(sL Set the configuration register confreg: confreg string svm set_conf_reg %s %sN(tconfregR(RNR7R9R>(R(R((RGt __setconfregs cCs|iS(s Returns the confreg N(R(RN(R(((RGt __getconfregss)The configuration register of this routercCs0todSnt|id|i|fdS(s4 Set the config to this base64 encoded configurationNsvm push_config %s %s(tDEBUGGERR7R(R9R>tconf64(R(R((RGt__set_config_b64scCsItodSnt|id|i}|diddi}|S(s5Get the base64 encoded config from the router's nvramNsvm extract_config %sit i( RR7R(R9R>tcfR:Rt b64config(R(RR((RGt__get_config_b64s s3The configuration of this router in base64 encodingcCs-||_t|id|i|ifdS(sW Set the Idle Pointer Counter for this instance pc: idle-pc string svm set_idle_pc %s %sN(tpcR(RER7R9R>(R(R((RGt __setidlepcs cCs|iS(s$ Returns the current idlepc N(R(RE(R(((RGt __getidlepc ss2The Idle Pointer Counter assigned to this instancecCsKtp@t|id|i}|ddjo|in|SndS(s) Returns the current idlepcdrift svm show_timer_drift %s 0is100-OKN(RR7R(R9R>RItpop(R(RI((RGt__getidlepcdrifts s"The idle-pc drift valueof instancecCsKtp@t|id|i}|ddjo|in|SndS(s% Returns the current cpuinfo svm cpu_info %s 0is100-OKN(RR7R(R9R>RIR(R(RI((RGt __getcpuinfos sThe cpu info for this instancecCs-||_t|id|i|ifdS(s\ Set the idlemax value for this instance val: (integer) idlemax counter svm set_idle_max %s 0 %iN(tvalR(RLR7R9R>(R(R((RGt __setidlemax%s cCs|iS(s% Returns the current idlemax N(R(RL(R(((RGt __getidlemax,scCs-||_t|id|i|ifdS(s_ Set the idle_sleep_time for this instance val: (integer) sleep time in ms svm set_idle_sleep_time %s 0 %iN(RR(RMR7R9R>(R(R((RGt__setidlesleep3s cCs|iS(s? Returns the current idlesleep value for this instance N(R(RM(R(((RGt__getidlesleep:ss$The idle sleep time of this instancecCsgt|tjo tdn||_|tjo d}nd}t|i d|i |fdS(s Set oldidle to True to use pre 0.2.7-RC1 idlepc values. It disables direct jumps between JIT blocks state: (bool) True to use old idlepc values, false to use RC2 and later values sinvalid oldidle statusiisvm set_blk_direct_jump %s %iN( RQtstateRR0R(t_Router__oldidleRGRR7R9R>(R(RR((RGt __setoldidleBs    cCs|iS(s+ Returns the current oldidle value N(R(R(R(((RGt __getoldidleQssEnable or disable legacy idle pc value option. Setting to True disables direct jumps between JIT blocks, allowing use of pre 0.2.7-RC2 idlepc values.cCs3||_t|id|it|ifdS(sT Set the Exec Area size for this instance pc: Exec area integer svm set_exec_area %s %sN(t exec_areaR(RFR7R9R>RS(R(R((RGt__setexec_areaYs cCs|iS(s Returns the exec_area N(R(RF(R(((RGt__getexec_area`ss,The Exec Area size assigned to this instancecCs3||_t|id|it|ifdS(s Set the ghost_status of this instance status: (int) Tristate flag indicating status 0 -> Do not use IOS ghosting 1 -> This is a ghost instance 2 -> Use an existing ghost instance svm set_ghost_status %s %sN(tstatusR(RJR7R9R>RS(R(R((RGt__setghost_statushs cCs|iS(s" Returns the ghost_status N(R(RJ(R(((RGt__getghost_statusrss!The ghost status of this instancecCs3||_t|id|it|ifdS(sx Set the ghost file for this instance ghost_file: (string) ghost file name to create (or reference) svm set_ghost_file %s %sN(t ghost_fileR(t_Router__ghost_fileR7R9R>RS(R(R((RGt__setghost_filezs cCs|iS(s Returns the ghost_file N(R(R(R(((RGt__getghost_filess,The ghost file associated with this instancecCsG||_|tjo d}nd}t|id|i|fdS(s Set the sparsemem of this instance status: (int) Flag indicating enabled or disabled false -> Do not use sparsemem true -> Turn on sparsemem t1t0svm set_sparse_mem %s %sN(RR(RKRGRR7R9R>(R(RR((RGt__setsparsemems    cCs|iS(s Returns the sparsemem N(R(RK(R(((RGt__getsparsememss%The sparsemem status of this instancecCs|iS(sB Returns the dynamips server on which this device resides N(R(R9(R(((RGt __getdynamipsss/The dynamips object associated with this devicecCs|iS(s& Returns model of this router N(R(R=(R(((RGt __getmodelssThe model of this routercCs|iS(s) Returns the name of this router N(R(R>(R(((RGRssThe name of this routercCs|iS(s* Returns the state of this router N(R(RI(R(((RGt __getstatessThe state of this routercCstS(s1 Returns true if this device is a router N(RG(R(((RGt __getisrouterss'Returns true if this device is a router(gRcRdReR:RRGRHR_RaRkReRmRpRLRqRrRxt_Router__setconsolet_Router__getconsoleRhRPt_Router__setauxt_Router__getauxR{t_Router__setmact_Router__getmacR~t_Router__setramt_Router__getramRTt_Router__setdisk0t_Router__getdisk0RXt_Router__setdisk1t_Router__getdisk1RZt_Router__setclockt_Router__getclockRt_Router__setmmapt_Router__getmmapRt_Router__setnpet_Router__getnpeRt_Router__setmidplanet_Router__getmidplaneR]t_Router__setnvramt_Router__getnvramRVt_Router__setimaget_Router__getimageRt_Router__getimagenamet imagenamet_Router__setcnfgt_Router__getcnfgRt_Router__setconfregt_Router__getconfregRt_Router__set_config_b64t_Router__get_config_b64t config_b64t_Router__setidlepct_Router__getidlepctidlepct_Router__getidlepcdriftt idlepcdriftt_Router__getcpuinfotcpuinfot_Router__setidlemaxt_Router__getidlemaxtidlemaxt_Router__setidlesleept_Router__getidlesleept idlesleept_Router__setoldidlet_Router__getoldidletoldidlet_Router__setexec_areat_Router__getexec_areaRt_Router__setghost_statust_Router__getghost_statust ghost_statust_Router__setghost_filet_Router__getghost_fileRt_Router__setsparsememt_Router__getsparsememt sparsememt_Router__getdynamipsRut_Router__getmodelRt_Router__getnameR~t_Router__getstateRt_Router__getisroutertisrouter(((RGR3s 4  O                                             tC7200cBstZdZedZRS(s+ Creates a new 7200 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number cCsati||ddd|ti|dddddd d d d d ddti|ddS(NRRR~RTiRViRXi@RZiRsnpe-200R]Ri(R3RHR(RuR~R_Ra(R(RuR~((RGRHs  (RcRdReRRH(((RGRs tC2691cBstZdZedZRS(s+ Creates a new 2691 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number c Cskti||ddd|ti|dddddd d d ti|d t|d |id 't'schassis type -> sinvalid chassis typesc2600 set_chassis %s %sN( RQRRStunicodet CHASSIS2600tdebugR0R(RR7RR(R(R((RGt __setchassiss&   cCs|iS(s" Returns chassis property N(R(R(R(((RGt __getchassis$sRPs#The chassis property of this router( RcRdReRRHt_C2600__setchassist_C2600__getchassisRhR(((RGRs  ! tC3725cBstZdZedZRS(s+ Creates a new 3725 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number c Cskti||ddd|ti|dddddd d d ti|d t|d |id sinvalid chassis type(RuR(t _C3600__dRt_C3600__chassisR~t _C3600__nameR3RHR_RaRRSR0(R(RuRR~((RGRH^s$         cCst|ttgjp|dddgjoItdtdt|dtdtt|tdn||_t|i d |i |ifd S( sU Set the chassis property chassis: (string) Set the chassis type RRRs&Invalid chassis passed to __setchassiss chassis -> 'Rschassis type -> sinvalid chassis typesc3600 set_chassis %s %sN( RQRRSRRR0R(R%R7R$R&(R(R((RGRxs/   cCs|iS(s" Returns chassis property N(R(R%(R(((RGRsRPs#The chassis property of this routercCszyt|}Wntj otdnX|ddjo tdn||_t|id|i|ifdS(sP Set the iomem property iomem: (string) Set the iomem value s&invalid iomem type, must be an integeriisiomem must be a multiple of 5sc3600 set_iomem %s %sN( RAtiomemt ValueErrorR0R(t _C3600__iomemR7R$R&(R(R'((RGt __setiomems  cCs|iS(s Returns iomem property N(R(R)(R(((RGt __getiomemssThe iomem size of this router( RcRdReRRHt_C3600__setchassist_C3600__getchassisRhRt_C3600__setiomemt_C3600__getiomemR'(((RGR#Vs    tC1700cBshtZdZedZdZdZeeeddZdZ dZ ee e ddZ RS( s+ Creates a new 1700 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number c Cs#||_||_||_ti||ddd|ti |dddddd d d ||_|d d gjoti |d nti |dhdt <dt <dt <dt <d t <d t <}|||d |id <|d d gjot|d|id 'Rschassis type -> sinvalid chassis typesc1700 set_chassis %s %sN( RQRRSRt CHASSIS1700RR0R(R2R7R1R3(R(R((RGRs&   cCs|iS(s" Returns chassis property N(R(R2(R(((RGRsRPs#The chassis property of this routercCszyt|}Wntj otdnX|ddjo tdn||_t|id|i|ifdS(sP Set the iomem property iomem: (string) Set the iomem value s&invalid iomem type, must be an integeriisiomem must be a multiple of 5sc1700 set_iomem %s %sN( RAR'R(R0R(t _C1700__iomemR7R1R3(R(R'((RGR*s  cCs|iS(s Returns iomem property N(R(R6(R(((RGR+ssThe iomem size of this router( RcRdReRRHt_C1700__setchassist_C1700__getchassisRhRt_C1700__setiomemt_C1700__getiomemR'(((RGR0s  &  R0cBstZRS(N(RcRd(((RGR0stDynamipsErrorHandledcBstZRS(N(RcRd(((RGR;sRDcBstZRS(N(RcRd(((RGRDstDynamipsWarningcBstZRS(N(RcRd(((RGR<sRcBstZdZdZeedZdZedZdZ e e ddZ dZ e e dd Z d Ze edd Zd Ze edd ZRS(so Creates a new Ethernet bridge instance dynamips: a Dynamips object name: An optional name icCs||_ti|_tid7_|djodt|i|_ n ||_ g|_ |ot |id|i ndS(Nitbsnio_bridge create ( RuR(t _Bridge__dRt_Bridge__instance_countt_Bridge__instanceR~RRSt _Bridge__namet _Bridge__niostcreateR7(R(RuR~RC((RGRH s     cCsdS(sC Delete this Frame Relay switch instance from the back end N((R(((RGRmscCs|djo.y |iSWq;tj otdq;Xnt|}|tjp4|t jp'|t jp|t jp |t jo$t |id|i|ifn|ii|dS(sB Adds an NIO to this bridge nio: A nio object s"port does not exist on this switchsnio_bridge add_nio %s %sN(RRR(RBRR0RQRRsRRRRR7R>RAR~R'(R(RR((RGR s   A$cCsdS(s& Returns the adapter property RN((R(((RGR3sRPsThe port adaptercCs|iS(s# Returns the name property N(R(RA(R(((RGR:ssThe device namecCs|iS(sB Returns the dynamips server on which this device resides N(R(R>(R(((RGRBss/The dynamips object associated with this devicecCstS(s1 Returns true if this device is a router N(tFalse(R(((RGRIss'Returns true if this device is a router(RcRdReR?RRGRHRmRt_Bridge__getadapterRhRt_Bridge__getnameR~t_Bridge__getdynamipsRut_Bridge__getisrouterR(((RGRs       RcBstZdZdZeedZdZdZdZ dZ edZ dZ d Z ee d d Zd Zeed d ZdZeed dZdZeed dZRS(sr Creates a new Frame Relay switch instance dynamips: a Dynamips object name: An optional name icCs||_ti|_tid7_|djodt|i|_ n ||_ h|_ h|_ |ot |id|i ndS(NiRs frsw create (RuR(t_FRSW__dRt_FRSW__instance_countt_FRSW__instanceR~RRSt _FRSW__namet _FRSW__dlcist _FRSW__niosRCR7(R(RuR~RC((RGRHXs      cCsdS(sC Delete this Frame Relay switch instance from the back end N((R(((RGRmgscCst|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdny|i|i }Wnt j otdnXy|i|i }Wnt j otdnXt |id|i||||f|ii|o|i|i|n|g|i|<|ii|o|i|i|n|g|i|= 0s"invalid port2. Must be an int >= 0s"invalid dlci1. Must be an int >= 0s#port1 does not exist on this switchs#port2 does not exist on this switchsfrsw create_vc %s %s %i %s %iN(RQtport1RAR0tport2tdlci1tdlci2R(RR~tnio1Rtnio2R7RIRLRMthas_keyR'(R(RORQRPRRRTRS((RGtmapms0        &c Cs?ttttd|id|d|d|d|d|dS(s Connect this switch to a port on another device remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter object on a router remoteport: A port on the remote adapter RRRRRRN( RRRRR(RIRRRR(R(RRRR((RGR-s  cCs t||S(sG Returns a boolean indicating if this port is connected or not N(RR(R/(R(R/((RGRscCsi|djoKy|i|SWqXtj o)tdt|d|idqXXn||i|= 0s"invalid port2. Must be an int >= 0s!invalid vpi1. Must be an int >= 0s!invalid vpi2. Must be an int >= 0s#port1 does not exist on this switchs#port2 does not exist on this switchsatmsw create_vpc %s %s %i %s %iN(RQRORAR0RPtvpi1tvpi2R(RR~RSRRTR7R\R_R`RUR'(R(RORbRPRcRTRS((RGtmapvp s0        &c Cst|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdny|i |i }Wnt j otdnXy|i |i }Wnt j otd nXt|id |i||||||f|ii|o|i|i|n|g|i|<|ii|o|i|i|n|g|i|= 0s"invalid port2. Must be an int >= 0s!invalid vpi1. Must be an int >= 0s!invalid vpi2. Must be an int >= 0s!invalid vci1. Must be an int >= 0s!invalid vci2. Must be an int >= 0s#port1 does not exist on this switchs#port2 does not exist on this switchs%atmsw create_vcc %s %s %i %i %s %i %iN(RQRORAR0RPRbRctvci1tvci2R(RR~RSRRTR7R\R_R`RUR'( R(RORbReRPRcRfRTRS((RGtmapvc5 s8            ,c Cs?ttttd|id|d|d|d|d|dS(s Connect this switch to a port on another device remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter object on a router remoteport: A port on the remote adapter RRRRRRN( RRRRR(R\RRRR(R(RRRR((RGR-a s  cCs t||S(sG Returns a boolean indicating if this port is connected or not N(RR(R/(R(R/((RGRq scCsi|djoKy|i|SWqXtj o)tdt|d|idqXXn||i|= 0s!invalid vlan. Must be an int >= 0s#port1 does not exist on this switchtaccesstdot1qsinvalid porttypes ethsw set_s_port RN(RQR/RAR0tvlanR(RR~RtporttypeRR7RmRpRS(R(R/RuRtR((RGtset_port s    cCst|id|iS(s. Show this switch's mac address table sethsw show_mac_addr_table N(R7R(RmRp(R(((RGtshow_mac scCst|id|iS(s/ Clear this switch's mac address table sethsw clear_mac_addr_table N(R7R(RmRp(R(((RGt clear_mac sc Cs?ttttd|id|d|d|d|d|dS(s Connect this switch to a port on another device remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter object on a router remoteport: A port on the remote adapter RRRRRRN( RRRRR(RmRRRR(R(RRRR((RGR- s  cCs t||S(sG Returns a boolean indicating if this port is connected or not N(RR(R/(R(R/((RGR scCs_|d joKy|i|SWqXtj o)tdt|d|idqXXnt |}|t jp4|t jp'|t jp|tjp |tjo$t|id|i|ifn td||i|<|d joo|i}|djo|djo tdnt|id |d |id |id t|nd S( s Returns the NETIO object for this port or if nio is set, sets the NETIO for this port port: a port on this adapter nio: optional NETIO object to assign porttype: either access or dot1q sEthernet switchport s on device "s" is defined, but not usedsethsw add_nio %s %ssinvalid NIO typeRrRssinvalid porttypes ethsw set_s_port RN(RRR(RqR/RR<RSR~RQRRsRRRRR7RmRpR0RuRRt(R(R/RRuRtR((RGR s  + A$     cCsdS(s& Returns the adapter property RN((R(((RGR- sRPsThe port adaptercCs|iS(s# Returns the name property N(R(Rp(R(((RGR5 ssThe device namecCs|iS(sB Returns the dynamips server on which this device resides N(R(Rm(R(((RGR= ss/The dynamips object associated with this devicecCstS(s1 Returns true if this device is a router N(RD(R(((RGRD ss'Returns true if this device is a router(RcRdReRnRRGRHRmRvRwRxR-RRt_ETHSW__getadapterRhRt_ETHSW__getnameR~t_ETHSW__getdynamipsRut_ETHSW__getisrouterR(((RGR s$           cCs3d}g}td|idt|id|tpy|i i |i dWn/t j o#d|iGHdGHdGHt nXg}d }xGto?y |i i|}||7}WnSt j o%}d |iGH|GHdGHt n$d |iGHdGHdGHt nXy|d djownWn/tj o#d |iGHdGHdGHt nX||id 7}|d d jo|ind }|d d djoPnti|d ot|d qqWt|djod|iGHtdntdt||Snd SdS(s Sends raw commands to the Dynamips process dynamips: a dynamips object command: raw commands returns results as a list is sending to t:s -> s s1Error: lost communication with dynamips server %ss<Dynamips may have crashed. Check the Dynamips server output.s Exiting...R s6Error: timed out communicating with dynamips server %ss4Error: could not communicate with dynamips server %sis is100-is@Error: no data returned from dynamips server %s. Server crashed?sno datas returned -> N(tSIZEt resultsetRRuR.RSR/tcommandR,RtsendallRR+R;tdatatbufRGtrecvtchunktmessageR9R:Rterror_reRR0Rf(RuRRRRRRR~((RGR7O sf*           c Cs|i|ijod} d} n|i} |i} |i}|id|_tdt|i|i}|id|_tdt|it ||| |}t ||| |} |id|d|t|to|id| n|id|d| dS(s Generalized connect function called by all connect methods. Connects a souce interface / port to a destination interface / port src_dynamips: the dynamips object that hosts the source connection src_adapter: the source adapter src_port: the source port dst_dynamips: the dynamips object that hosts the destination connection dst_adapter: the destination adatper dst_port: the destination port (set to none if the destination is a bridge) s 127.0.0.1issource NIO udp is now: sdest NIO udp is now: R/RN(RR.Rtsrc_iptdst_ipRYtsrc_udpRRStdst_udpRstsrc_niotdst_nioRRRR8RRR( RRRRRRRRRRRR((RGR s$      cCsd }d}d}d}||jo||jod Snz||jo||jod SnX||jo||jod Sn6||jo||jod Sntd ||fd S( s Check to see if a given adapter can be connected to another adapter i1: interface type 1 i2: interface type 2 RRR tnR&RRRNsattempt to connect %s to %s(RRR RR&(t ethernetstserialstatmstpossti1ti2R0(RRRRRR((RGR s cCs4y|i|i}Wntj o tSnXtS(sC Returns a boolean indicating if this port is connected or not N(tobjRR/R~RSRRDRG(RR/RS((RGR s  cCsSxL|iD]A}y |i}Wntj o q nX||jo|Sq q WdS(sk Returns the device that uses the console port Returns None if no device has that console port N(RuRMtdeviceRPtcon2RR(RPRuRR((RGRQ s    cCs(|tjp |tjo |andS(s@ If true, don't actually send any commands to the back end. N(RRGRDR,(R((RGtnosend scCs(|tjp |tjo |andS(s If true, print out debugs N(RRGRDtDEBUG(R((RGtsetdebug& scCstodt|GHndS(s' Print string if debugging is true s DEBUG: N(RRSR^(R^((RGR/ st__main__s,/opt/ios-images/c1710-k9o3sy-mz.124-16.imaget localhosti s/tmpRR~tr1i({RetsysRRtbase64R%R+R&R'R8tMAJORtMINORtSUBtRCVERRCRERDR,RRtRuRvtcompileRtlast_retDBGPHideChildrent NameErrorRRGR<t DEVICETUPLER5Rt CHASSIS3600tMB2CHASSIS1700tMB2CHASSIS2600tGENERIC_1700_NMStGENERIC_2600_NMStGENERIC_3600_NMStGENERIC_3700_NMStGENERIC_7200_PAStIO_7200RcRRRR%RtobjectR!RsRRRRRRRR R RRRRRRRRRRRRRR R!R"R#R$R(R)R+R,R-R.R/R0R1R2R3RRRR!R"R#R0t ExceptionR0R;RDR<RRRRR7RRRRQRRRRctIMAGERRKRkRRRTRkRp(iRRRRR7RR8RtRRRR.RR R+R!R"RRR+RR2RRQR'RR;R-RRRRR<RR RR$RR5RR,R%RRR&RRRRuRRRR0RRRRRDRR!RRvRR1RCRRR3RR#RRRRR<RR0RR RER!RcRR/RRRR)R0RRRR"RRRR#RsRRRR(RRR((RGt?s($ K$< ` !6 (   *#$      =KVL W , 1         m fFc@s dZdkZdkZdkZdkZdklZlZlZlZdZ ddddf\Z Z Z Z e de d e e Zd ZeaeadZd Zd Zeid ZeidZyeWnej o eZnXeZdddddddfZddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,fZddddddfZddddd d!d"d#d$d%f Z d)d*d+fZ!hdd-<dd.<dd.<dd.<dd.<dd.d?d@dAdBf Z(dCdDdEfZ)hdFd dGg<dHddGg<dId dJgdne:fdoYZ?dpe:fdqYZ@dre:fdsYZAdte:fduYZBdve:fdwYZCdxe:fdyYZDdze:fd{YZEd|e:fd}YZFd~e9fdYZGdeGfdYZHdeGfdYZIdeGfdYZJdeGfdYZKdeGfdYZLdeGfdYZMdeGfdYZNdeGfdYZOdeGfdYZPdeGfdYZQdeGfdYZRdeGfdYZSdeGfdYZTdeGfdYZUdeGfdYZVdeGfdYZWde0fdYZXdeXfdYZYdeXfdYZZdeXfdYZ[deXfdYZ\deXfdYZ]deXfdYZ^deXfdYZ_de`fdYZade`fdYZbde`fdYZcde`fdYZdde0fdYZede0fdYZfde0fdYZgde0fdYZhdZidZjdZkdZldZmdZndZodZpeqdjoeadZre1ddZsesitdes_ue_esddddZverev_wdev_xeviydFddevizesitndS(s dynamips_lib.py Copyright (C) 2006 Greg Anuzelli This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. N(ssocketstimeoutsAF_INETs SOCK_STREAMs 0.10.1.090807iiif0.10000000000000001i'ids 0.2.8-RC1iis ^2[0-9][0-9]-s^[1-2][0-9][0-9]-tc1700tc2600tc2691tc3725tc3745tc3600tc7200t1710t1720t1721t1750t1751t1760t2610t2611t2620t2621t2610XMt2611XMt2620XMt2621XMt2650XMt2651XMt2691t3725t3745t3620t3640t3660t7200sCISCO1710-MB-1FE-1Es C1700-MB-1ETHsCISCO2600-MB-1EsCISCO2600-MB-2EsCISCO2600-MB-1FEsCISCO2600-MB-2FEs NM-1FE-TXsNM-1EsNM-4EsNM-16ESWsNM-CIDSsNM-NAMsNM-4TsPA-A1sPA-FE-TXs PA-2FE-TXsPA-GEsPA-4T+sPA-8TsPA-4EsPA-8Es PA-POS-OC3s C7200-IO-FEs C7200-IO-2FEs C7200-IO-GE-EsWIC-1TtssWIC-2Ts WIC-1ENETtes C1700-WIC1s GT96100-FEtis Leopard-2FEiitDynamipscBs7tZdZdddZdZdZdZdZdZe eed d Z d Z d Z e e e d d Z dZdZe eed dZdZdZe eed dZdZdZdZe ed dZdZe ed dZdZe ed dZRS(s Creates a new connection to a Dynamips server host: the hostname or ip address of the Dynamips server port: the tcp port (defaults to 7200) timeout: how log to wait for a response to commands sent to the server default is 3 seconds i i,c Csttt|_|iid|ii|tp1y|ii ||fWqjt dqjXng|_ d|_||_||_d|_d|_yt|ddd}Wntj o d}nXy|id did \}}}|id d } | d d jotd | d }nd}t|dt|dt||} Wnd|GHd} nX| tjot dt!||fn||_"dS(NisCould not connect to serverR ii'shypervisor versionisN/At-t.iitRCf0.999idsVWarning: problem determing dynamips server version on host: %s. Skipping version checki?BsThis version of Dynagen requires at least version %s of dynamips. Server %s is runnning version %s. Get the latest version from http://www.ipflow.utc.fr/blog/(#tsockettAF_INETt SOCK_STREAMtselfRt setblockingt settimeoutttimeouttNOSENDtconnectthosttportt DynamipsErrort_Dynamips__devicest_Dynamips__workingdirt_Dynamips__hostt_Dynamips__portt_Dynamips__baseconsolet_Dynamips__udptsendtversiont IndexErrortsplittmajortminortsubtrelease_candidatetfloattrcvertinttintvertINTVERtDynamipsVerErrortSTRVERt_Dynamips__version( R(R.R/R+R;R@R=R8R<RBR>((t/usr/bin/dynamips_lib.pyt__init__s>       %0   cCs t|d}|iidS(sG Close the connection to the Hypervisor (but leave it running) shypervisor closeN(R7R(tresultRtclose(R(RI((RGRJscCst|d}dS(s reset the hypervisor shypervisor resetN(R7R(RI(R(RI((RGtresetscCs t|d}|iidS(s" Shut down the hypervisor shypervisor stopN(R7R(RIRRJ(R(RI((RGtstopscCs ||_dS(s Set the list of devices managed by this dynamips instance This method is for internal use by Router.__init__ devices: (list) a list of device objects N(tdevicesR(R1(R(RM((RGt __setdevicesscCs|iS(sG Returns the list of devices managed by this dynamips instance N(R(R1(R(((RGt __getdevicesstdocs5The list of devices managed by this dynamips instancecCsAt|tjo tdn||_t|d|idS(sb Set the working directory for this network directory: (string) the directory sinvalid directoryshypervisor working_dir %sN(ttypet directorytstrR0R(R2R7(R(RR((RGt__setworkingdirs   cCs|iS(s# Returns working directory N(R(R2(R(((RGt__getworkingdirssThe working directorycCs-t|tjo tdn||_dS(su Set the base console TCP port for this server directory: (int) the starting console port number sinvalid console portN(RQt baseconsoleRAR0R(R5(R(RV((RGt__setbaseconsoles cCs|iS(s# Returns working directory N(R(R5(R(((RGt__getbaseconsolessThe starting console portcCs-t|tjo tdn||_dS(sj Set the next open UDP port for NIOs for this server udp: (int) the next NIO udp port sinvalid UDP portN(RQtudpRAR0R(R6(R(RY((RGt__setudp s cCs|iS(s6 Returns the next available UDP port for NIOs N(R(R6(R(((RGt__getudpss$The next available UDP port for NIOscCst||d}|S(sb Send a generic list command to Dynamips subsystem is one of nio, frsw, atmsw s listN(R7R(t subsystemRI(R(R\RI((RGtlistscCst||}|S(s8 Send a raw command to Dynamips. Use sparingly. N(R7R(tstringRI(R(R^RI((RGtsend_raw"scCs|iS(s# Returns the host property N(R(R3(R(((RGt __gethost)ssThe dynamips host IP or namecCs|iS(s# Returns the port property N(R(R4(R(((RGt __getport0ssThe dynamips portcCs|iS(s" Returns dynamips version N(R(RF(R(((RGt __getversion8ssThe dynamips version(t__name__t __module__t__doc__RHRJRKRLt_Dynamips__setdevicest_Dynamips__getdevicestpropertyRMt_Dynamips__setworkingdirt_Dynamips__getworkingdirt workingdirt_Dynamips__setbaseconsolet_Dynamips__getbaseconsoleRVt_Dynamips__setudpt_Dynamips__getudpRYR]R_t_Dynamips__gethostR.t_Dynamips__getportR/t_Dynamips__getversionR8(((RGR!s2 *               tNIO_udpcBsttZdZdZedZdZeeZdZ ee Z dZ ee Z dZ ee ZRS(s  Create a nio_udp object dynamips: the dynamips server object udplocal: (int) local udp port remotehost: (string) host or ip address of remote udpremote: (int) remote udp port name: (string) optional name for this object icCs||_||_||_||_t i |_ t i d7_ |djodt |i |_n ||_t|id|i|i|i|ifdS(Nitnio_udpsnio create_udp %s %i %s %i(tdynamipsR(t _NIO_udp__dtudplocalt_NIO_udp__udplocalt remotehostt_NIO_udp__remotehostt udpremotet_NIO_udp__udpremoteRst_NIO_udp__instancetnametNoneRSt_NIO_udp__nameR7(R(RuRwRyR{R~((RGRHJs       cCs|iS(N(R(Rx(R(((RGt __getudplocalYscCs|iS(N(R(Rz(R(((RGt__getremotehost]scCs|iS(N(R(R|(R(((RGt__getudpremoteascCs|iS(N(R(R(R(((RGt __getnamees(RcRdReR}RRHt_NIO_udp__getudplocalRhRwt_NIO_udp__getremotehostRyt_NIO_udp__getudpremoteR{t_NIO_udp__getnameR~(((RGRs@s         t NIO_linux_ethcBsJtZdZdZedZdZeeZdZ ee Z RS(s Create a nio_linux_eth object dynamips: the dynamips server object interface: (string) the interface on this linux host name: (string) optional name for this object icCs||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |ifdS(Nit nio_linux_ethsnio create_linux_eth %s %s( RuR(t_NIO_linux_eth__dt interfacet_NIO_linux_eth__interfaceRt_NIO_linux_eth__instanceR~RRSt_NIO_linux_eth__nameR7(R(RuRR~((RGRHrs     cCs|iS(N(R(R(R(((RGt__getinterfacescCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_linux_eth__getinterfaceRhRt_NIO_linux_eth__getnameR~(((RGRjs    t NIO_gen_ethcBsJtZdZdZedZdZeeZdZ ee Z RS(s Create a nio_gen_eth object dynamips: the dynamips server object interface: (string) the interface on this host name: (string) optional name for this object icCs||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |ifdS(Nit nio_gen_ethsnio create_gen_eth %s %s( RuR(t_NIO_gen_eth__dRt_NIO_gen_eth__interfaceRt_NIO_gen_eth__instanceR~RRSt_NIO_gen_eth__nameR7(R(RuRR~((RGRHs     cCs|iS(N(R(R(R(((RGRscCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_gen_eth__getinterfaceRhRt_NIO_gen_eth__getnameR~(((RGRs    tNIO_tapcBsJtZdZdZedZdZeeZdZ ee Z RS(s Create a nio_tap object dynamips: the dynamips server object tap: (string) the tap device name: (string) optional name for this object icCs||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |ifdS(Nitnio_tapsnio create_tap %s %s( RuR(t _NIO_tap__dttapt_NIO_tap__interfaceRt_NIO_tap__instanceR~RRSt_NIO_tap__nameR7(R(RuRR~((RGRHs     cCs|iS(N(R(R(R(((RGRscCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_tap__getinterfaceRhRt_NIO_tap__getnameR~(((RGRs    tNIO_unixcBs_tZdZdZedZdZeeZdZ ee Z dZ ee Z RS(s Create a nio_unix object dynamips: the dynamips server object unixlocal: local unix socket unixremote: remote unix socket name: (string) optional name for this object icCs||_||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |i|ifdS(Nitnio_unixsnio create_unix %s %s %s(RuR(t _NIO_unix__dt unixlocalt_NIO_unix__unixlocalt unixremotet_NIO_unix__unixremoteRt_NIO_unix__instanceR~RRSt_NIO_unix__nameR7(R(RuRRR~((RGRHs      cCs|iS(N(R(R(R(((RGt__getunixlocalscCs|iS(N(R(R(R(((RGt__getunixremotescCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_unix__getunixlocalRhRt_NIO_unix__getunixremoteRt_NIO_unix__getnameR~(((RGRs       tNIO_vdecBs_tZdZdZedZdZeeZdZ ee Z dZ ee Z RS(s Create a nio_vde object dynamips: the dynamips server object controlsock: control socket localsock: local socket name: (string) optional name for this object icCs||_||_||_ti|_tid7_|djodt |i|_ n ||_ t |id|i |i|ifdS(NiRsnio create_vde %s %s %s(RuR(t _NIO_vde__dt controlsockt_NIO_vde__controlsockt localsockt_NIO_vde__localsockRt_NIO_vde__instanceR~RRSt_NIO_vde__nameR7(R(RuRRR~((RGRHs      cCs|iS(N(R(R(R(((RGt__getcontrolsockscCs|iS(N(R(R(R(((RGt__getlocalsockscCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_vde__getcontrolsockRhRt_NIO_vde__getlocalsockRt_NIO_vde__getnameR~(((RGRs       tNIO_nullcBs5tZdZdZedZdZeeZRS(s Create a nio_nulll object dynamips: the dynamips server object name: (string) optional name for this object icCso||_ti|_tid7_|djodt|i|_n ||_t |id|idS(Nitnio_nullsnio create_null %s( RuR(t _NIO_null__dRt_NIO_null__instanceR~RRSt_NIO_null__nameR7(R(RuR~((RGRHs    cCs|iS(N(R(R(R(((RGRs( RcRdReRRRHt_NIO_null__getnameRhR~(((RGRs  t BaseAdaptercBstZdZddZdZeeddZdZeeddZdZ ee dd Z d Z ee dd Z d Z ee dd ZedZdedZedZdZRS(s The base adapter object router: A Router object slot: An int specifying the slot adapter: the adapter or network module model ports: the number of ports bindingcommand: either "slot_add_binding" or None intlist: a list of interface descriptors this adapter provides (interface, port, dynamipsport) wics: number of WIC slots on this adapter ic Csxy |i} Wntj o d} nXy=|t|i| |jotd|||ifnWn)t j otd||ifnX||_ ||_ ||_ h|_h|_|dg|_|djoax^|D]R\} }} y|i| Wn t j oh|i| dddgdddgf}ti|||dd|dS(NRiis PA-2FE-TXi(RR RHR(RR(R(RRR((RGRH9s(RcRdReRH(((RGR6s tPA_GEcBstZdZdZRS(s" A PA-GE FastEthernet adapter cCs2dddgf}ti|||dd|dS(NR isPA-GEi(RR RHR(RR(R(RRR((RGRHAs(RcRdReRH(((RGR>s tPA_4TcBstZdZdZRS(s$ A PA_4T+ 4-port serial adapter cCsVdddgdddgdddgdddgf}ti|||dd|dS(NRiiiisPA-4T+i(RR RHR(RR(R(RRR((RGRHIs6(RcRdReRH(((RGRFs tPA_8TcBstZdZdZRS(s# A PA_8T 8-port serial adapter c Csdddgdddgdddgdddgdddgdddgdddgdd d gf}ti|||d d |dS( NRiiiiiiiisPA-8Ti(RR RHR(RR(R(RRR((RGRHQsf(RcRdReRH(((RGRNs tPA_4EcBstZdZdZRS(s% A PA_4E 4-port ethernet adapter cCsVdddgdddgdddgdddgf}ti|||dd|dS(NRiiiisPA-4Ei(RR RHR(RR(R(RRR((RGRHYs6(RcRdReRH(((RGRVs tPA_8EcBstZdZdZRS(s% A PA_8E 4-port ethernet adapter c Csdddgdddgdddgdddgdddgdddgdddgdd d gf}ti|||d d |dS( NRiiiiiiiisPA-8Ei(RR RHR(RR(R(RRR((RGRHasf(RcRdReRH(((RGR^s t PA_POS_OC3cBstZdZdZRS(s A PA-POS-OC3 adapter cCs2dddgf}ti|||dd|dS(Ntpis PA-POS-OC3i(RR RHR(RR(R(RRR((RGRHis(RcRdReRH(((RGRfs tNMcBstZdZddZRS(sx A C2691/C3725/C3745/C3600/C2600/C1700 Network Module base object. Derived from the C7200 port adapter, with methods overridden where necessary router: A Router object slot: An int specifying the slot module: the network module model ports: the number of ports intlist: a list of interface descriptors this adapter provides ic Cs^|ddddddddd g jo d}nd }ti||||||||dS( Ns GT96100-FEs Leopard-2FEsCISCO2600-MB-1EsCISCO2600-MB-2EsCISCO2600-MB-1FEsCISCO2600-MB-2FEsCISCO1710-MB-1FE-1Es C1700-MB-1ETHs C1700-WIC1R ( tmoduleRRRRHR(RRRRR(R(RRRRRRR((RGRHys( (RcRdReRH(((RGRps t Leopard_2FEcBstZdZdZRS(s1 Integrated 3660 2 Port FastEthernet adapter cCs>dddgdddgf}ti|||dd|dS(NRiis Leopard-2FEi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGRs t NM_1FE_TXcBstZdZdZRS(s& A NM-1FE-TX FastEthernet adapter cCs2dddgf}ti|||dd|dS(NRis NM-1FE-TXi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR s tNM_1EcBstZdZdZRS(s A NM-1E Ethernet adapter cCs2dddgf}ti|||dd|dS(NRisNM-1Ei(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR!s tNM_4EcBstZdZdZRS(s A NM-4E Ethernet adapter cCsVdddgdddgdddgdddgf}ti|||dd|dS(NRiiiisNM-4Ei(RRRHR(RR(R(RRR((RGRHs6(RcRdReRH(((RGR"s tNM_4TcBstZdZdZRS(s A NM-4T Serial adapter cCsVdddgdddgdddgdddgf}ti|||dd|dS(NRiiiisNM-4Ti(RRRHR(RR(R(RRR((RGRHs6(RcRdReRH(((RGR#s tNM_16ESWcBstZdZdZRS(s! A NM-16ESW Ethernet adapter cCsVg}x-tddD]}|id||gqWti|||dd|dS(NiiRsNM-16ESW( RtrangetitappendRRHR(RR(R(RRR&R((RGRHs (RcRdReRH(((RGR$s tNM_CIDScBstZdZdZRS(sW IDS Network Module Note, not currently functional in Dynamips just a stub cCs2dddgf}ti|||dd|dS(NR&isNM-CIDSi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR(s tNM_NAMcBstZdZdZRS(sO NAM Module Note, not currently functional in Dynamips just a stub cCs2dddgf}ti|||dd|dS(NtanisNM-NAMi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR)s t GT96100_FEcBstZdZdZRS(sF Integrated GT96100-FE 2691/3725/3745 2 Port FastEthernet adapter c CsDdddgdddgf}ti|||dd|dddS(NRiis GT96100-FEiRi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR+s tCISCO2600_MB_1EcBstZdZdZRS(s= Integrated CISCO2600-MB-1E 2600 1 Port Ethernet adapter c Cs8dddgf}ti|||dd|dddS(NRisCISCO2600-MB-1EiRi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR,s tCISCO2600_MB_2EcBstZdZdZRS(s= Integrated CISCO2600-MB-2E 2600 1 Port Ethernet adapter c CsDdddgdddgf}ti|||dd|dddS(NRiisCISCO2600-MB-2EiR(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR-s tCISCO2600_MB_1FEcBstZdZdZRS(sB Integrated CISCO2600-MB-1FE 2600 1 Port FastEthernet adapter c Cs8dddgf}ti|||dd|dddS(NRisCISCO2600-MB-1FEiRi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR.s tCISCO2600_MB_2FEcBstZdZdZRS(sB Integrated CISCO2600-MB-2FE 2600 2 Port FastEthernet adapter c CsDdddgdddgf}ti|||dd|dddS(NRiisCISCO2600-MB-2FEiR(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR/s tCISCO1710_MB_1FE_1EcBstZdZdZRS(s: Integrated CISCO1710-MB-1FE-1E 1710 1 FE 1 E adapter c CsDdddgdddgf}ti|||dd|dddS(NRiRisCISCO1710-MB-1FE-1EiR(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR0s t C1700_MB_1ETHcBstZdZdZRS(s? Integrated C1700-MB-1ETH 1700 1 Port FastEthernet adapter cCs5dddgf}ti|||dd|ddS(NRis C1700-MB-1ETHi(RRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR1s t C1700_WIC1cBstZdZdZRS(so Fake module to provide a placeholder for slot 1 interfaces when WICs are inserted into WIC slot 1 c Cs,d}ti|||dd|dddS(Ns C1700-WIC1iRi(RRRRHR(RR(R(RRR((RGRHs(RcRdReRH(((RGR2s tRoutercBstZdZdZdeedZeedZdZedZ dZ dZ d Z d Z d Zd Zed ZdZdZeeeddZdZdZeeeddZdZdZeeeddZdZdZeeeddZdZdZeeeddZ dZ!dZ"ee"e!dd Z#d!Z$d"Z%ee%e$dd#Z&d$Z'd%Z(ee(e'dd&Z)d'Z*d(Z+ee+e*dd)Z,d*Z-d+Z.ee.e-dd,Z/d-Z0d.Z1ee1e0dd/Z2d0Z3d1Z4ee4e3dd2Z5d3Z6ee6dd4Z7d5Z8d6Z9ee9e8dd7Z:d8Z;d9Z<ee<e;dd:Z=d;Z>d<Z?ee?e>dd=Z@d>ZAd?ZBeeBeAdd@ZCdAZDeeDddBZEdCZFeeFddDZGdEZHdFZIeeIeHdd@ZJdGZKdHZLeeLeKddIZMdJZNdKZOeeOeNddLZPdMZQdNZReeReQddOZSdPZTdQZUeeUeTddRZVdSZWdTZXeeXeWddUZYdVZZdWZ[ee[eZddXZ\dYZ]ee]ddZZ^d[Z_ee_dd\Z`d]Zaeeadd^Zbd_Zceecdd`ZddaZeeeeddbZfRS(csB Creates a new Router instance dynamips: a Dynamips object model: Router model console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number iRcCst|tp tdn||_ti|_tid7_|t jo ||_ n td|djodt|i|_n ||_d|_d|_d|_d|_d|_d|_d|_d|_t|_d|_d|_d|_d|_d |_d |_t |id ||i|f|oz|ii"|i}xdtoXt$||i}|djo+||_&t |id |i|fPqX|d7}qXWn|ii'i(|dS( Nsnot a Dynammips instanceisinvalid router modeltrt0x2102tstoppediiitunknownsvm create %s %i %ssvm set_con_tcp_port %s %i()t isinstanceRuR!R0R(t _Router__dR3t_Router__instance_countt_Router__instanceRt ROUTERMODELSt_Router__modelR~RRSt _Router__namet _Router__cnfgt _Router__conft _Router__mact_Router__clockt _Router__auxt_Router__imaget_Router__idlepct_Router__exec_areatTruet _Router__mmapt_Router__statet_Router__ghost_statust_Router__sparsememt_Router__idlemaxt_Router__idlesleept_Router__confregR7t consoleFlagRVtconsolet checkconsoletconflictt_Router__consoleRMR'(R(RuRR~RORPRR((RGRH sL                          cCs:||_||_||_||_||_ ||_ dS(s0 Set the default values for this router N( tramR(t _Router__ramtnvramt_Router__nvramtdisk0t_Router__disk0tdisk1t_Router__disk1Rt _Router__npetmidplanet_Router__midplane(R(RTRVRXRZRR]((RGt setdefaults>s     cCs|dg|_dS(s@ Create the appropriate number of slots for this router N(tnumslotsRR(R(R(R`((RGt createslotsIscCs|tjotd|n|ddgjo=|idddddgjotd ||ifqnB|d gjo1|idgjotd ||ifqn|djo=|i|}|d jotd |i||fqnt t|} d |d}|djod |d}n|}y||i |i|(R(((RGtdeletescCsn|idjotd|in|idjotd|int|id|i}d|_|S(s Start this instance trunningsrouter "%s" is already runningt suspendeds;router "%s" is suspended and cannot be started. Use Resume.s vm start %sN(R(RIR0R~R7R9R>R4(R(R4((RGtstarts cCsJ|idjotd|int|id|i}d|_|S(s Stop this instance R6srouter "%s" is already stoppeds vm stop %sN(R(RIR0R~R7R9R>R4(R(R4((RGRLs  cCsn|idjotd|in|idjotd|int|id|i}d|_|S(s Suspend this instance Ros router "%s" is already suspendedR6s.router "%s" is stopped and cannot be suspendeds vm suspend %sN(R(RIR0R~R7R9R>R4(R(R4((RGtsuspends cCsn|idjotd|in|idjotd|int|id|i}d|_|S(s Resume this instance Rnsrouter "%s" is already runningR6s,router "%s" is stopped and cannot be resumeds vm resume %sN(R(RIR0R~R7R9R>R4(R(R4((RGtresumes cCs|idjotd|in|tjo!t|id|i}|Snl|t jo!t|id|i}|Sn>|t jo0t|id|i|f}||_ |SndS(s3 get, show, or set the online idlepc value R6sMrouter "%s" is stopped. Idle-pc functions can only be used on running routerssvm get_idle_pc_prop %s 0svm show_idle_pc_prop %s 0svm set_idle_pc_online %s 0 %sN(R(RIR0R~tfunctiont IDLEPROPGETR7R9R>R4t IDLEPROPSHOWt IDLEPROPSETtvalueRE(R(RsRwR4((RGtidleprops    cCst|tjp|djp |djo tdnt||i}|djo+||jotd||i fqn||_ t |id|i |i fdS(sI Set console port console: (int) TCP port of console iisinvalid console ports/console port %i is already in use by device: %ssvm set_con_tcp_port %s %iN( RQRPRAR0RQR(R9RRRR~RSR7R>(R(RPRR((RGt __setconsoles-    cCs|iS(s Returns console port N(R(RS(R(((RGt __getconsolesRPsThe router console portcCsgt|tjp|djp |djo tdn||_t|id|i|ifdS(sF Set aux port aux: (int) TCP port of the aux port iisinvalid aux portsvm set_aux_tcp_port %s %iN( RQtauxRAR0R(RCR7R9R>(R(R{((RGt__setaux s -  cCs|iS(s Returns aux port N(R(RC(R(((RGt__getauxssThe router aux portcCsyt|tjo tdntid|tip tdn||_t |i d|i |i |ifdS(sW Set the base MAC address of this router mac: (string) MAC address sinvalid MAC addresss)^([0-9a-f][0-9a-f]\:){5}[0-9a-f][0-9a-f]$s3Invalid MAC address. Format is "xx:xx:xx:xx:xx:xx".s%s set_mac_addr %s %sN( RQtmacRSR0tretsearcht IGNORECASER(RAR7R9R=R>(R(R~((RGt__setmacs   cCs|iS(s1 Returns base MAC address of this router N(R(RA(R(((RGt__getmac&ss#The base MAC address of this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(s_ Set amount of RAM allocated to this router ram: (int) amount of RAM in MB isinvalid ram sizesvm set_ram %s %iN( RQRTRAR0R(RUR7R9R>(R(RT((RGt__setram.s    cCs|iS(s< Returns the amount of RAM allocated to this router N(R(RU(R(((RGt__getram7ss*The amount of RAM allocated to this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(sU Set size of PCMCIA ATA disk0 disk0: (int) amount of disk0 in MB isinvalid disk0 sizesvm set_disk0 %s %iN( RQRXRAR0R(RYR7R9R>(R(RX((RGt __setdisk0?s    cCs|iS(s/ Returns the disk0 size on this router N(R(RY(R(((RGt __getdisk0HssThe disk0 size on this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(sU Set size of PCMCIA ATA disk1 disk1: (int) amount of disk1 in MB isinvalid disk1 sizesvm set_disk1 %s %iN( RQRZRAR0R(R[R7R9R>(R(RZ((RGt __setdisk1Ps    cCs|iS(s/ Returns the disk1 size on this router N(R(R[(R(((RGt __getdisk1YssThe disk1 size on this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(sG Set the clock property clock: (int) clock divisor is invalid clocksvm set_clock_divisor %s %iN( RQtclockRAR0R(RBR7R9R>(R(R((RGt __setclock`s    cCs|iS(s Returns clock property N(R(RB(R(((RGt __getclockiss!The clock property of this routercCsgt|tjo tdn||_|tjo d}nd}t|i d|i |fdS(s_ Set the mmap property mmap: (boolean) Map dynamic memory to a file or not s invalid mmapiisvm set_ram_mmap %s %iN( RQtmmaptboolR0R(RHRGtflagR7R9R>(R(RR((RGt __setmmapqs    cCs|iS(s Returns mmap property N(R(RH(R(((RGt __getmmap~ss The mmap property of this routerc Cs{t|tjp(|ddddddddd g jo td n||_t|id |i|i |ifd S( sI Set the npe property npe: (string) Set the NPE type snpe-100snpe-150snpe-175snpe-200snpe-225snpe-300snpe-400snpe-g1snpe-g2sinvalid NPE types%s set_npe %s %sN( RQRRSR0R(R\R7R9R=R>(R(R((RGt__setnpes ;  cCs|iS(s Returns npe property N(R(R\(R(((RGt__getnpessThe npe property of this routercCsft|tjp|ddgjo tdn||_t|id|i|i |ifdS(sX Set the midplane property midplane: (string) Set the midplane type tstdtvxrsinvalid midplane types%s set_midplane %s %sN( RQR]RSR0R(R^R7R9R=R>(R(R]((RGt __setmidplanes &  cCs|iS(s# Returns midplane property N(R(R^(R(((RGt __getmidplaness$The midplane property of this routercCsZt|tjp |djo tdn||_t|id|i|ifdS(se Set amount of nvram allocated to this router nvram: (int) amount of nvram in KB isinvalid nvram sizesvm set_nvram %s %iN( RQRVRAR0R(RWR7R9R>(R(RV((RGt __setnvrams    cCs|iS(s> Returns the amount of nvram allocated to this router N(R(RW(R(((RGt __getnvramss,The amount of nvram allocated to this routercCs-||_t|id|i|ifdS(sU Set the IOS image for this router image: path to IOS image file svm set_ios %s %sN(timageR(RDR7R9R>(R(R((RGt __setimages cCs|iS(s= Returns path of the image being used by this router N(R(RD(R(((RGt __getimagess"The IOS image file for this routercCs:|idjodSntii|iid}|S(s6 Returns just the name of the image file used t"N(R(RDRtostpathtbasenametstripR(R(R((RGt__getimagenames s.The name of the IOS image file for this routercCs-||_t|id|i|ifdS(sq Import an IOS configuration file into NVRAM cnfg: path to configuration file to be imported svm set_config %s %sN(tcnfgR(R?R7R9R>(R(R((RGt __setcnfgs cCs|iS(s< Returns path of the cnfg being used by this router N(R(R?(R(((RGt __getcnfgss/The IOS configuration file to import into NVRAMcCs-||_t|id|i|ifdS(sL Set the configuration register confreg: confreg string svm set_conf_reg %s %sN(tconfregR(RNR7R9R>(R(R((RGt __setconfregs cCs|iS(s Returns the confreg N(R(RN(R(((RGt __getconfregss)The configuration register of this routercCs0todSnt|id|i|fdS(s4 Set the config to this base64 encoded configurationNsvm push_config %s %s(tDEBUGGERR7R(R9R>tconf64(R(R((RGt__set_config_b64scCsItodSnt|id|i}|diddi}|S(s5Get the base64 encoded config from the router's nvramNsvm extract_config %sit i( RR7R(R9R>tcfR:Rt b64config(R(RR((RGt__get_config_b64s s3The configuration of this router in base64 encodingcCs-||_t|id|i|ifdS(sW Set the Idle Pointer Counter for this instance pc: idle-pc string svm set_idle_pc %s %sN(tpcR(RER7R9R>(R(R((RGt __setidlepcs cCs|iS(s$ Returns the current idlepc N(R(RE(R(((RGt __getidlepc ss2The Idle Pointer Counter assigned to this instancecCsKtp@t|id|i}|ddjo|in|SndS(s) Returns the current idlepcdrift svm show_timer_drift %s 0is100-OKN(RR7R(R9R>RItpop(R(RI((RGt__getidlepcdrifts s"The idle-pc drift valueof instancecCsKtp@t|id|i}|ddjo|in|SndS(s% Returns the current cpuinfo svm cpu_info %s 0is100-OKN(RR7R(R9R>RIR(R(RI((RGt __getcpuinfos sThe cpu info for this instancecCs-||_t|id|i|ifdS(s\ Set the idlemax value for this instance val: (integer) idlemax counter svm set_idle_max %s 0 %iN(tvalR(RLR7R9R>(R(R((RGt __setidlemax%s cCs|iS(s% Returns the current idlemax N(R(RL(R(((RGt __getidlemax,scCs-||_t|id|i|ifdS(s_ Set the idle_sleep_time for this instance val: (integer) sleep time in ms svm set_idle_sleep_time %s 0 %iN(RR(RMR7R9R>(R(R((RGt__setidlesleep3s cCs|iS(s? Returns the current idlesleep value for this instance N(R(RM(R(((RGt__getidlesleep:ss$The idle sleep time of this instancecCsgt|tjo tdn||_|tjo d}nd}t|i d|i |fdS(s Set oldidle to True to use pre 0.2.7-RC1 idlepc values. It disables direct jumps between JIT blocks state: (bool) True to use old idlepc values, false to use RC2 and later values sinvalid oldidle statusiisvm set_blk_direct_jump %s %iN( RQtstateRR0R(t_Router__oldidleRGRR7R9R>(R(RR((RGt __setoldidleBs    cCs|iS(s+ Returns the current oldidle value N(R(R(R(((RGt __getoldidleQssEnable or disable legacy idle pc value option. Setting to True disables direct jumps between JIT blocks, allowing use of pre 0.2.7-RC2 idlepc values.cCs3||_t|id|it|ifdS(sT Set the Exec Area size for this instance pc: Exec area integer svm set_exec_area %s %sN(t exec_areaR(RFR7R9R>RS(R(R((RGt__setexec_areaYs cCs|iS(s Returns the exec_area N(R(RF(R(((RGt__getexec_area`ss,The Exec Area size assigned to this instancecCs3||_t|id|it|ifdS(s Set the ghost_status of this instance status: (int) Tristate flag indicating status 0 -> Do not use IOS ghosting 1 -> This is a ghost instance 2 -> Use an existing ghost instance svm set_ghost_status %s %sN(tstatusR(RJR7R9R>RS(R(R((RGt__setghost_statushs cCs|iS(s" Returns the ghost_status N(R(RJ(R(((RGt__getghost_statusrss!The ghost status of this instancecCs3||_t|id|it|ifdS(sx Set the ghost file for this instance ghost_file: (string) ghost file name to create (or reference) svm set_ghost_file %s %sN(t ghost_fileR(t_Router__ghost_fileR7R9R>RS(R(R((RGt__setghost_filezs cCs|iS(s Returns the ghost_file N(R(R(R(((RGt__getghost_filess,The ghost file associated with this instancecCsG||_|tjo d}nd}t|id|i|fdS(s Set the sparsemem of this instance status: (int) Flag indicating enabled or disabled false -> Do not use sparsemem true -> Turn on sparsemem t1t0svm set_sparse_mem %s %sN(RR(RKRGRR7R9R>(R(RR((RGt__setsparsemems    cCs|iS(s Returns the sparsemem N(R(RK(R(((RGt__getsparsememss%The sparsemem status of this instancecCs|iS(sB Returns the dynamips server on which this device resides N(R(R9(R(((RGt __getdynamipsss/The dynamips object associated with this devicecCs|iS(s& Returns model of this router N(R(R=(R(((RGt __getmodelssThe model of this routercCs|iS(s) Returns the name of this router N(R(R>(R(((RGRssThe name of this routercCs|iS(s* Returns the state of this router N(R(RI(R(((RGt __getstatessThe state of this routercCstS(s1 Returns true if this device is a router N(RG(R(((RGt __getisrouterss'Returns true if this device is a router(gRcRdReR:RRGRHR_RaRkReRmRpRLRqRrRxt_Router__setconsolet_Router__getconsoleRhRPt_Router__setauxt_Router__getauxR{t_Router__setmact_Router__getmacR~t_Router__setramt_Router__getramRTt_Router__setdisk0t_Router__getdisk0RXt_Router__setdisk1t_Router__getdisk1RZt_Router__setclockt_Router__getclockRt_Router__setmmapt_Router__getmmapRt_Router__setnpet_Router__getnpeRt_Router__setmidplanet_Router__getmidplaneR]t_Router__setnvramt_Router__getnvramRVt_Router__setimaget_Router__getimageRt_Router__getimagenamet imagenamet_Router__setcnfgt_Router__getcnfgRt_Router__setconfregt_Router__getconfregRt_Router__set_config_b64t_Router__get_config_b64t config_b64t_Router__setidlepct_Router__getidlepctidlepct_Router__getidlepcdriftt idlepcdriftt_Router__getcpuinfotcpuinfot_Router__setidlemaxt_Router__getidlemaxtidlemaxt_Router__setidlesleept_Router__getidlesleept idlesleept_Router__setoldidlet_Router__getoldidletoldidlet_Router__setexec_areat_Router__getexec_areaRt_Router__setghost_statust_Router__getghost_statust ghost_statust_Router__setghost_filet_Router__getghost_fileRt_Router__setsparsememt_Router__getsparsememt sparsememt_Router__getdynamipsRut_Router__getmodelRt_Router__getnameR~t_Router__getstateRt_Router__getisroutertisrouter(((RGR3s 4  O                                             tC7200cBstZdZedZRS(s+ Creates a new 7200 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number cCsati||ddd|ti|dddddd d d d d ddti|ddS(NRRR~RTiRViRXi@RZiRsnpe-200R]Ri(R3RHR(RuR~R_Ra(R(RuR~((RGRHs  (RcRdReRRH(((RGRs tC2691cBstZdZedZRS(s+ Creates a new 2691 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number c Cskti||ddd|ti|dddddd d d ti|d t|d |id 't'schassis type -> sinvalid chassis typesc2600 set_chassis %s %sN( RQRRStunicodet CHASSIS2600tdebugR0R(RR7RR(R(R((RGt __setchassiss&   cCs|iS(s" Returns chassis property N(R(R(R(((RGt __getchassis$sRPs#The chassis property of this router( RcRdReRRHt_C2600__setchassist_C2600__getchassisRhR(((RGRs  ! tC3725cBstZdZedZRS(s+ Creates a new 3725 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number c Cskti||ddd|ti|dddddd d d ti|d t|d |id sinvalid chassis type(RuR(t _C3600__dRt_C3600__chassisR~t _C3600__nameR3RHR_RaRRSR0(R(RuRR~((RGRH^s$         cCst|ttgjp|dddgjoItdtdt|dtdtt|tdn||_t|i d |i |ifd S( sU Set the chassis property chassis: (string) Set the chassis type RRRs&Invalid chassis passed to __setchassiss chassis -> 'Rschassis type -> sinvalid chassis typesc3600 set_chassis %s %sN( RQRRSRRR0R(R%R7R$R&(R(R((RGRxs/   cCs|iS(s" Returns chassis property N(R(R%(R(((RGRsRPs#The chassis property of this routercCszyt|}Wntj otdnX|ddjo tdn||_t|id|i|ifdS(sP Set the iomem property iomem: (string) Set the iomem value s&invalid iomem type, must be an integeriisiomem must be a multiple of 5sc3600 set_iomem %s %sN( RAtiomemt ValueErrorR0R(t _C3600__iomemR7R$R&(R(R'((RGt __setiomems  cCs|iS(s Returns iomem property N(R(R)(R(((RGt __getiomemssThe iomem size of this router( RcRdReRRHt_C3600__setchassist_C3600__getchassisRhRt_C3600__setiomemt_C3600__getiomemR'(((RGR#Vs    tC1700cBshtZdZedZdZdZeeeddZdZ dZ ee e ddZ RS( s+ Creates a new 1700 Router instance dynamips: a Dynamips object console (optional): TCP port that attaches to this router's console. Defaults to TCP 2000 + the instance number name (optional): An optional name. Defaults to the instance number c Cs#||_||_||_ti||ddd|ti |dddddd d d ||_|d d gjoti |d nti |dhdt <dt <dt <dt <d t <d t <}|||d |id <|d d gjot|d|id 'Rschassis type -> sinvalid chassis typesc1700 set_chassis %s %sN( RQRRSRt CHASSIS1700RR0R(R2R7R1R3(R(R((RGRs&   cCs|iS(s" Returns chassis property N(R(R2(R(((RGRsRPs#The chassis property of this routercCszyt|}Wntj otdnX|ddjo tdn||_t|id|i|ifdS(sP Set the iomem property iomem: (string) Set the iomem value s&invalid iomem type, must be an integeriisiomem must be a multiple of 5sc1700 set_iomem %s %sN( RAR'R(R0R(t _C1700__iomemR7R1R3(R(R'((RGR*s  cCs|iS(s Returns iomem property N(R(R6(R(((RGR+ssThe iomem size of this router( RcRdReRRHt_C1700__setchassist_C1700__getchassisRhRt_C1700__setiomemt_C1700__getiomemR'(((RGR0s  &  R0cBstZRS(N(RcRd(((RGR0stDynamipsErrorHandledcBstZRS(N(RcRd(((RGR;sRDcBstZRS(N(RcRd(((RGRDstDynamipsWarningcBstZRS(N(RcRd(((RGR<sRcBstZdZdZeedZdZedZdZ e e ddZ dZ e e dd Z d Ze edd Zd Ze edd ZRS(so Creates a new Ethernet bridge instance dynamips: a Dynamips object name: An optional name icCs||_ti|_tid7_|djodt|i|_ n ||_ g|_ |ot |id|i ndS(Nitbsnio_bridge create ( RuR(t _Bridge__dRt_Bridge__instance_countt_Bridge__instanceR~RRSt _Bridge__namet _Bridge__niostcreateR7(R(RuR~RC((RGRH s     cCsdS(sC Delete this Frame Relay switch instance from the back end N((R(((RGRmscCs|djo.y |iSWq;tj otdq;Xnt|}|tjp4|t jp'|t jp|t jp |t jo$t |id|i|ifn|ii|dS(sB Adds an NIO to this bridge nio: A nio object s"port does not exist on this switchsnio_bridge add_nio %s %sN(RRR(RBRR0RQRRsRRRRR7R>RAR~R'(R(RR((RGR s   A$cCsdS(s& Returns the adapter property RN((R(((RGR3sRPsThe port adaptercCs|iS(s# Returns the name property N(R(RA(R(((RGR:ssThe device namecCs|iS(sB Returns the dynamips server on which this device resides N(R(R>(R(((RGRBss/The dynamips object associated with this devicecCstS(s1 Returns true if this device is a router N(tFalse(R(((RGRIss'Returns true if this device is a router(RcRdReR?RRGRHRmRt_Bridge__getadapterRhRt_Bridge__getnameR~t_Bridge__getdynamipsRut_Bridge__getisrouterR(((RGRs       RcBstZdZdZeedZdZdZdZ dZ edZ dZ d Z ee d d Zd Zeed d ZdZeed dZdZeed dZRS(sr Creates a new Frame Relay switch instance dynamips: a Dynamips object name: An optional name icCs||_ti|_tid7_|djodt|i|_ n ||_ h|_ h|_ |ot |id|i ndS(NiRs frsw create (RuR(t_FRSW__dRt_FRSW__instance_countt_FRSW__instanceR~RRSt _FRSW__namet _FRSW__dlcist _FRSW__niosRCR7(R(RuR~RC((RGRHXs      cCsdS(sC Delete this Frame Relay switch instance from the back end N((R(((RGRmgscCst|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdny|i|i }Wnt j otdnXy|i|i }Wnt j otdnXt |id|i||||f|ii|o|i|i|n|g|i|<|ii|o|i|i|n|g|i|= 0s"invalid port2. Must be an int >= 0s"invalid dlci1. Must be an int >= 0s#port1 does not exist on this switchs#port2 does not exist on this switchsfrsw create_vc %s %s %i %s %iN(RQtport1RAR0tport2tdlci1tdlci2R(RR~tnio1Rtnio2R7RIRLRMthas_keyR'(R(RORQRPRRRTRS((RGtmapms0        &c Cs?ttttd|id|d|d|d|d|dS(s Connect this switch to a port on another device remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter object on a router remoteport: A port on the remote adapter RRRRRRN( RRRRR(RIRRRR(R(RRRR((RGR-s  cCs t||S(sG Returns a boolean indicating if this port is connected or not N(RR(R/(R(R/((RGRscCsi|djoKy|i|SWqXtj o)tdt|d|idqXXn||i|= 0s"invalid port2. Must be an int >= 0s!invalid vpi1. Must be an int >= 0s!invalid vpi2. Must be an int >= 0s#port1 does not exist on this switchs#port2 does not exist on this switchsatmsw create_vpc %s %s %i %s %iN(RQRORAR0RPtvpi1tvpi2R(RR~RSRRTR7R\R_R`RUR'(R(RORbRPRcRTRS((RGtmapvp s0        &c Cst|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdnt|tjp |djo tdny|i |i }Wnt j otdnXy|i |i }Wnt j otd nXt|id |i||||||f|ii|o|i|i|n|g|i|<|ii|o|i|i|n|g|i|= 0s"invalid port2. Must be an int >= 0s!invalid vpi1. Must be an int >= 0s!invalid vpi2. Must be an int >= 0s!invalid vci1. Must be an int >= 0s!invalid vci2. Must be an int >= 0s#port1 does not exist on this switchs#port2 does not exist on this switchs%atmsw create_vcc %s %s %i %i %s %i %iN(RQRORAR0RPRbRctvci1tvci2R(RR~RSRRTR7R\R_R`RUR'( R(RORbReRPRcRfRTRS((RGtmapvc5 s8            ,c Cs?ttttd|id|d|d|d|d|dS(s Connect this switch to a port on another device remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter object on a router remoteport: A port on the remote adapter RRRRRRN( RRRRR(R\RRRR(R(RRRR((RGR-a s  cCs t||S(sG Returns a boolean indicating if this port is connected or not N(RR(R/(R(R/((RGRq scCsi|djoKy|i|SWqXtj o)tdt|d|idqXXn||i|= 0s!invalid vlan. Must be an int >= 0s#port1 does not exist on this switchtaccesstdot1qsinvalid porttypes ethsw set_s_port RN(RQR/RAR0tvlanR(RR~RtporttypeRR7RmRpRS(R(R/RuRtR((RGtset_port s    cCst|id|iS(s. Show this switch's mac address table sethsw show_mac_addr_table N(R7R(RmRp(R(((RGtshow_mac scCst|id|iS(s/ Clear this switch's mac address table sethsw clear_mac_addr_table N(R7R(RmRp(R(((RGt clear_mac sc Cs?ttttd|id|d|d|d|d|dS(s Connect this switch to a port on another device remoteserver: the dynamips object that hosts the remote adapter remoteadapter: An adapter object on a router remoteport: A port on the remote adapter RRRRRRN( RRRRR(RmRRRR(R(RRRR((RGR- s  cCs t||S(sG Returns a boolean indicating if this port is connected or not N(RR(R/(R(R/((RGR scCs_|d joKy|i|SWqXtj o)tdt|d|idqXXnt |}|t jp4|t jp'|t jp|tjp |tjo$t|id|i|ifn td||i|<|d joo|i}|djo|djo tdnt|id |d |id |id t|nd S( s Returns the NETIO object for this port or if nio is set, sets the NETIO for this port port: a port on this adapter nio: optional NETIO object to assign porttype: either access or dot1q sEthernet switchport s on device "s" is defined, but not usedsethsw add_nio %s %ssinvalid NIO typeRrRssinvalid porttypes ethsw set_s_port RN(RRR(RqR/RR<RSR~RQRRsRRRRR7RmRpR0RuRRt(R(R/RRuRtR((RGR s  + A$     cCsdS(s& Returns the adapter property RN((R(((RGR- sRPsThe port adaptercCs|iS(s# Returns the name property N(R(Rp(R(((RGR5 ssThe device namecCs|iS(sB Returns the dynamips server on which this device resides N(R(Rm(R(((RGR= ss/The dynamips object associated with this devicecCstS(s1 Returns true if this device is a router N(RD(R(((RGRD ss'Returns true if this device is a router(RcRdReRnRRGRHRmRvRwRxR-RRt_ETHSW__getadapterRhRt_ETHSW__getnameR~t_ETHSW__getdynamipsRut_ETHSW__getisrouterR(((RGR s$           cCs3d}g}td|idt|id|tpy|i i |i dWn/t j o#d|iGHdGHdGHt nXg}d }xGto?y |i i|}||7}WnSt j o%}d |iGH|GHdGHt n$d |iGHdGHdGHt nXy|d djownWn/tj o#d |iGHdGHdGHt nX||id 7}|d d jo|ind }|d d djoPnti|d ot|d qqWt|djod|iGHtdntdt||Snd SdS(s Sends raw commands to the Dynamips process dynamips: a dynamips object command: raw commands returns results as a list is sending to t:s -> s s1Error: lost communication with dynamips server %ss<Dynamips may have crashed. Check the Dynamips server output.s Exiting...R s6Error: timed out communicating with dynamips server %ss4Error: could not communicate with dynamips server %sis is100-is@Error: no data returned from dynamips server %s. Server crashed?sno datas returned -> N(tSIZEt resultsetRRuR.RSR/tcommandR,RtsendallRR+R;tdatatbufRGtrecvtchunktmessageR9R:Rterror_reRR0Rf(RuRRRRRRR~((RGR7O sf*           c Cs|i|ijod} d} n|i} |i} |i}|id|_tdt|i|i}|id|_tdt|it ||| |}t ||| |} |id|d|t|to|id| n|id|d| dS(s Generalized connect function called by all connect methods. Connects a souce interface / port to a destination interface / port src_dynamips: the dynamips object that hosts the source connection src_adapter: the source adapter src_port: the source port dst_dynamips: the dynamips object that hosts the destination connection dst_adapter: the destination adatper dst_port: the destination port (set to none if the destination is a bridge) s 127.0.0.1issource NIO udp is now: sdest NIO udp is now: R/RN(RR.Rtsrc_iptdst_ipRYtsrc_udpRRStdst_udpRstsrc_niotdst_nioRRRR8RRR( RRRRRRRRRRRR((RGR s$      cCsd }d}d}d}||jo||jod Snz||jo||jod SnX||jo||jod Sn6||jo||jod Sntd ||fd S( s Check to see if a given adapter can be connected to another adapter i1: interface type 1 i2: interface type 2 RRR tnR&RRRNsattempt to connect %s to %s(RRR RR&(t ethernetstserialstatmstpossti1ti2R0(RRRRRR((RGR s cCs4y|i|i}Wntj o tSnXtS(sC Returns a boolean indicating if this port is connected or not N(tobjRR/R~RSRRDRG(RR/RS((RGR s  cCsSxL|iD]A}y |i}Wntj o q nX||jo|Sq q WdS(sk Returns the device that uses the console port Returns None if no device has that console port N(RuRMtdeviceRPtcon2RR(RPRuRR((RGRQ s    cCs(|tjp |tjo |andS(s@ If true, don't actually send any commands to the back end. N(RRGRDR,(R((RGtnosend scCs(|tjp |tjo |andS(s If true, print out debugs N(RRGRDtDEBUG(R((RGtsetdebug& scCstodt|GHndS(s' Print string if debugging is true s DEBUG: N(RRSR^(R^((RGR/ st__main__s,/opt/ios-images/c1710-k9o3sy-mz.124-16.imaget localhosti s/tmpRR~tr1i({RetsysRRtbase64R%R+R&R'R8tMAJORtMINORtSUBtRCVERRCRERDR,RRtRuRvtcompileRtlast_retDBGPHideChildrent NameErrorRRGR<t DEVICETUPLER5Rt CHASSIS3600tMB2CHASSIS1700tMB2CHASSIS2600tGENERIC_1700_NMStGENERIC_2600_NMStGENERIC_3600_NMStGENERIC_3700_NMStGENERIC_7200_PAStIO_7200RcRRRR%RtobjectR!RsRRRRRRRR R RRRRRRRRRRRRRR R!R"R#R$R(R)R+R,R-R.R/R0R1R2R3RRRR!R"R#R0t ExceptionR0R;RDR<RRRRR7RRRRQRRRRctIMAGERRKRkRRRTRkRp(iRRRRR7RR8RtRRRR.RR R+R!R"RRR+RR2RRQR'RR;R-RRRRR<RR RR$RR5RR,R%RRR&RRRRuRRRR0RRRRRDRR!RRvRR1RCRRR3RR#RRRRR<RR0RR RER!RcRR/RRRR)R0RRRR"RRRR#RsRRRR(RRR((RGt?s($ K$< ` !6 (   *#$      =KVL W , 1         # validate.py # A Validator object # Copyright (C) 2005 Michael Foord, Mark Andrews, Nicola Larosa # E-mail: fuzzyman AT voidspace DOT org DOT uk # mark AT la-la DOT com # nico AT tekNico DOT net # This software is licensed under the terms of the BSD license. # http://www.voidspace.org.uk/python/license.shtml # Basically you're free to copy, modify, distribute and relicense it, # So long as you keep a copy of the license with it. # Scripts maintained at http://www.voidspace.org.uk/python/index.shtml # For information about bugfixes, updates and support, please join the # ConfigObj mailing list: # http://lists.sourceforge.net/lists/listinfo/configobj-develop # Comments, suggestions and bug reports welcome. """ The Validator object is used to check that supplied values conform to a specification. The value can be supplied as a string - e.g. from a config file. In this case the check will also *convert* the value to the required type. This allows you to add validation as a transparent layer to access data stored as strings. The validation checks that the data is correct *and* converts it to the expected type. Some standard checks are provided for basic data types. Additional checks are easy to write. They can be provided when the ``Validator`` is instantiated or added afterwards. The standard functions work with the following basic data types : * integers * floats * booleans * strings * ip_addr plus lists of these datatypes Adding additional checks is done through coding simple functions. The full set of standard checks are : * 'integer': matches integer values (including negative) Takes optional 'min' and 'max' arguments : :: integer() integer(3, 9) # any value from 3 to 9 integer(min=0) # any positive value integer(max=9) * 'float': matches float values Has the same parameters as the integer check. * 'boolean': matches boolean values - ``True`` or ``False`` Acceptable string values for True are : true, on, yes, 1 Acceptable string values for False are : false, off, no, 0 Any other value raises an error. * 'ip_addr': matches an Internet Protocol address, v.4, represented by a dotted-quad string, i.e. '1.2.3.4'. * 'string': matches any string. Takes optional keyword args 'min' and 'max' to specify min and max lengths of the string. * 'list': matches any list. Takes optional keyword args 'min', and 'max' to specify min and max sizes of the list. * 'int_list': Matches a list of integers. Takes the same arguments as list. * 'float_list': Matches a list of floats. Takes the same arguments as list. * 'bool_list': Matches a list of boolean values. Takes the same arguments as list. * 'ip_addr_list': Matches a list of IP addresses. Takes the same arguments as list. * 'string_list': Matches a list of strings. Takes the same arguments as list. * 'mixed_list': Matches a list with different types in specific positions. List size must match the number of arguments. Each position can be one of : 'integer', 'float', 'ip_addr', 'string', 'boolean' So to specify a list with two strings followed by two integers, you write the check as : :: mixed_list('string', 'string', 'integer', 'integer') * 'pass': This check matches everything ! It never fails and the value is unchanged. It is also the default if no check is specified. * 'option': This check matches any from a list of options. You specify this check with : :: option('option 1', 'option 2', 'option 3') You can supply a default value (returned if no value is supplied) using the default keyword argument. You specify a list argument for default using a list constructor syntax in the check : :: checkname(arg1, arg2, default=list('val 1', 'val 2', 'val 3')) A badly formatted set of arguments will raise a ``VdtParamError``. """ __docformat__ = "restructuredtext en" __version__ = '0.2.1' __revision__ = '$Id: validate.py 123 2005-09-08 08:54:28Z fuzzyman $' __all__ = ( '__version__', 'dottedQuadToNum', 'numToDottedQuad', 'ValidateError', 'VdtUnknownCheckError', 'VdtParamError', 'VdtTypeError', 'VdtValueError', 'VdtValueTooSmallError', 'VdtValueTooBigError', 'VdtValueTooShortError', 'VdtValueTooLongError', 'VdtMissingValue', 'Validator', 'is_integer', 'is_float', 'is_bool', 'is_list', 'is_ip_addr', 'is_string', 'is_int_list', 'is_bool_list', 'is_float_list', 'is_string_list', 'is_ip_addr_list', 'is_mixed_list', 'is_option', '__docformat__', ) import sys INTP_VER = sys.version_info[:2] if INTP_VER < (2, 2): raise RuntimeError("Python v.2.2 or later needed") import re StringTypes = (str, unicode) _list_arg = re.compile(r''' (?: ([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*list\( ( (?: \s* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted ) \s*,\s* )* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted )? # last one ) \) ) ''', re.VERBOSE) # two groups _list_members = re.compile(r''' ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s=][^,=]*?) # unquoted ) (?: (?:\s*,\s*)|(?:\s*$) # comma ) ''', re.VERBOSE) # one group _paramstring = r''' (?: ( (?: [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*list\( (?: \s* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted ) \s*,\s* )* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted )? # last one \) )| (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s=][^,=]*?)| # unquoted (?: # keyword argument [a-zA-Z_][a-zA-Z0-9_]*\s*=\s* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s=][^,=]*?) # unquoted ) ) ) ) (?: (?:\s*,\s*)|(?:\s*$) # comma ) ) ''' _matchstring = '^%s*' % _paramstring # Python pre 2.2.1 doesn't have bool try: bool except NameError: def bool(val): """Simple boolean equivalent function. """ if val: return 1 else: return 0 def dottedQuadToNum(ip): """ Convert decimal dotted quad string to long integer >>> dottedQuadToNum('1 ') 1L >>> dottedQuadToNum(' 1.2') 16777218L >>> dottedQuadToNum(' 1.2.3 ') 16908291L >>> dottedQuadToNum('1.2.3.4') 16909060L >>> dottedQuadToNum('1.2.3. 4') Traceback (most recent call last): ValueError: Not a good dotted-quad IP: 1.2.3. 4 >>> dottedQuadToNum('255.255.255.255') 4294967295L >>> dottedQuadToNum('255.255.255.256') Traceback (most recent call last): ValueError: Not a good dotted-quad IP: 255.255.255.256 """ # import here to avoid it when ip_addr values are not used import socket, struct try: return struct.unpack('!L', socket.inet_aton(ip.strip()))[0] except socket.error: # bug in inet_aton, corrected in Python 2.3 if ip.strip() == '255.255.255.255': return 0xFFFFFFFFL else: raise ValueError('Not a good dotted-quad IP: %s' % ip) return def numToDottedQuad(num): """ Convert long int to dotted quad string >>> numToDottedQuad(-1L) Traceback (most recent call last): ValueError: Not a good numeric IP: -1 >>> numToDottedQuad(1L) '0.0.0.1' >>> numToDottedQuad(16777218L) '1.0.0.2' >>> numToDottedQuad(16908291L) '1.2.0.3' >>> numToDottedQuad(16909060L) '1.2.3.4' >>> numToDottedQuad(4294967295L) '255.255.255.255' >>> numToDottedQuad(4294967296L) Traceback (most recent call last): ValueError: Not a good numeric IP: 4294967296 """ # import here to avoid it when ip_addr values are not used import socket, struct # no need to intercept here, 4294967295L is fine try: return socket.inet_ntoa( struct.pack('!L', long(num))) except (socket.error, struct.error, OverflowError): raise ValueError('Not a good numeric IP: %s' % num) class ValidateError(Exception): """ This error indicates that the check failed. It can be the base class for more specific errors. Any check function that fails ought to raise this error. (or a subclass) >>> raise ValidateError Traceback (most recent call last): ValidateError """ class VdtMissingValue(ValidateError): """No value was supplied to a check that needed one.""" class VdtUnknownCheckError(ValidateError): """An unknown check function was requested""" def __init__(self, value): """ >>> raise VdtUnknownCheckError('yoda') Traceback (most recent call last): VdtUnknownCheckError: the check "yoda" is unknown. """ ValidateError.__init__( self, 'the check "%s" is unknown.' % value) class VdtParamError(SyntaxError): """An incorrect parameter was passed""" def __init__(self, name, value): """ >>> raise VdtParamError('yoda', 'jedi') Traceback (most recent call last): VdtParamError: passed an incorrect value "jedi" for parameter "yoda". """ SyntaxError.__init__( self, 'passed an incorrect value "%s" for parameter "%s".' % ( value, name)) class VdtTypeError(ValidateError): """The value supplied was of the wrong type""" def __init__(self, value): """ >>> raise VdtTypeError('jedi') Traceback (most recent call last): VdtTypeError: the value "jedi" is of the wrong type. """ ValidateError.__init__( self, 'the value "%s" is of the wrong type.' % value) class VdtValueError(ValidateError): """ The value supplied was of the correct type, but was not an allowed value. """ def __init__(self, value): """ >>> raise VdtValueError('jedi') Traceback (most recent call last): VdtValueError: the value "jedi" is unacceptable. """ ValidateError.__init__( self, 'the value "%s" is unacceptable.' % value) class VdtValueTooSmallError(VdtValueError): """The value supplied was of the correct type, but was too small.""" def __init__(self, value): """ >>> raise VdtValueTooSmallError('0') Traceback (most recent call last): VdtValueTooSmallError: the value "0" is too small. """ ValidateError.__init__( self, 'the value "%s" is too small.' % value) class VdtValueTooBigError(VdtValueError): """The value supplied was of the correct type, but was too big.""" def __init__(self, value): """ >>> raise VdtValueTooBigError('1') Traceback (most recent call last): VdtValueTooBigError: the value "1" is too big. """ ValidateError.__init__( self, 'the value "%s" is too big.' % value) class VdtValueTooShortError(VdtValueError): """The value supplied was of the correct type, but was too short.""" def __init__(self, value): """ >>> raise VdtValueTooShortError('jed') Traceback (most recent call last): VdtValueTooShortError: the value "jed" is too short. """ ValidateError.__init__( self, 'the value "%s" is too short.' % (value,)) class VdtValueTooLongError(VdtValueError): """The value supplied was of the correct type, but was too long.""" def __init__(self, value): """ >>> raise VdtValueTooLongError('jedie') Traceback (most recent call last): VdtValueTooLongError: the value "jedie" is too long. """ ValidateError.__init__( self, 'the value "%s" is too long.' % (value,)) class Validator(object): """ Validator is an object that allows you to register a set of 'checks'. These checks take input and test that it conforms to the check. This can also involve converting the value from a string into the correct datatype. The ``check`` method takes an input string which configures which check is to be used and applies that check to a supplied value. An example input string would be: 'int_range(param1, param2)' You would then provide something like: >>> def int_range_check(value, min, max): ... # turn min and max from strings to integers ... min = int(min) ... max = int(max) ... # check that value is of the correct type. ... # possible valid inputs are integers or strings ... # that represent integers ... if not isinstance(value, (int, long, StringTypes)): ... raise VdtTypeError(value) ... elif isinstance(value, StringTypes): ... # if we are given a string ... # attempt to convert to an integer ... try: ... value = int(value) ... except ValueError: ... raise VdtValueError(value) ... # check the value is between our constraints ... if not min <= value: ... raise VdtValueTooSmallError(value) ... if not value <= max: ... raise VdtValueTooBigError(value) ... return value >>> fdict = {'int_range': int_range_check} >>> vtr1 = Validator(fdict) >>> vtr1.check('int_range(20, 40)', '30') 30 >>> vtr1.check('int_range(20, 40)', '60') Traceback (most recent call last): VdtValueTooBigError: the value "60" is too big. New functions can be added with : :: >>> vtr2 = Validator() >>> vtr2.functions['int_range'] = int_range_check Or by passing in a dictionary of functions when Validator is instantiated. Your functions *can* use keyword arguments, but the first argument should always be 'value'. If the function doesn't take additional arguments, the parentheses are optional in the check. It can be written with either of : :: keyword = function_name keyword = function_name() The first program to utilise Validator() was Michael Foord's ConfigObj, an alternative to ConfigParser which supports lists and can validate a config file using a config schema. For more details on using Validator with ConfigObj see: http://www.voidspace.org.uk/python/configobj.html """ # this regex does the initial parsing of the checks _func_re = re.compile(r'(.+?)\((.*)\)') # this regex takes apart keyword arguments _key_arg = re.compile(r'^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$') # this regex finds keyword=list(....) type values _list_arg = _list_arg # this regex takes individual values out of lists - in one pass _list_members = _list_members # These regexes check a set of arguments for validity # and then pull the members out _paramfinder = re.compile(_paramstring, re.VERBOSE) _matchfinder = re.compile(_matchstring, re.VERBOSE) def __init__(self, functions=None): """ >>> vtri = Validator() """ self.functions = { '': self._pass, 'integer': is_integer, 'float': is_float, 'boolean': is_bool, 'ip_addr': is_ip_addr, 'string': is_string, 'list': is_list, 'int_list': is_int_list, 'float_list': is_float_list, 'bool_list': is_bool_list, 'ip_addr_list': is_ip_addr_list, 'string_list': is_string_list, 'mixed_list': is_mixed_list, 'pass': self._pass, 'option': is_option, } if functions is not None: self.functions.update(functions) # tekNico: for use by ConfigObj self.baseErrorClass = ValidateError def check(self, check, value, missing=False): """ Usage: check(check, value) Arguments: check: string representing check to apply (including arguments) value: object to be checked Returns value, converted to correct type if necessary If the check fails, raises a ``ValidateError`` subclass. >>> vtor.check('yoda', '') Traceback (most recent call last): VdtUnknownCheckError: the check "yoda" is unknown. >>> vtor.check('yoda()', '') Traceback (most recent call last): VdtUnknownCheckError: the check "yoda" is unknown. """ fun_match = self._func_re.match(check) if fun_match: fun_name = fun_match.group(1) arg_string = fun_match.group(2) arg_match = self._matchfinder.match(arg_string) if arg_match is None: # Bad syntax raise VdtParamError fun_args = [] fun_kwargs = {} # pull out args of group 2 for arg in self._paramfinder.findall(arg_string): # args may need whitespace removing (before removing quotes) arg = arg.strip() listmatch = self._list_arg.match(arg) if listmatch: key, val = self._list_handle(listmatch) fun_kwargs[key] = val continue keymatch = self._key_arg.match(arg) if keymatch: val = self._unquote(keymatch.group(2)) fun_kwargs[keymatch.group(1)] = val continue # fun_args.append(self._unquote(arg)) else: # allows for function names without (args) (fun_name, fun_args, fun_kwargs) = (check, (), {}) # if missing: try: value = fun_kwargs['default'] except KeyError: raise VdtMissingValue if value == 'None': value = None if value is None: return None # tekNico: default must be deleted if the value is specified too, # otherwise the check function will get a spurious "default" keyword arg try: del fun_kwargs['default'] except KeyError: pass try: fun = self.functions[fun_name] except KeyError: raise VdtUnknownCheckError(fun_name) else: ## print fun_args ## print fun_kwargs return fun(value, *fun_args, **fun_kwargs) def _unquote(self, val): """Unquote a value if necessary.""" if (len(val) > 2) and (val[0] in ("'", '"')) and (val[0] == val[-1]): val = val[1:-1] return val def _list_handle(self, listmatch): """Take apart a ``keyword=list('val, 'val')`` type string.""" out = [] name = listmatch.group(1) args = listmatch.group(2) for arg in self._list_members.findall(args): out.append(self._unquote(arg)) return name, out def _pass(self, value): """ Dummy check that always passes >>> vtor.check('', 0) 0 >>> vtor.check('', '0') '0' """ return value def _is_num_param(names, values, to_float=False): """ Return numbers from inputs or raise VdtParamError. Lets ``None`` pass through. Pass in keyword argument ``to_float=True`` to use float for the conversion rather than int. >>> _is_num_param(('', ''), (0, 1.0)) [0, 1] >>> _is_num_param(('', ''), (0, 1.0), to_float=True) [0.0, 1.0] >>> _is_num_param(('a'), ('a')) Traceback (most recent call last): VdtParamError: passed an incorrect value "a" for parameter "a". """ fun = to_float and float or int out_params = [] for (name, val) in zip(names, values): if val is None: out_params.append(val) elif isinstance(val, (int, long, float, StringTypes)): try: out_params.append(fun(val)) except ValueError, e: raise VdtParamError(name, val) else: raise VdtParamError(name, val) return out_params # built in checks # you can override these by setting the appropriate name # in Validator.functions # note: if the params are specified wrongly in your input string, # you will also raise errors. def is_integer(value, min=None, max=None): """ A check that tests that a given value is an integer (int, or long) and optionally, between bounds. A negative value is accepted, while a float will fail. If the value is a string, then the conversion is done - if possible. Otherwise a VdtError is raised. >>> vtor.check('integer', '-1') -1 >>> vtor.check('integer', '0') 0 >>> vtor.check('integer', 9) 9 >>> vtor.check('integer', 'a') Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. >>> vtor.check('integer', '2.2') Traceback (most recent call last): VdtTypeError: the value "2.2" is of the wrong type. >>> vtor.check('integer(10)', '20') 20 >>> vtor.check('integer(max=20)', '15') 15 >>> vtor.check('integer(10)', '9') Traceback (most recent call last): VdtValueTooSmallError: the value "9" is too small. >>> vtor.check('integer(10)', 9) Traceback (most recent call last): VdtValueTooSmallError: the value "9" is too small. >>> vtor.check('integer(max=20)', '35') Traceback (most recent call last): VdtValueTooBigError: the value "35" is too big. >>> vtor.check('integer(max=20)', 35) Traceback (most recent call last): VdtValueTooBigError: the value "35" is too big. >>> vtor.check('integer(0, 9)', False) 0 """ # print value, type(value) (min_val, max_val) = _is_num_param(('min', 'max'), (min, max)) if not isinstance(value, (int, long, StringTypes)): raise VdtTypeError(value) if isinstance(value, StringTypes): # if it's a string - does it represent an integer ? try: value = int(value) except ValueError: raise VdtTypeError(value) if (min_val is not None) and (value < min_val): raise VdtValueTooSmallError(value) if (max_val is not None) and (value > max_val): raise VdtValueTooBigError(value) return value def is_float(value, min=None, max=None): """ A check that tests that a given value is a float (an integer will be accepted), and optionally - that it is between bounds. If the value is a string, then the conversion is done - if possible. Otherwise a VdtError is raised. This can accept negative values. >>> vtor.check('float', '2') 2.0 From now on we multiply the value to avoid comparing decimals >>> vtor.check('float', '-6.8') * 10 -68.0 >>> vtor.check('float', '12.2') * 10 122.0 >>> vtor.check('float', 8.4) * 10 84.0 >>> vtor.check('float', 'a') Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. >>> vtor.check('float(10.1)', '10.2') * 10 102.0 >>> vtor.check('float(max=20.2)', '15.1') * 10 151.0 >>> vtor.check('float(10.0)', '9.0') Traceback (most recent call last): VdtValueTooSmallError: the value "9.0" is too small. >>> vtor.check('float(max=20.0)', '35.0') Traceback (most recent call last): VdtValueTooBigError: the value "35.0" is too big. """ (min_val, max_val) = _is_num_param( ('min', 'max'), (min, max), to_float=True) if not isinstance(value, (int, long, float, StringTypes)): raise VdtTypeError(value) if not isinstance(value, float): # if it's a string - does it represent a float ? try: value = float(value) except ValueError: raise VdtTypeError(value) if (min_val is not None) and (value < min_val): raise VdtValueTooSmallError(value) if (max_val is not None) and (value > max_val): raise VdtValueTooBigError(value) return value bool_dict = { True: True, 'on': True, '1': True, 'true': True, 'yes': True, False: False, 'off': False, '0': False, 'false': False, 'no': False, } def is_bool(value): """ Check if the value represents a boolean. >>> vtor.check('boolean', 0) 0 >>> vtor.check('boolean', False) 0 >>> vtor.check('boolean', '0') 0 >>> vtor.check('boolean', 'off') 0 >>> vtor.check('boolean', 'false') 0 >>> vtor.check('boolean', 'no') 0 >>> vtor.check('boolean', 'nO') 0 >>> vtor.check('boolean', 'NO') 0 >>> vtor.check('boolean', 1) 1 >>> vtor.check('boolean', True) 1 >>> vtor.check('boolean', '1') 1 >>> vtor.check('boolean', 'on') 1 >>> vtor.check('boolean', 'true') 1 >>> vtor.check('boolean', 'yes') 1 >>> vtor.check('boolean', 'Yes') 1 >>> vtor.check('boolean', 'YES') 1 >>> vtor.check('boolean', '') Traceback (most recent call last): VdtTypeError: the value "" is of the wrong type. >>> vtor.check('boolean', 'up') Traceback (most recent call last): VdtTypeError: the value "up" is of the wrong type. """ if isinstance(value, StringTypes): try: return bool_dict[value.lower()] except KeyError: raise VdtTypeError(value) # we do an equality test rather than an identity test # this ensures Python 2.2 compatibilty # and allows 0 and 1 to represent True and False if value == False: return False elif value == True: return True else: raise VdtTypeError(value) def is_ip_addr(value): """ Check that the supplied value is an Internet Protocol address, v.4, represented by a dotted-quad string, i.e. '1.2.3.4'. >>> vtor.check('ip_addr', '1 ') '1' >>> vtor.check('ip_addr', ' 1.2') '1.2' >>> vtor.check('ip_addr', ' 1.2.3 ') '1.2.3' >>> vtor.check('ip_addr', '1.2.3.4') '1.2.3.4' >>> vtor.check('ip_addr', '0.0.0.0') '0.0.0.0' >>> vtor.check('ip_addr', '255.255.255.255') '255.255.255.255' >>> vtor.check('ip_addr', '255.255.255.256') Traceback (most recent call last): VdtValueError: the value "255.255.255.256" is unacceptable. >>> vtor.check('ip_addr', '1.2.3.4.5') Traceback (most recent call last): VdtValueError: the value "1.2.3.4.5" is unacceptable. >>> vtor.check('ip_addr', '1.2.3. 4') Traceback (most recent call last): VdtValueError: the value "1.2.3. 4" is unacceptable. >>> vtor.check('ip_addr', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. """ if not isinstance(value, StringTypes): raise VdtTypeError(value) value = value.strip() try: dottedQuadToNum(value) except ValueError: raise VdtValueError(value) return value def is_list(value, min=None, max=None): """ Check that the value is a list of values. You can optionally specify the minimum and maximum number of members. It does no check on list members. >>> vtor.check('list', ()) () >>> vtor.check('list', []) [] >>> vtor.check('list', (1, 2)) (1, 2) >>> vtor.check('list', [1, 2]) [1, 2] >>> vtor.check('list', '12') '12' >>> vtor.check('list(3)', (1, 2)) Traceback (most recent call last): VdtValueTooShortError: the value "(1, 2)" is too short. >>> vtor.check('list(max=5)', (1, 2, 3, 4, 5, 6)) Traceback (most recent call last): VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long. >>> vtor.check('list(min=3, max=5)', (1, 2, 3, 4)) (1, 2, 3, 4) >>> vtor.check('list', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. """ (min_len, max_len) = _is_num_param(('min', 'max'), (min, max)) try: num_members = len(value) except TypeError: raise VdtTypeError(value) if min_len is not None and num_members < min_len: raise VdtValueTooShortError(value) if max_len is not None and num_members > max_len: raise VdtValueTooLongError(value) return value def is_string(value, min=None, max=None): """ Check that the supplied value is a string. You can optionally specify the minimum and maximum number of members. >>> vtor.check('string', '0') '0' >>> vtor.check('string', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. >>> vtor.check('string(2)', '12') '12' >>> vtor.check('string(2)', '1') Traceback (most recent call last): VdtValueTooShortError: the value "1" is too short. >>> vtor.check('string(min=2, max=3)', '123') '123' >>> vtor.check('string(min=2, max=3)', '1234') Traceback (most recent call last): VdtValueTooLongError: the value "1234" is too long. """ if not isinstance(value, StringTypes): raise VdtTypeError(value) return is_list(value, min, max) def is_int_list(value, min=None, max=None): """ Check that the value is a list of integers. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is an integer. >>> vtor.check('int_list', ()) [] >>> vtor.check('int_list', []) [] >>> vtor.check('int_list', (1, 2)) [1, 2] >>> vtor.check('int_list', [1, 2]) [1, 2] >>> vtor.check('int_list', [1, 'a']) Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. """ return [is_integer(mem) for mem in is_list(value, min, max)] def is_bool_list(value, min=None, max=None): """ Check that the value is a list of booleans. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is a boolean. >>> vtor.check('bool_list', ()) [] >>> vtor.check('bool_list', []) [] >>> check_res = vtor.check('bool_list', (True, False)) >>> check_res == [True, False] 1 >>> check_res = vtor.check('bool_list', [True, False]) >>> check_res == [True, False] 1 >>> vtor.check('bool_list', [True, 'a']) Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. """ return [is_bool(mem) for mem in is_list(value, min, max)] def is_float_list(value, min=None, max=None): """ Check that the value is a list of floats. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is a float. >>> vtor.check('float_list', ()) [] >>> vtor.check('float_list', []) [] >>> vtor.check('float_list', (1, 2.0)) [1.0, 2.0] >>> vtor.check('float_list', [1, 2.0]) [1.0, 2.0] >>> vtor.check('float_list', [1, 'a']) Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. """ return [is_float(mem) for mem in is_list(value, min, max)] def is_string_list(value, min=None, max=None): """ Check that the value is a list of strings. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is a string. >>> vtor.check('string_list', ()) [] >>> vtor.check('string_list', []) [] >>> vtor.check('string_list', ('a', 'b')) ['a', 'b'] >>> vtor.check('string_list', ['a', 1]) Traceback (most recent call last): VdtTypeError: the value "1" is of the wrong type. """ return [is_string(mem) for mem in is_list(value, min, max)] def is_ip_addr_list(value, min=None, max=None): """ Check that the value is a list of IP addresses. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is an IP address. >>> vtor.check('ip_addr_list', ()) [] >>> vtor.check('ip_addr_list', []) [] >>> vtor.check('ip_addr_list', ('1.2.3.4', '5.6.7.8')) ['1.2.3.4', '5.6.7.8'] >>> vtor.check('ip_addr_list', ['a']) Traceback (most recent call last): VdtValueError: the value "a" is unacceptable. """ return [is_ip_addr(mem) for mem in is_list(value, min, max)] fun_dict = { 'integer': is_integer, 'float': is_float, 'ip_addr': is_ip_addr, 'string': is_string, 'boolean': is_bool, } def is_mixed_list(value, *args): """ Check that the value is a list. Allow specifying the type of each member. Work on lists of specific lengths. You specify each member as a positional argument specifying type Each type should be one of the following strings : 'integer', 'float', 'ip_addr', 'string', 'boolean' So you can specify a list of two strings, followed by two integers as : mixed_list('string', 'string', 'integer', 'integer') The length of the list must match the number of positional arguments you supply. >>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')" >>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True)) >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 1 >>> check_res = vtor.check(mix_str, ('1', '2.0', '1.2.3.4', 'a', 'True')) >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 1 >>> vtor.check(mix_str, ('b', 2.0, '1.2.3.4', 'a', True)) Traceback (most recent call last): VdtTypeError: the value "b" is of the wrong type. >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a')) Traceback (most recent call last): VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short. >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b')) Traceback (most recent call last): VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long. >>> vtor.check(mix_str, 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. This test requires an elaborate setup, because of a change in error string output from the interpreter between Python 2.2 and 2.3 . >>> res_seq = ( ... 'passed an incorrect value "', ... 'yoda', ... '" for parameter "mixed_list".', ... ) >>> if INTP_VER == (2, 2): ... res_str = "".join(res_seq) ... else: ... res_str = "'".join(res_seq) >>> try: ... vtor.check('mixed_list("yoda")', ('a')) ... except VdtParamError, err: ... str(err) == res_str 1 """ try: length = len(value) except TypeError: raise VdtTypeError(value) if length < len(args): raise VdtValueTooShortError(value) elif length > len(args): raise VdtValueTooLongError(value) try: return [fun_dict[arg](val) for arg, val in zip(args, value)] except KeyError, e: raise VdtParamError('mixed_list', e) def is_option(value, *options): """ This check matches the value to any of a set of options. >>> vtor.check('option("yoda", "jedi")', 'yoda') 'yoda' >>> vtor.check('option("yoda", "jedi")', 'jed') Traceback (most recent call last): VdtValueError: the value "jed" is unacceptable. >>> vtor.check('option("yoda", "jedi")', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. """ if not isinstance(value, StringTypes): raise VdtTypeError(value) if not value in options: raise VdtValueError(value) return value def _test(value, *args, **keywargs): """ A function that exists for test purposes. >>> checks = [ ... '3, 6, min=1, max=3, test=list(a, b, c)', ... '3', ... '3, 6', ... '3,', ... 'min=1, test="a b c"', ... 'min=5, test="a, b, c"', ... 'min=1, max=3, test="a, b, c"', ... 'min=-100, test=-99', ... 'min=1, max=3', ... '3, 6, test="36"', ... '3, 6, test="a, b, c"', ... '3, max=3, test=list("a", "b", "c")', ... '''3, max=3, test=list("'a'", 'b', "x=(c)")''', ... "test='x=fish(3)'", ... ] >>> v = Validator({'test': _test}) >>> for entry in checks: ... print v.check(('test(%s)' % entry), 3) (3, ('3', '6'), {'test': ['a', 'b', 'c'], 'max': '3', 'min': '1'}) (3, ('3',), {}) (3, ('3', '6'), {}) (3, ('3',), {}) (3, (), {'test': 'a b c', 'min': '1'}) (3, (), {'test': 'a, b, c', 'min': '5'}) (3, (), {'test': 'a, b, c', 'max': '3', 'min': '1'}) (3, (), {'test': '-99', 'min': '-100'}) (3, (), {'max': '3', 'min': '1'}) (3, ('3', '6'), {'test': '36'}) (3, ('3', '6'), {'test': 'a, b, c'}) (3, ('3',), {'test': ['a', 'b', 'c'], 'max': '3'}) (3, ('3',), {'test': ["'a'", 'b', 'x=(c)'], 'max': '3'}) (3, (), {'test': 'x=fish(3)'}) """ return (value, args, keywargs) if __name__ == '__main__': # run the code tests in doctest format import doctest m = sys.modules.get('__main__') globs = m.__dict__.copy() globs.update({ 'INTP_VER': INTP_VER, 'vtor': Validator(), }) doctest.testmod(m, globs=globs) """ TODO ==== Consider which parts of the regex stuff to put back in Can we implement a timestamp datatype ? (check DateUtil module) ISSUES ====== If we could pull tuples out of arguments, it would be easier to specify arguments for 'mixed_lists'. CHANGELOG ========= 2005/12/16 ---------- Fixed bug so we can handle keyword argument values with commas. We now use a list constructor for passing list values to keyword arguments (including ``default``) : :: default=list("val", "val", "val") Added the ``_test`` test. {sm;:-)} 0.2.1 2005/12/12 ---------- Moved a function call outside a try...except block. 2005/08/25 ---------- Most errors now prefixed ``Vdt`` ``VdtParamError`` no longer derives from ``VdtError`` Finalised as version 0.2.0 2005/08/21 ---------- By Nicola Larosa Removed the "length" argument for lists and strings, and related tests 2005/08/16 ---------- By Nicola Larosa Deleted the "none" and "multiple" types and checks Added the None value for all types in Validation.check 2005/08/14 ---------- By Michael Foord Removed timestamp. By Nicola Larosa Fixed bug in Validator.check: when a value that has a default is also specified in the config file, the default must be deleted from fun_kwargs anyway, otherwise the check function will get a spurious "default" keyword argument Added "ip_addr_list" check 2005/08/13 ---------- By Nicola Larosa Updated comments at top 2005/08/11 ---------- By Nicola Larosa Added test for interpreter version: raises RuntimeError if earlier than 2.2 Fixed last is_mixed_list test to work on Python 2.2 too 2005/08/10 ---------- By Nicola Larosa Restored Python2.2 compatibility by avoiding usage of dict.pop 2005/08/07 ---------- By Nicola Larosa Adjusted doctests for Python 2.2.3 compatibility, one test still fails for trivial reasons (string output delimiters) 2005/08/05 ---------- By Michael Foord Added __version__, __all__, and __docformat__ Replaced ``basestring`` with ``types.StringTypes`` 2005/07/28 ---------- By Nicola Larosa Reformatted final docstring in ReST format, indented it for easier folding 2005/07/20 ---------- By Nicola Larosa Added an 'ip_addr' IPv4 address value check, with tests Updated the tests for mixed_list to include IP addresses Changed all references to value "tests" into value "checks", including the main Validator method, and all code tests 2005/07/19 ---------- By Nicola Larosa Added even more code tests Refined the mixed_list check 2005/07/18 ---------- By Nicola Larosa Introduced more VdtValueError subclasses Collapsed the ``_function_test`` and ``_function_parse`` methods into the ``check`` one Refined the value checks, using the new VdtValueError subclasses Changed "is_string" to use "is_list" Added many more code tests Changed the "bool" value type to "boolean" Some more code cleanup 2005/07/17 ---------- By Nicola Larosa Code tests converted to doctest format and placed in the respective docstrings, so they are automatically checked, and easier to update Changed local vars "min" and "max" to "min_len", "max_len", "min_val" and "max_val", to avoid shadowing the builtin functions (but left function parameters alone) Uniformed value check function names to is_* convention ``date`` type name changed to ``timestamp`` Avoided some code duplication in list check functions Some more code cleanup 2005/07/09 ---------- Recoded the standard functions 2005/07/08 ---------- Improved paramfinder regex Ripped out all the regex stuff, checks, and the example functions (to be replaced !) 2005/07/06 ---------- By Nicola Larosa Code cleanup """ m fFc@sdZdZdZdZdUZd kZeid! ZedVjoed"nd k Z e e fZ e i d#e iZe i d$e iZd%Zd&eZyeWnej od'ZnXd(Zd)Zdefd*YZdefd+YZdefd,YZd efd-YZd efd.YZd efd/YZd efd0YZd efd1YZ defd2YZ!defd3YZ"de#fd4YZ$e%d5Z&d d d6Z(d d d7Z)he*e*<d8e*<d9e*<d:e*<d;e*<e%e%<d<e%<d=e%<d>e%<d?e%i?Z@e@iAhdRe<dSe$<e:iBe=dTe@nd S(WsF The Validator object is used to check that supplied values conform to a specification. The value can be supplied as a string - e.g. from a config file. In this case the check will also *convert* the value to the required type. This allows you to add validation as a transparent layer to access data stored as strings. The validation checks that the data is correct *and* converts it to the expected type. Some standard checks are provided for basic data types. Additional checks are easy to write. They can be provided when the ``Validator`` is instantiated or added afterwards. The standard functions work with the following basic data types : * integers * floats * booleans * strings * ip_addr plus lists of these datatypes Adding additional checks is done through coding simple functions. The full set of standard checks are : * 'integer': matches integer values (including negative) Takes optional 'min' and 'max' arguments : :: integer() integer(3, 9) # any value from 3 to 9 integer(min=0) # any positive value integer(max=9) * 'float': matches float values Has the same parameters as the integer check. * 'boolean': matches boolean values - ``True`` or ``False`` Acceptable string values for True are : true, on, yes, 1 Acceptable string values for False are : false, off, no, 0 Any other value raises an error. * 'ip_addr': matches an Internet Protocol address, v.4, represented by a dotted-quad string, i.e. '1.2.3.4'. * 'string': matches any string. Takes optional keyword args 'min' and 'max' to specify min and max lengths of the string. * 'list': matches any list. Takes optional keyword args 'min', and 'max' to specify min and max sizes of the list. * 'int_list': Matches a list of integers. Takes the same arguments as list. * 'float_list': Matches a list of floats. Takes the same arguments as list. * 'bool_list': Matches a list of boolean values. Takes the same arguments as list. * 'ip_addr_list': Matches a list of IP addresses. Takes the same arguments as list. * 'string_list': Matches a list of strings. Takes the same arguments as list. * 'mixed_list': Matches a list with different types in specific positions. List size must match the number of arguments. Each position can be one of : 'integer', 'float', 'ip_addr', 'string', 'boolean' So to specify a list with two strings followed by two integers, you write the check as : :: mixed_list('string', 'string', 'integer', 'integer') * 'pass': This check matches everything ! It never fails and the value is unchanged. It is also the default if no check is specified. * 'option': This check matches any from a list of options. You specify this check with : :: option('option 1', 'option 2', 'option 3') You can supply a default value (returned if no value is supplied) using the default keyword argument. You specify a list argument for default using a list constructor syntax in the check : :: checkname(arg1, arg2, default=list('val 1', 'val 2', 'val 3')) A badly formatted set of arguments will raise a ``VdtParamError``. srestructuredtext ens0.2.1s4$Id: validate.py 123 2005-09-08 08:54:28Z fuzzyman $t __version__tdottedQuadToNumtnumToDottedQuadt ValidateErrortVdtUnknownCheckErrort VdtParamErrort VdtTypeErrort VdtValueErrortVdtValueTooSmallErrortVdtValueTooBigErrortVdtValueTooShortErrortVdtValueTooLongErrortVdtMissingValuet Validatort is_integertis_floattis_booltis_listt is_ip_addrt is_stringt is_int_listt is_bool_listt is_float_listtis_string_listtis_ip_addr_listt is_mixed_listt is_optiont __docformat__NisPython v.2.2 or later neededs (?: ([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*list\( ( (?: \s* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted ) \s*,\s* )* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted )? # last one ) \) ) s ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s=][^,=]*?) # unquoted ) (?: (?:\s*,\s*)|(?:\s*$) # comma ) s (?: ( (?: [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*list\( (?: \s* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted ) \s*,\s* )* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted )? # last one \) )| (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s=][^,=]*?)| # unquoted (?: # keyword argument [a-zA-Z_][a-zA-Z0-9_]*\s*=\s* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s=][^,=]*?) # unquoted ) ) ) ) (?: (?:\s*,\s*)|(?:\s*$) # comma ) ) s^%s*cCs|odSndSdS(s$Simple boolean equivalent function. iiN(tval(R((t/usr/bin/validate.pytboolscCsdk}dk}y'|id|i|idSWnA|ij o2|idjodSq}td|nXdS(s= Convert decimal dotted quad string to long integer >>> dottedQuadToNum('1 ') 1L >>> dottedQuadToNum(' 1.2') 16777218L >>> dottedQuadToNum(' 1.2.3 ') 16908291L >>> dottedQuadToNum('1.2.3.4') 16909060L >>> dottedQuadToNum('1.2.3. 4') Traceback (most recent call last): ValueError: Not a good dotted-quad IP: 1.2.3. 4 >>> dottedQuadToNum('255.255.255.255') 4294967295L >>> dottedQuadToNum('255.255.255.256') Traceback (most recent call last): ValueError: Not a good dotted-quad IP: 255.255.255.256 Ns!Lis255.255.255.255lsNot a good dotted-quad IP: %s(tsockettstructtunpackt inet_atontiptstripterrort ValueError(R#RR ((RRs cCsndk}dk}y#|i|idt|SWn2|i|itfj otd|nXdS(s Convert long int to dotted quad string >>> numToDottedQuad(-1L) Traceback (most recent call last): ValueError: Not a good numeric IP: -1 >>> numToDottedQuad(1L) '0.0.0.1' >>> numToDottedQuad(16777218L) '1.0.0.2' >>> numToDottedQuad(16908291L) '1.2.0.3' >>> numToDottedQuad(16909060L) '1.2.3.4' >>> numToDottedQuad(4294967295L) '255.255.255.255' >>> numToDottedQuad(4294967296L) Traceback (most recent call last): ValueError: Not a good numeric IP: 4294967296 Ns!LsNot a good numeric IP: %s( RR t inet_ntoatpacktlongtnumR%t OverflowErrorR&(R*RR ((RR)s #cBstZdZRS(s This error indicates that the check failed. It can be the base class for more specific errors. Any check function that fails ought to raise this error. (or a subclass) >>> raise ValidateError Traceback (most recent call last): ValidateError (t__name__t __module__t__doc__(((RRIs cBstZdZRS(s1No value was supplied to a check that needed one.(R,R-R.(((RR Vs cBstZdZdZRS(s'An unknown check function was requestedcCsti|d|dS(s >>> raise VdtUnknownCheckError('yoda') Traceback (most recent call last): VdtUnknownCheckError: the check "yoda" is unknown. sthe check "%s" is unknown.N(Rt__init__tselftvalue(R0R1((RR/\s (R,R-R.R/(((RRYs cBstZdZdZRS(s!An incorrect parameter was passedcCsti|d||fdS(s >>> raise VdtParamError('yoda', 'jedi') Traceback (most recent call last): VdtParamError: passed an incorrect value "jedi" for parameter "yoda". s2passed an incorrect value "%s" for parameter "%s".N(t SyntaxErrorR/R0R1tname(R0R3R1((RR/is (R,R-R.R/(((RRfs cBstZdZdZRS(s(The value supplied was of the wrong typecCsti|d|dS(s >>> raise VdtTypeError('jedi') Traceback (most recent call last): VdtTypeError: the value "jedi" is of the wrong type. s$the value "%s" is of the wrong type.N(RR/R0R1(R0R1((RR/ws (R,R-R.R/(((RRts cBstZdZdZRS(sS The value supplied was of the correct type, but was not an allowed value. cCsti|d|dS(s >>> raise VdtValueError('jedi') Traceback (most recent call last): VdtValueError: the value "jedi" is unacceptable. sthe value "%s" is unacceptable.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RRs cBstZdZdZRS(s>The value supplied was of the correct type, but was too small.cCsti|d|dS(s >>> raise VdtValueTooSmallError('0') Traceback (most recent call last): VdtValueTooSmallError: the value "0" is too small. sthe value "%s" is too small.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RRs cBstZdZdZRS(s<The value supplied was of the correct type, but was too big.cCsti|d|dS(s >>> raise VdtValueTooBigError('1') Traceback (most recent call last): VdtValueTooBigError: the value "1" is too big. sthe value "%s" is too big.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RR s cBstZdZdZRS(s>The value supplied was of the correct type, but was too short.cCsti|d|fdS(s >>> raise VdtValueTooShortError('jed') Traceback (most recent call last): VdtValueTooShortError: the value "jed" is too short. sthe value "%s" is too short.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RR s cBstZdZdZRS(s=The value supplied was of the correct type, but was too long.cCsti|d|fdS(s >>> raise VdtValueTooLongError('jedie') Traceback (most recent call last): VdtValueTooLongError: the value "jedie" is too long. sthe value "%s" is too long.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RR s cBstZdZeidZeidZeZeZeie ei Z eie ei Z edZedZdZdZdZRS(s: Validator is an object that allows you to register a set of 'checks'. These checks take input and test that it conforms to the check. This can also involve converting the value from a string into the correct datatype. The ``check`` method takes an input string which configures which check is to be used and applies that check to a supplied value. An example input string would be: 'int_range(param1, param2)' You would then provide something like: >>> def int_range_check(value, min, max): ... # turn min and max from strings to integers ... min = int(min) ... max = int(max) ... # check that value is of the correct type. ... # possible valid inputs are integers or strings ... # that represent integers ... if not isinstance(value, (int, long, StringTypes)): ... raise VdtTypeError(value) ... elif isinstance(value, StringTypes): ... # if we are given a string ... # attempt to convert to an integer ... try: ... value = int(value) ... except ValueError: ... raise VdtValueError(value) ... # check the value is between our constraints ... if not min <= value: ... raise VdtValueTooSmallError(value) ... if not value <= max: ... raise VdtValueTooBigError(value) ... return value >>> fdict = {'int_range': int_range_check} >>> vtr1 = Validator(fdict) >>> vtr1.check('int_range(20, 40)', '30') 30 >>> vtr1.check('int_range(20, 40)', '60') Traceback (most recent call last): VdtValueTooBigError: the value "60" is too big. New functions can be added with : :: >>> vtr2 = Validator() >>> vtr2.functions['int_range'] = int_range_check Or by passing in a dictionary of functions when Validator is instantiated. Your functions *can* use keyword arguments, but the first argument should always be 'value'. If the function doesn't take additional arguments, the parentheses are optional in the check. It can be written with either of : :: keyword = function_name keyword = function_name() The first program to utilise Validator() was Michael Foord's ConfigObj, an alternative to ConfigParser which supports lists and can validate a config file using a config schema. For more details on using Validator with ConfigObj see: http://www.voidspace.org.uk/python/configobj.html s (.+?)\((.*)\)s%^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$cCshd|i<dt<dt<dt<dt<dt<dt<dt<d t <d t <d t <d t <d t <d|i<dt<|_|dj o|ii|nt|_dS(s( >>> vtri = Validator() ttintegertfloattbooleantip_addrtstringtlisttint_listt float_listt bool_listt ip_addr_listt string_listt mixed_listtpasstoptionN(R0t_passRRRRRRRRRRRRRt functionstNonetupdateRtbaseErrorClass(R0RD((RR/s  cCs|ii|}|o |id} |id}|ii|}|djo t ng}h}x|ii|D]} | i} |ii| }|o&|i|\} }||| >> vtor.check('yoda', '') Traceback (most recent call last): VdtUnknownCheckError: the check "yoda" is unknown. >>> vtor.check('yoda()', '') Traceback (most recent call last): VdtUnknownCheckError: the check "yoda" is unknown. iitdefaultREN("R0t_func_retmatchtcheckt fun_matchtgrouptfun_namet arg_stringt _matchfindert arg_matchRERtfun_argst fun_kwargst _paramfindertfindalltargR$t _list_argt listmatcht _list_handletkeyRt_key_argtkeymatcht_unquotetappendtmissingR1tKeyErrorR RDtfunR(R0RKR1R_RRRRORQRLRNR\RZRVRaRXRS((RRK9sV        cCsNt|djo7|ddjo&|d|djo|dd!}n|S( sUnquote a value if necessary.iit't"iiN(RbRc(tlenR(R0R((RR]s9cCsag}|id}|id}x0|ii|D]}|i |i |q7W||fS(s7Take apart a ``keyword=list('val, 'val')`` type string.iiN( toutRXRMR3targsR0t _list_membersRURVR^R](R0RXR3RfRVRe((RRYscCs|S(s Dummy check that always passes >>> vtor.check('', 0) 0 >>> vtor.check('', '0') '0' N(R1(R0R1((RRCs(R,R-R.tretcompileRIR[RWRgt _paramstringtVERBOSERTt _matchstringRPRER/tFalseRKR]RYRC(((RR s F  H  cCs|otpt}g}xt||D]\}}|djo|i |q*t |tt ttfoBy|i ||Wqtj o}t||qXq*t||q*W|S(s Return numbers from inputs or raise VdtParamError. Lets ``None`` pass through. Pass in keyword argument ``to_float=True`` to use float for the conversion rather than int. >>> _is_num_param(('', ''), (0, 1.0)) [0, 1] >>> _is_num_param(('', ''), (0, 1.0), to_float=True) [0.0, 1.0] >>> _is_num_param(('a'), ('a')) Traceback (most recent call last): VdtParamError: passed an incorrect value "a" for parameter "a". N(tto_floatR6tintRat out_paramstziptnamestvaluesR3RRER^t isinstanceR)t StringTypesR&teR(RrRsRnRvR3RRpRa((Rt _is_num_params  cCstd||f\}}t|ttt fpt |nt|t o6yt|}Wqt j ot |qXn|dj o||jot |n|dj o||jot|n|S(sH A check that tests that a given value is an integer (int, or long) and optionally, between bounds. A negative value is accepted, while a float will fail. If the value is a string, then the conversion is done - if possible. Otherwise a VdtError is raised. >>> vtor.check('integer', '-1') -1 >>> vtor.check('integer', '0') 0 >>> vtor.check('integer', 9) 9 >>> vtor.check('integer', 'a') Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. >>> vtor.check('integer', '2.2') Traceback (most recent call last): VdtTypeError: the value "2.2" is of the wrong type. >>> vtor.check('integer(10)', '20') 20 >>> vtor.check('integer(max=20)', '15') 15 >>> vtor.check('integer(10)', '9') Traceback (most recent call last): VdtValueTooSmallError: the value "9" is too small. >>> vtor.check('integer(10)', 9) Traceback (most recent call last): VdtValueTooSmallError: the value "9" is too small. >>> vtor.check('integer(max=20)', '35') Traceback (most recent call last): VdtValueTooBigError: the value "35" is too big. >>> vtor.check('integer(max=20)', 35) Traceback (most recent call last): VdtValueTooBigError: the value "35" is too big. >>> vtor.check('integer(0, 9)', False) 0 tmintmaxN(sminsmax(RwRxRytmin_valtmax_valRtR1RoR)RuRR&RERR (R1RxRyRzR{((RRs'cCstd||fdt\}}t|tt t t fpt |nt|t p6yt |}Wqt j ot |qXn|dj o||jot|n|dj o||jot|n|S(s< A check that tests that a given value is a float (an integer will be accepted), and optionally - that it is between bounds. If the value is a string, then the conversion is done - if possible. Otherwise a VdtError is raised. This can accept negative values. >>> vtor.check('float', '2') 2.0 From now on we multiply the value to avoid comparing decimals >>> vtor.check('float', '-6.8') * 10 -68.0 >>> vtor.check('float', '12.2') * 10 122.0 >>> vtor.check('float', 8.4) * 10 84.0 >>> vtor.check('float', 'a') Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. >>> vtor.check('float(10.1)', '10.2') * 10 102.0 >>> vtor.check('float(max=20.2)', '15.1') * 10 151.0 >>> vtor.check('float(10.0)', '9.0') Traceback (most recent call last): VdtValueTooSmallError: the value "9.0" is too small. >>> vtor.check('float(max=20.0)', '35.0') Traceback (most recent call last): VdtValueTooBigError: the value "35.0" is too big. RxRyRnN(sminsmax(RwRxRytTrueRzR{RtR1RoR)R6RuRR&RERR (R1RxRyRzR{((RRs"!tont1ttruetyestofft0tfalsetnocCst|to8yt|iSWqHtj ot|qHXn|tjotSn"|tjotSn t|dS(s Check if the value represents a boolean. >>> vtor.check('boolean', 0) 0 >>> vtor.check('boolean', False) 0 >>> vtor.check('boolean', '0') 0 >>> vtor.check('boolean', 'off') 0 >>> vtor.check('boolean', 'false') 0 >>> vtor.check('boolean', 'no') 0 >>> vtor.check('boolean', 'nO') 0 >>> vtor.check('boolean', 'NO') 0 >>> vtor.check('boolean', 1) 1 >>> vtor.check('boolean', True) 1 >>> vtor.check('boolean', '1') 1 >>> vtor.check('boolean', 'on') 1 >>> vtor.check('boolean', 'true') 1 >>> vtor.check('boolean', 'yes') 1 >>> vtor.check('boolean', 'Yes') 1 >>> vtor.check('boolean', 'YES') 1 >>> vtor.check('boolean', '') Traceback (most recent call last): VdtTypeError: the value "" is of the wrong type. >>> vtor.check('boolean', 'up') Traceback (most recent call last): VdtTypeError: the value "up" is of the wrong type. N( RtR1Rut bool_dicttlowerR`RRmR|(R1((RR0s+  cCs`t|tpt|n|i}yt|Wntj ot|nX|S(s Check that the supplied value is an Internet Protocol address, v.4, represented by a dotted-quad string, i.e. '1.2.3.4'. >>> vtor.check('ip_addr', '1 ') '1' >>> vtor.check('ip_addr', ' 1.2') '1.2' >>> vtor.check('ip_addr', ' 1.2.3 ') '1.2.3' >>> vtor.check('ip_addr', '1.2.3.4') '1.2.3.4' >>> vtor.check('ip_addr', '0.0.0.0') '0.0.0.0' >>> vtor.check('ip_addr', '255.255.255.255') '255.255.255.255' >>> vtor.check('ip_addr', '255.255.255.256') Traceback (most recent call last): VdtValueError: the value "255.255.255.256" is unacceptable. >>> vtor.check('ip_addr', '1.2.3.4.5') Traceback (most recent call last): VdtValueError: the value "1.2.3.4.5" is unacceptable. >>> vtor.check('ip_addr', '1.2.3. 4') Traceback (most recent call last): VdtValueError: the value "1.2.3. 4" is unacceptable. >>> vtor.check('ip_addr', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. N(RtR1RuRR$RR&R(R1((RRls cCstd||f\}}yt|}Wntj ot |nX|dj o||jot |n|dj o||jot |n|S(ss Check that the value is a list of values. You can optionally specify the minimum and maximum number of members. It does no check on list members. >>> vtor.check('list', ()) () >>> vtor.check('list', []) [] >>> vtor.check('list', (1, 2)) (1, 2) >>> vtor.check('list', [1, 2]) [1, 2] >>> vtor.check('list', '12') '12' >>> vtor.check('list(3)', (1, 2)) Traceback (most recent call last): VdtValueTooShortError: the value "(1, 2)" is too short. >>> vtor.check('list(max=5)', (1, 2, 3, 4, 5, 6)) Traceback (most recent call last): VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long. >>> vtor.check('list(min=3, max=5)', (1, 2, 3, 4)) (1, 2, 3, 4) >>> vtor.check('list', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. RxRyN(sminsmax( RwRxRytmin_lentmax_lenRdR1t num_memberst TypeErrorRRER R (R1RxRyRRR((RRscCs0t|tpt|nt|||S(s Check that the supplied value is a string. You can optionally specify the minimum and maximum number of members. >>> vtor.check('string', '0') '0' >>> vtor.check('string', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. >>> vtor.check('string(2)', '12') '12' >>> vtor.check('string(2)', '1') Traceback (most recent call last): VdtValueTooShortError: the value "1" is too short. >>> vtor.check('string(min=2, max=3)', '123') '123' >>> vtor.check('string(min=2, max=3)', '1234') Traceback (most recent call last): VdtValueTooLongError: the value "1234" is too long. N(RtR1RuRRRxRy(R1RxRy((RRscCs1g}t|||D]}|t|q~S(s Check that the value is a list of integers. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is an integer. >>> vtor.check('int_list', ()) [] >>> vtor.check('int_list', []) [] >>> vtor.check('int_list', (1, 2)) [1, 2] >>> vtor.check('int_list', [1, 2]) [1, 2] >>> vtor.check('int_list', [1, 'a']) Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. N(t_[1]RR1RxRytmemR(R1RxRyRR((RRscCs1g}t|||D]}|t|q~S(sl Check that the value is a list of booleans. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is a boolean. >>> vtor.check('bool_list', ()) [] >>> vtor.check('bool_list', []) [] >>> check_res = vtor.check('bool_list', (True, False)) >>> check_res == [True, False] 1 >>> check_res = vtor.check('bool_list', [True, False]) >>> check_res == [True, False] 1 >>> vtor.check('bool_list', [True, 'a']) Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. N(RRR1RxRyRR(R1RxRyRR((RRscCs1g}t|||D]}|t|q~S(s Check that the value is a list of floats. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is a float. >>> vtor.check('float_list', ()) [] >>> vtor.check('float_list', []) [] >>> vtor.check('float_list', (1, 2.0)) [1.0, 2.0] >>> vtor.check('float_list', [1, 2.0]) [1.0, 2.0] >>> vtor.check('float_list', [1, 'a']) Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. N(RRR1RxRyRR(R1RxRyRR((RRscCs1g}t|||D]}|t|q~S(s Check that the value is a list of strings. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is a string. >>> vtor.check('string_list', ()) [] >>> vtor.check('string_list', []) [] >>> vtor.check('string_list', ('a', 'b')) ['a', 'b'] >>> vtor.check('string_list', ['a', 1]) Traceback (most recent call last): VdtTypeError: the value "1" is of the wrong type. N(RRR1RxRyRR(R1RxRyRR((RRscCs1g}t|||D]}|t|q~S(s Check that the value is a list of IP addresses. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is an IP address. >>> vtor.check('ip_addr_list', ()) [] >>> vtor.check('ip_addr_list', []) [] >>> vtor.check('ip_addr_list', ('1.2.3.4', '5.6.7.8')) ['1.2.3.4', '5.6.7.8'] >>> vtor.check('ip_addr_list', ['a']) Traceback (most recent call last): VdtValueError: the value "a" is unacceptable. N(RRR1RxRyRR(R1RxRyRR((RR.sR5R6R8R9R7cGsyt|}Wntj ot|nX|t|jot|n$|t|jot|ny<g}t ||D]\}}|t ||q~SWn$t j o}td|nXdS(s3 Check that the value is a list. Allow specifying the type of each member. Work on lists of specific lengths. You specify each member as a positional argument specifying type Each type should be one of the following strings : 'integer', 'float', 'ip_addr', 'string', 'boolean' So you can specify a list of two strings, followed by two integers as : mixed_list('string', 'string', 'integer', 'integer') The length of the list must match the number of positional arguments you supply. >>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')" >>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True)) >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 1 >>> check_res = vtor.check(mix_str, ('1', '2.0', '1.2.3.4', 'a', 'True')) >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 1 >>> vtor.check(mix_str, ('b', 2.0, '1.2.3.4', 'a', True)) Traceback (most recent call last): VdtTypeError: the value "b" is of the wrong type. >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a')) Traceback (most recent call last): VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short. >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b')) Traceback (most recent call last): VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long. >>> vtor.check(mix_str, 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. This test requires an elaborate setup, because of a change in error string output from the interpreter between Python 2.2 and 2.3 . >>> res_seq = ( ... 'passed an incorrect value "', ... 'yoda', ... '" for parameter "mixed_list".', ... ) >>> if INTP_VER == (2, 2): ... res_str = "".join(res_seq) ... else: ... res_str = "'".join(res_seq) >>> try: ... vtor.check('mixed_list("yoda")', ('a')) ... except VdtParamError, err: ... str(err) == res_str 1 R@N(RdR1tlengthRRRfR R RRqRVRtfun_dictR`RvR(R1RfRRvRRRV((RRJs8<cGsAt|tpt|n||jot|n|S(s This check matches the value to any of a set of options. >>> vtor.check('option("yoda", "jedi")', 'yoda') 'yoda' >>> vtor.check('option("yoda", "jedi")', 'jed') Traceback (most recent call last): VdtValueError: the value "jed" is unacceptable. >>> vtor.check('option("yoda", "jedi")', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. N(RtR1RuRtoptionsR(R1R((RRs  cOs |||fS(s  A function that exists for test purposes. >>> checks = [ ... '3, 6, min=1, max=3, test=list(a, b, c)', ... '3', ... '3, 6', ... '3,', ... 'min=1, test="a b c"', ... 'min=5, test="a, b, c"', ... 'min=1, max=3, test="a, b, c"', ... 'min=-100, test=-99', ... 'min=1, max=3', ... '3, 6, test="36"', ... '3, 6, test="a, b, c"', ... '3, max=3, test=list("a", "b", "c")', ... '''3, max=3, test=list("'a'", 'b', "x=(c)")''', ... "test='x=fish(3)'", ... ] >>> v = Validator({'test': _test}) >>> for entry in checks: ... print v.check(('test(%s)' % entry), 3) (3, ('3', '6'), {'test': ['a', 'b', 'c'], 'max': '3', 'min': '1'}) (3, ('3',), {}) (3, ('3', '6'), {}) (3, ('3',), {}) (3, (), {'test': 'a b c', 'min': '1'}) (3, (), {'test': 'a, b, c', 'min': '5'}) (3, (), {'test': 'a, b, c', 'max': '3', 'min': '1'}) (3, (), {'test': '-99', 'min': '-100'}) (3, (), {'max': '3', 'min': '1'}) (3, ('3', '6'), {'test': '36'}) (3, ('3', '6'), {'test': 'a, b, c'}) (3, ('3',), {'test': ['a', 'b', 'c'], 'max': '3'}) (3, ('3',), {'test': ["'a'", 'b', 'x=(c)'], 'max': '3'}) (3, (), {'test': 'x=fish(3)'}) N(R1Rftkeywargs(R1RfR((Rt_tests%t__main__tINTP_VERtvtortglobs(s __version__sdottedQuadToNumsnumToDottedQuads ValidateErrorsVdtUnknownCheckErrors VdtParamErrors VdtTypeErrors VdtValueErrorsVdtValueTooSmallErrorsVdtValueTooBigErrorsVdtValueTooShortErrorsVdtValueTooLongErrorsVdtMissingValues Validators is_integersis_floatsis_boolsis_lists is_ip_addrs is_strings is_int_lists is_bool_lists is_float_listsis_string_listsis_ip_addr_lists is_mixed_lists is_options __docformat__(ii(CR.RRt __revision__t__all__tsyst version_infoRt RuntimeErrorRhtstrtunicodeRuRiRkRWRgRjRlRt NameErrorRRt ExceptionRR RR2RRRRR R R tobjectR RmRwRERRR|RRRRRRRRRRRRRRR,tdoctesttmodulestgettmt__dict__tcopyRRFttestmod(.RlRRRR RRRRRWRRRRRRRhRRRR RRRRRuR RRRRRjRR RRRwR RRRRgRRRR((Rt?}sl      )  $         $83` < ')3 F  )  "m fFc@sdZdZdZdZdUZd kZeid! ZedVjoed"nd k Z e e fZ e i d#e iZe i d$e iZd%Zd&eZyeWnej od'ZnXd(Zd)Zdefd*YZdefd+YZdefd,YZd efd-YZd efd.YZd efd/YZd efd0YZd efd1YZ defd2YZ!defd3YZ"de#fd4YZ$e%d5Z&d d d6Z(d d d7Z)he*e*<d8e*<d9e*<d:e*<d;e*<e%e%<d<e%<d=e%<d>e%<d?e%i?Z@e@iAhdRe<dSe$<e:iBe=dTe@nd S(WsF The Validator object is used to check that supplied values conform to a specification. The value can be supplied as a string - e.g. from a config file. In this case the check will also *convert* the value to the required type. This allows you to add validation as a transparent layer to access data stored as strings. The validation checks that the data is correct *and* converts it to the expected type. Some standard checks are provided for basic data types. Additional checks are easy to write. They can be provided when the ``Validator`` is instantiated or added afterwards. The standard functions work with the following basic data types : * integers * floats * booleans * strings * ip_addr plus lists of these datatypes Adding additional checks is done through coding simple functions. The full set of standard checks are : * 'integer': matches integer values (including negative) Takes optional 'min' and 'max' arguments : :: integer() integer(3, 9) # any value from 3 to 9 integer(min=0) # any positive value integer(max=9) * 'float': matches float values Has the same parameters as the integer check. * 'boolean': matches boolean values - ``True`` or ``False`` Acceptable string values for True are : true, on, yes, 1 Acceptable string values for False are : false, off, no, 0 Any other value raises an error. * 'ip_addr': matches an Internet Protocol address, v.4, represented by a dotted-quad string, i.e. '1.2.3.4'. * 'string': matches any string. Takes optional keyword args 'min' and 'max' to specify min and max lengths of the string. * 'list': matches any list. Takes optional keyword args 'min', and 'max' to specify min and max sizes of the list. * 'int_list': Matches a list of integers. Takes the same arguments as list. * 'float_list': Matches a list of floats. Takes the same arguments as list. * 'bool_list': Matches a list of boolean values. Takes the same arguments as list. * 'ip_addr_list': Matches a list of IP addresses. Takes the same arguments as list. * 'string_list': Matches a list of strings. Takes the same arguments as list. * 'mixed_list': Matches a list with different types in specific positions. List size must match the number of arguments. Each position can be one of : 'integer', 'float', 'ip_addr', 'string', 'boolean' So to specify a list with two strings followed by two integers, you write the check as : :: mixed_list('string', 'string', 'integer', 'integer') * 'pass': This check matches everything ! It never fails and the value is unchanged. It is also the default if no check is specified. * 'option': This check matches any from a list of options. You specify this check with : :: option('option 1', 'option 2', 'option 3') You can supply a default value (returned if no value is supplied) using the default keyword argument. You specify a list argument for default using a list constructor syntax in the check : :: checkname(arg1, arg2, default=list('val 1', 'val 2', 'val 3')) A badly formatted set of arguments will raise a ``VdtParamError``. srestructuredtext ens0.2.1s4$Id: validate.py 123 2005-09-08 08:54:28Z fuzzyman $t __version__tdottedQuadToNumtnumToDottedQuadt ValidateErrortVdtUnknownCheckErrort VdtParamErrort VdtTypeErrort VdtValueErrortVdtValueTooSmallErrortVdtValueTooBigErrortVdtValueTooShortErrortVdtValueTooLongErrortVdtMissingValuet Validatort is_integertis_floattis_booltis_listt is_ip_addrt is_stringt is_int_listt is_bool_listt is_float_listtis_string_listtis_ip_addr_listt is_mixed_listt is_optiont __docformat__NisPython v.2.2 or later neededs (?: ([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*list\( ( (?: \s* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted ) \s*,\s* )* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted )? # last one ) \) ) s ( (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s=][^,=]*?) # unquoted ) (?: (?:\s*,\s*)|(?:\s*$) # comma ) s (?: ( (?: [a-zA-Z_][a-zA-Z0-9_]*\s*=\s*list\( (?: \s* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted ) \s*,\s* )* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s\)][^,\)]*?) # unquoted )? # last one \) )| (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s=][^,=]*?)| # unquoted (?: # keyword argument [a-zA-Z_][a-zA-Z0-9_]*\s*=\s* (?: (?:".*?")| # double quotes (?:'.*?')| # single quotes (?:[^'",\s=][^,=]*?) # unquoted ) ) ) ) (?: (?:\s*,\s*)|(?:\s*$) # comma ) ) s^%s*cCs|odSndSdS(s$Simple boolean equivalent function. iiN(tval(R((t/usr/bin/validate.pytboolscCsdk}dk}y'|id|i|idSWnA|ij o2|idjodSq}td|nXdS(s= Convert decimal dotted quad string to long integer >>> dottedQuadToNum('1 ') 1L >>> dottedQuadToNum(' 1.2') 16777218L >>> dottedQuadToNum(' 1.2.3 ') 16908291L >>> dottedQuadToNum('1.2.3.4') 16909060L >>> dottedQuadToNum('1.2.3. 4') Traceback (most recent call last): ValueError: Not a good dotted-quad IP: 1.2.3. 4 >>> dottedQuadToNum('255.255.255.255') 4294967295L >>> dottedQuadToNum('255.255.255.256') Traceback (most recent call last): ValueError: Not a good dotted-quad IP: 255.255.255.256 Ns!Lis255.255.255.255lsNot a good dotted-quad IP: %s(tsockettstructtunpackt inet_atontiptstripterrort ValueError(R#RR ((RRs cCsndk}dk}y#|i|idt|SWn2|i|itfj otd|nXdS(s Convert long int to dotted quad string >>> numToDottedQuad(-1L) Traceback (most recent call last): ValueError: Not a good numeric IP: -1 >>> numToDottedQuad(1L) '0.0.0.1' >>> numToDottedQuad(16777218L) '1.0.0.2' >>> numToDottedQuad(16908291L) '1.2.0.3' >>> numToDottedQuad(16909060L) '1.2.3.4' >>> numToDottedQuad(4294967295L) '255.255.255.255' >>> numToDottedQuad(4294967296L) Traceback (most recent call last): ValueError: Not a good numeric IP: 4294967296 Ns!LsNot a good numeric IP: %s( RR t inet_ntoatpacktlongtnumR%t OverflowErrorR&(R*RR ((RR)s #cBstZdZRS(s This error indicates that the check failed. It can be the base class for more specific errors. Any check function that fails ought to raise this error. (or a subclass) >>> raise ValidateError Traceback (most recent call last): ValidateError (t__name__t __module__t__doc__(((RRIs cBstZdZRS(s1No value was supplied to a check that needed one.(R,R-R.(((RR Vs cBstZdZdZRS(s'An unknown check function was requestedcCsti|d|dS(s >>> raise VdtUnknownCheckError('yoda') Traceback (most recent call last): VdtUnknownCheckError: the check "yoda" is unknown. sthe check "%s" is unknown.N(Rt__init__tselftvalue(R0R1((RR/\s (R,R-R.R/(((RRYs cBstZdZdZRS(s!An incorrect parameter was passedcCsti|d||fdS(s >>> raise VdtParamError('yoda', 'jedi') Traceback (most recent call last): VdtParamError: passed an incorrect value "jedi" for parameter "yoda". s2passed an incorrect value "%s" for parameter "%s".N(t SyntaxErrorR/R0R1tname(R0R3R1((RR/is (R,R-R.R/(((RRfs cBstZdZdZRS(s(The value supplied was of the wrong typecCsti|d|dS(s >>> raise VdtTypeError('jedi') Traceback (most recent call last): VdtTypeError: the value "jedi" is of the wrong type. s$the value "%s" is of the wrong type.N(RR/R0R1(R0R1((RR/ws (R,R-R.R/(((RRts cBstZdZdZRS(sS The value supplied was of the correct type, but was not an allowed value. cCsti|d|dS(s >>> raise VdtValueError('jedi') Traceback (most recent call last): VdtValueError: the value "jedi" is unacceptable. sthe value "%s" is unacceptable.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RRs cBstZdZdZRS(s>The value supplied was of the correct type, but was too small.cCsti|d|dS(s >>> raise VdtValueTooSmallError('0') Traceback (most recent call last): VdtValueTooSmallError: the value "0" is too small. sthe value "%s" is too small.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RRs cBstZdZdZRS(s<The value supplied was of the correct type, but was too big.cCsti|d|dS(s >>> raise VdtValueTooBigError('1') Traceback (most recent call last): VdtValueTooBigError: the value "1" is too big. sthe value "%s" is too big.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RR s cBstZdZdZRS(s>The value supplied was of the correct type, but was too short.cCsti|d|fdS(s >>> raise VdtValueTooShortError('jed') Traceback (most recent call last): VdtValueTooShortError: the value "jed" is too short. sthe value "%s" is too short.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RR s cBstZdZdZRS(s=The value supplied was of the correct type, but was too long.cCsti|d|fdS(s >>> raise VdtValueTooLongError('jedie') Traceback (most recent call last): VdtValueTooLongError: the value "jedie" is too long. sthe value "%s" is too long.N(RR/R0R1(R0R1((RR/s (R,R-R.R/(((RR s cBstZdZeidZeidZeZeZeie ei Z eie ei Z edZedZdZdZdZRS(s: Validator is an object that allows you to register a set of 'checks'. These checks take input and test that it conforms to the check. This can also involve converting the value from a string into the correct datatype. The ``check`` method takes an input string which configures which check is to be used and applies that check to a supplied value. An example input string would be: 'int_range(param1, param2)' You would then provide something like: >>> def int_range_check(value, min, max): ... # turn min and max from strings to integers ... min = int(min) ... max = int(max) ... # check that value is of the correct type. ... # possible valid inputs are integers or strings ... # that represent integers ... if not isinstance(value, (int, long, StringTypes)): ... raise VdtTypeError(value) ... elif isinstance(value, StringTypes): ... # if we are given a string ... # attempt to convert to an integer ... try: ... value = int(value) ... except ValueError: ... raise VdtValueError(value) ... # check the value is between our constraints ... if not min <= value: ... raise VdtValueTooSmallError(value) ... if not value <= max: ... raise VdtValueTooBigError(value) ... return value >>> fdict = {'int_range': int_range_check} >>> vtr1 = Validator(fdict) >>> vtr1.check('int_range(20, 40)', '30') 30 >>> vtr1.check('int_range(20, 40)', '60') Traceback (most recent call last): VdtValueTooBigError: the value "60" is too big. New functions can be added with : :: >>> vtr2 = Validator() >>> vtr2.functions['int_range'] = int_range_check Or by passing in a dictionary of functions when Validator is instantiated. Your functions *can* use keyword arguments, but the first argument should always be 'value'. If the function doesn't take additional arguments, the parentheses are optional in the check. It can be written with either of : :: keyword = function_name keyword = function_name() The first program to utilise Validator() was Michael Foord's ConfigObj, an alternative to ConfigParser which supports lists and can validate a config file using a config schema. For more details on using Validator with ConfigObj see: http://www.voidspace.org.uk/python/configobj.html s (.+?)\((.*)\)s%^([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*)$cCshd|i<dt<dt<dt<dt<dt<dt<dt<d t <d t <d t <d t <d t <d|i<dt<|_|dj o|ii|nt|_dS(s( >>> vtri = Validator() ttintegertfloattbooleantip_addrtstringtlisttint_listt float_listt bool_listt ip_addr_listt string_listt mixed_listtpasstoptionN(R0t_passRRRRRRRRRRRRRt functionstNonetupdateRtbaseErrorClass(R0RD((RR/s  cCs|ii|}|o |id} |id}|ii|}|djo t ng}h}x|ii|D]} | i} |ii| }|o&|i|\} }||| >> vtor.check('yoda', '') Traceback (most recent call last): VdtUnknownCheckError: the check "yoda" is unknown. >>> vtor.check('yoda()', '') Traceback (most recent call last): VdtUnknownCheckError: the check "yoda" is unknown. iitdefaultREN("R0t_func_retmatchtcheckt fun_matchtgrouptfun_namet arg_stringt _matchfindert arg_matchRERtfun_argst fun_kwargst _paramfindertfindalltargR$t _list_argt listmatcht _list_handletkeyRt_key_argtkeymatcht_unquotetappendtmissingR1tKeyErrorR RDtfunR(R0RKR1R_RRRRORQRLRNR\RZRVRaRXRS((RRK9sV        cCsNt|djo7|ddjo&|d|djo|dd!}n|S( sUnquote a value if necessary.iit't"iiN(RbRc(tlenR(R0R((RR]s9cCsag}|id}|id}x0|ii|D]}|i |i |q7W||fS(s7Take apart a ``keyword=list('val, 'val')`` type string.iiN( toutRXRMR3targsR0t _list_membersRURVR^R](R0RXR3RfRVRe((RRYscCs|S(s Dummy check that always passes >>> vtor.check('', 0) 0 >>> vtor.check('', '0') '0' N(R1(R0R1((RRCs(R,R-R.tretcompileRIR[RWRgt _paramstringtVERBOSERTt _matchstringRPRER/tFalseRKR]RYRC(((RR s F  H  cCs|otpt}g}xt||D]\}}|djo|i |q*t |tt ttfoBy|i ||Wqtj o}t||qXq*t||q*W|S(s Return numbers from inputs or raise VdtParamError. Lets ``None`` pass through. Pass in keyword argument ``to_float=True`` to use float for the conversion rather than int. >>> _is_num_param(('', ''), (0, 1.0)) [0, 1] >>> _is_num_param(('', ''), (0, 1.0), to_float=True) [0.0, 1.0] >>> _is_num_param(('a'), ('a')) Traceback (most recent call last): VdtParamError: passed an incorrect value "a" for parameter "a". N(tto_floatR6tintRat out_paramstziptnamestvaluesR3RRER^t isinstanceR)t StringTypesR&teR(RrRsRnRvR3RRpRa((Rt _is_num_params  cCstd||f\}}t|ttt fpt |nt|t o6yt|}Wqt j ot |qXn|dj o||jot |n|dj o||jot|n|S(sH A check that tests that a given value is an integer (int, or long) and optionally, between bounds. A negative value is accepted, while a float will fail. If the value is a string, then the conversion is done - if possible. Otherwise a VdtError is raised. >>> vtor.check('integer', '-1') -1 >>> vtor.check('integer', '0') 0 >>> vtor.check('integer', 9) 9 >>> vtor.check('integer', 'a') Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. >>> vtor.check('integer', '2.2') Traceback (most recent call last): VdtTypeError: the value "2.2" is of the wrong type. >>> vtor.check('integer(10)', '20') 20 >>> vtor.check('integer(max=20)', '15') 15 >>> vtor.check('integer(10)', '9') Traceback (most recent call last): VdtValueTooSmallError: the value "9" is too small. >>> vtor.check('integer(10)', 9) Traceback (most recent call last): VdtValueTooSmallError: the value "9" is too small. >>> vtor.check('integer(max=20)', '35') Traceback (most recent call last): VdtValueTooBigError: the value "35" is too big. >>> vtor.check('integer(max=20)', 35) Traceback (most recent call last): VdtValueTooBigError: the value "35" is too big. >>> vtor.check('integer(0, 9)', False) 0 tmintmaxN(sminsmax(RwRxRytmin_valtmax_valRtR1RoR)RuRR&RERR (R1RxRyRzR{((RRs'cCstd||fdt\}}t|tt t t fpt |nt|t p6yt |}Wqt j ot |qXn|dj o||jot|n|dj o||jot|n|S(s< A check that tests that a given value is a float (an integer will be accepted), and optionally - that it is between bounds. If the value is a string, then the conversion is done - if possible. Otherwise a VdtError is raised. This can accept negative values. >>> vtor.check('float', '2') 2.0 From now on we multiply the value to avoid comparing decimals >>> vtor.check('float', '-6.8') * 10 -68.0 >>> vtor.check('float', '12.2') * 10 122.0 >>> vtor.check('float', 8.4) * 10 84.0 >>> vtor.check('float', 'a') Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. >>> vtor.check('float(10.1)', '10.2') * 10 102.0 >>> vtor.check('float(max=20.2)', '15.1') * 10 151.0 >>> vtor.check('float(10.0)', '9.0') Traceback (most recent call last): VdtValueTooSmallError: the value "9.0" is too small. >>> vtor.check('float(max=20.0)', '35.0') Traceback (most recent call last): VdtValueTooBigError: the value "35.0" is too big. RxRyRnN(sminsmax(RwRxRytTrueRzR{RtR1RoR)R6RuRR&RERR (R1RxRyRzR{((RRs"!tont1ttruetyestofft0tfalsetnocCst|to8yt|iSWqHtj ot|qHXn|tjotSn"|tjotSn t|dS(s Check if the value represents a boolean. >>> vtor.check('boolean', 0) 0 >>> vtor.check('boolean', False) 0 >>> vtor.check('boolean', '0') 0 >>> vtor.check('boolean', 'off') 0 >>> vtor.check('boolean', 'false') 0 >>> vtor.check('boolean', 'no') 0 >>> vtor.check('boolean', 'nO') 0 >>> vtor.check('boolean', 'NO') 0 >>> vtor.check('boolean', 1) 1 >>> vtor.check('boolean', True) 1 >>> vtor.check('boolean', '1') 1 >>> vtor.check('boolean', 'on') 1 >>> vtor.check('boolean', 'true') 1 >>> vtor.check('boolean', 'yes') 1 >>> vtor.check('boolean', 'Yes') 1 >>> vtor.check('boolean', 'YES') 1 >>> vtor.check('boolean', '') Traceback (most recent call last): VdtTypeError: the value "" is of the wrong type. >>> vtor.check('boolean', 'up') Traceback (most recent call last): VdtTypeError: the value "up" is of the wrong type. N( RtR1Rut bool_dicttlowerR`RRmR|(R1((RR0s+  cCs`t|tpt|n|i}yt|Wntj ot|nX|S(s Check that the supplied value is an Internet Protocol address, v.4, represented by a dotted-quad string, i.e. '1.2.3.4'. >>> vtor.check('ip_addr', '1 ') '1' >>> vtor.check('ip_addr', ' 1.2') '1.2' >>> vtor.check('ip_addr', ' 1.2.3 ') '1.2.3' >>> vtor.check('ip_addr', '1.2.3.4') '1.2.3.4' >>> vtor.check('ip_addr', '0.0.0.0') '0.0.0.0' >>> vtor.check('ip_addr', '255.255.255.255') '255.255.255.255' >>> vtor.check('ip_addr', '255.255.255.256') Traceback (most recent call last): VdtValueError: the value "255.255.255.256" is unacceptable. >>> vtor.check('ip_addr', '1.2.3.4.5') Traceback (most recent call last): VdtValueError: the value "1.2.3.4.5" is unacceptable. >>> vtor.check('ip_addr', '1.2.3. 4') Traceback (most recent call last): VdtValueError: the value "1.2.3. 4" is unacceptable. >>> vtor.check('ip_addr', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. N(RtR1RuRR$RR&R(R1((RRls cCstd||f\}}yt|}Wntj ot |nX|dj o||jot |n|dj o||jot |n|S(ss Check that the value is a list of values. You can optionally specify the minimum and maximum number of members. It does no check on list members. >>> vtor.check('list', ()) () >>> vtor.check('list', []) [] >>> vtor.check('list', (1, 2)) (1, 2) >>> vtor.check('list', [1, 2]) [1, 2] >>> vtor.check('list', '12') '12' >>> vtor.check('list(3)', (1, 2)) Traceback (most recent call last): VdtValueTooShortError: the value "(1, 2)" is too short. >>> vtor.check('list(max=5)', (1, 2, 3, 4, 5, 6)) Traceback (most recent call last): VdtValueTooLongError: the value "(1, 2, 3, 4, 5, 6)" is too long. >>> vtor.check('list(min=3, max=5)', (1, 2, 3, 4)) (1, 2, 3, 4) >>> vtor.check('list', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. RxRyN(sminsmax( RwRxRytmin_lentmax_lenRdR1t num_memberst TypeErrorRRER R (R1RxRyRRR((RRscCs0t|tpt|nt|||S(s Check that the supplied value is a string. You can optionally specify the minimum and maximum number of members. >>> vtor.check('string', '0') '0' >>> vtor.check('string', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. >>> vtor.check('string(2)', '12') '12' >>> vtor.check('string(2)', '1') Traceback (most recent call last): VdtValueTooShortError: the value "1" is too short. >>> vtor.check('string(min=2, max=3)', '123') '123' >>> vtor.check('string(min=2, max=3)', '1234') Traceback (most recent call last): VdtValueTooLongError: the value "1234" is too long. N(RtR1RuRRRxRy(R1RxRy((RRscCs1g}t|||D]}|t|q~S(s Check that the value is a list of integers. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is an integer. >>> vtor.check('int_list', ()) [] >>> vtor.check('int_list', []) [] >>> vtor.check('int_list', (1, 2)) [1, 2] >>> vtor.check('int_list', [1, 2]) [1, 2] >>> vtor.check('int_list', [1, 'a']) Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. N(t_[1]RR1RxRytmemR(R1RxRyRR((RRscCs1g}t|||D]}|t|q~S(sl Check that the value is a list of booleans. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is a boolean. >>> vtor.check('bool_list', ()) [] >>> vtor.check('bool_list', []) [] >>> check_res = vtor.check('bool_list', (True, False)) >>> check_res == [True, False] 1 >>> check_res = vtor.check('bool_list', [True, False]) >>> check_res == [True, False] 1 >>> vtor.check('bool_list', [True, 'a']) Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. N(RRR1RxRyRR(R1RxRyRR((RRscCs1g}t|||D]}|t|q~S(s Check that the value is a list of floats. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is a float. >>> vtor.check('float_list', ()) [] >>> vtor.check('float_list', []) [] >>> vtor.check('float_list', (1, 2.0)) [1.0, 2.0] >>> vtor.check('float_list', [1, 2.0]) [1.0, 2.0] >>> vtor.check('float_list', [1, 'a']) Traceback (most recent call last): VdtTypeError: the value "a" is of the wrong type. N(RRR1RxRyRR(R1RxRyRR((RRscCs1g}t|||D]}|t|q~S(s Check that the value is a list of strings. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is a string. >>> vtor.check('string_list', ()) [] >>> vtor.check('string_list', []) [] >>> vtor.check('string_list', ('a', 'b')) ['a', 'b'] >>> vtor.check('string_list', ['a', 1]) Traceback (most recent call last): VdtTypeError: the value "1" is of the wrong type. N(RRR1RxRyRR(R1RxRyRR((RRscCs1g}t|||D]}|t|q~S(s Check that the value is a list of IP addresses. You can optionally specify the minimum and maximum number of members. Each list member is checked that it is an IP address. >>> vtor.check('ip_addr_list', ()) [] >>> vtor.check('ip_addr_list', []) [] >>> vtor.check('ip_addr_list', ('1.2.3.4', '5.6.7.8')) ['1.2.3.4', '5.6.7.8'] >>> vtor.check('ip_addr_list', ['a']) Traceback (most recent call last): VdtValueError: the value "a" is unacceptable. N(RRR1RxRyRR(R1RxRyRR((RR.sR5R6R8R9R7cGsyt|}Wntj ot|nX|t|jot|n$|t|jot|ny<g}t ||D]\}}|t ||q~SWn$t j o}td|nXdS(s3 Check that the value is a list. Allow specifying the type of each member. Work on lists of specific lengths. You specify each member as a positional argument specifying type Each type should be one of the following strings : 'integer', 'float', 'ip_addr', 'string', 'boolean' So you can specify a list of two strings, followed by two integers as : mixed_list('string', 'string', 'integer', 'integer') The length of the list must match the number of positional arguments you supply. >>> mix_str = "mixed_list('integer', 'float', 'ip_addr', 'string', 'boolean')" >>> check_res = vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', True)) >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 1 >>> check_res = vtor.check(mix_str, ('1', '2.0', '1.2.3.4', 'a', 'True')) >>> check_res == [1, 2.0, '1.2.3.4', 'a', True] 1 >>> vtor.check(mix_str, ('b', 2.0, '1.2.3.4', 'a', True)) Traceback (most recent call last): VdtTypeError: the value "b" is of the wrong type. >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a')) Traceback (most recent call last): VdtValueTooShortError: the value "(1, 2.0, '1.2.3.4', 'a')" is too short. >>> vtor.check(mix_str, (1, 2.0, '1.2.3.4', 'a', 1, 'b')) Traceback (most recent call last): VdtValueTooLongError: the value "(1, 2.0, '1.2.3.4', 'a', 1, 'b')" is too long. >>> vtor.check(mix_str, 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. This test requires an elaborate setup, because of a change in error string output from the interpreter between Python 2.2 and 2.3 . >>> res_seq = ( ... 'passed an incorrect value "', ... 'yoda', ... '" for parameter "mixed_list".', ... ) >>> if INTP_VER == (2, 2): ... res_str = "".join(res_seq) ... else: ... res_str = "'".join(res_seq) >>> try: ... vtor.check('mixed_list("yoda")', ('a')) ... except VdtParamError, err: ... str(err) == res_str 1 R@N(RdR1tlengthRRRfR R RRqRVRtfun_dictR`RvR(R1RfRRvRRRV((RRJs8<cGsAt|tpt|n||jot|n|S(s This check matches the value to any of a set of options. >>> vtor.check('option("yoda", "jedi")', 'yoda') 'yoda' >>> vtor.check('option("yoda", "jedi")', 'jed') Traceback (most recent call last): VdtValueError: the value "jed" is unacceptable. >>> vtor.check('option("yoda", "jedi")', 0) Traceback (most recent call last): VdtTypeError: the value "0" is of the wrong type. N(RtR1RuRtoptionsR(R1R((RRs  cOs |||fS(s  A function that exists for test purposes. >>> checks = [ ... '3, 6, min=1, max=3, test=list(a, b, c)', ... '3', ... '3, 6', ... '3,', ... 'min=1, test="a b c"', ... 'min=5, test="a, b, c"', ... 'min=1, max=3, test="a, b, c"', ... 'min=-100, test=-99', ... 'min=1, max=3', ... '3, 6, test="36"', ... '3, 6, test="a, b, c"', ... '3, max=3, test=list("a", "b", "c")', ... '''3, max=3, test=list("'a'", 'b', "x=(c)")''', ... "test='x=fish(3)'", ... ] >>> v = Validator({'test': _test}) >>> for entry in checks: ... print v.check(('test(%s)' % entry), 3) (3, ('3', '6'), {'test': ['a', 'b', 'c'], 'max': '3', 'min': '1'}) (3, ('3',), {}) (3, ('3', '6'), {}) (3, ('3',), {}) (3, (), {'test': 'a b c', 'min': '1'}) (3, (), {'test': 'a, b, c', 'min': '5'}) (3, (), {'test': 'a, b, c', 'max': '3', 'min': '1'}) (3, (), {'test': '-99', 'min': '-100'}) (3, (), {'max': '3', 'min': '1'}) (3, ('3', '6'), {'test': '36'}) (3, ('3', '6'), {'test': 'a, b, c'}) (3, ('3',), {'test': ['a', 'b', 'c'], 'max': '3'}) (3, ('3',), {'test': ["'a'", 'b', 'x=(c)'], 'max': '3'}) (3, (), {'test': 'x=fish(3)'}) N(R1Rftkeywargs(R1RfR((Rt_tests%t__main__tINTP_VERtvtortglobs(s __version__sdottedQuadToNumsnumToDottedQuads ValidateErrorsVdtUnknownCheckErrors VdtParamErrors VdtTypeErrors VdtValueErrorsVdtValueTooSmallErrorsVdtValueTooBigErrorsVdtValueTooShortErrorsVdtValueTooLongErrorsVdtMissingValues Validators is_integersis_floatsis_boolsis_lists is_ip_addrs is_strings is_int_lists is_bool_lists is_float_listsis_string_listsis_ip_addr_lists is_mixed_lists is_options __docformat__(ii(CR.RRt __revision__t__all__tsyst version_infoRt RuntimeErrorRhtstrtunicodeRuRiRkRWRgRjRlRt NameErrorRRt ExceptionRR RR2RRRRR R R tobjectR RmRwRERRR|RRRRRRRRRRRRRRR,tdoctesttmodulestgettmt__dict__tcopyRRFttestmod(.RlRRRR RRRRRWRRRRRRRhRRRR RRRRRuR RRRRRjRR RRRwR RRRRgRRRR((Rt?}sl      )  $         $83` < ')3 F  )  "ELF 4G\4 (  55@"@"@LldtQ,uPowerPC@=@"aJG=`#akl9J9k8 | X@H$|H|h< 84|dP|N =`"= $9kG9)l!}+HP})p|$|+x|x|#x}%Kx}c[x8Hh<ޭ`|@= "xG(xH+<8<`0H61,||x@$<`!<8c<0L1H2}8`H<Hy%<`!8cH),|~xA?"<!8D8G8H),@ <`!8G8cP8Hg,A@<!x8X8G8H),@,<!8G8`8HgE,@8= " GH"1|}xHxx<H5mH4ix$8! |N !|A4?@"|{x@;,A@;;;@cx|.; ; Hfx,;A|.,@8|xA48!0|N !|<!`t?$|}x9?`8'8`HM,|~x@߄`<!8`8dHM,|xA,8P8 Hk!P| A ,@||x;x8xHem;@<!xx8pxxH5,@<`!x8cL1H0IH;xxH9,|xA,@<`!D8cL1H0HxH0H8`Hv,|xAH88Hé!xx)8})N!,@<`!x8cL1H/!8a)})N!,A xHwt`8!p|N !|!Ԑ|yx|#x8`|+x`c;Hv-,|{x@<`!8cHL= " G,@= !9a@9)|4|5H0,A ,Ax8a@HcH 8@;@<!8xHcՓH;8a@x!@ADH8],||xA4@<`!D8cL1H.HxH.<`!8cH!8x`)ex})N!,|}xA<`!8cL1H.1H|dx<`!8c L1H.!x)})N!dxxxHIU,@<`!8c ,L1H-H<!8`8 PHJ,AH2<!8`8 \HJ= "<!|`x8 h8` GHJ,|}xA,K= ",iG@<`!x8c pL1H-]<!8`8 HJU,|}xA,K= ",iG @<`!x8c L1H-= "G ,A4;P<!8 xL1HrxH2 <`!8c L1H,= "G,A$;<!8 xL1HrxH1<!8`8 HI,A|dx<`!8c'L1H,}<!8`8 HIu,AKI8;,A!8a)})N!k0}'1@} } H9A cxHtIx!8!|N !|= " G,A HJ<`!<$8c 8lL1H+ɀ8!|N 8c, M , @ , A |t,@ N c |th T>U)>|})}*9@( |th T>U)>|})}*9A , @8 , A ,M dN !|A4|#x?`"<!;@8!|}x[H;HHG,|xADxxH_u8xH`E,|~xA0,A8 ;H<!x8!HGm,|xA8= !8~9)!x}i4}~5H_ 8xH_8 ;<!x8!HHA,A<ro` ;<!x8!$HH,A<rw` ;<!x8!0HF,|xA8= !8~9)!8x|L|MH^i8xH_98 ;<!x8!DHF},|xA8= !8~ 9)!Px|t|uH^8xH^8 ;<!x8!`HGQ,A,= !x9)!h8|l|mH^8 ;<!x8!xHE,A(|dxxH]8xH^m8 ;^<!8!xHF= "<!|`x8!x G,HE,A = "i@,AxxH]148{HA8!0|N !|dx<`!|8c!$L1H();<`!?"8c!L1H(8= $88`;l lHI<`!8cL1H'<!|G88!H]18|`x$a;@H\:= !9),<$95`)HH= " @,A?"<`!8P88ci@;PHu8$8aK݀,A@<`!8cL1H&u$,A<`!8cL1H&Y<`!8cL1H&I= " G,A8<!8`8HC1,A ,A88H`|~x<`!;8cL1H%,AH+!,@4dH#9,|x&@H*|@ @ ; HHk 81i}KI ||}ISx| H9A ,A= $89ill k 1@}j1I| I}i9A|, At, @ K1Hd,@\= $8;l<!8xlHC),A0= " G,A <`!x8c';@L1H$k ! | k !I}*I}+yAd,@ HDa,A<`!8cL1H$y$,A<`!8c L1H$]<`!8cL1H$MH`,@X<` 88cd?$HE<`!8cL1H$<`"8l8caHX;l8= "8a8$ G$K9>"G,A$!, A ,@ HCՐaG;u`,A?@!8`8'?!H@8d|{x8`H@,|xA,8 8 H^A! | A ,@|yx<!8`8!H@I,A = "i@?!8`8HAM,A:<!a8H@ ,A,A8'axH?,|{x@u`8dxH?,|xA,8 8 H]}! | A ,@|yx8xH@,A:,AT$,A$= "<`! G8c$1@}*}+9@$= " G1@}*}+yA<`!8chKՀ$xK!|$<!a8HW9,@0,@ = $i`<`!dx8c%xL1H!H<!a8HV,@(= " G,A<`!8cKMH&H<!a8HV,@,= "8` G,A<`!8cK 8`H|,$@0= " G,A<`!8cKـa8cH&5H$L1H];v`x88(HU5{,Al<!8"HTi,@X|t,/AD,\A"!x)})N!8x8(HSiG0,A;` ,A<`!;v`8c#@L1HM{,A<!8"HRm,@x? |t,/Ad,\A\,A xHe- HR8cHc,||x@<`!8c#XH쀛HQ xHQр Hd铟 <`"x8caH&Y,|xA0;`<`!8cL1H} xHHЀa<8|cH,|zx@<`!;@8c#hL1H5H@!<x`)Ex})N!,|xx@ ;@H ;!x)})N!8x8(HQ,A,<`!W8c#DxL1H!=)!H<`!8c#L1HH G0,Ah?";`,AT= $;Ʉ`~,A<!8"HP,@? ,/At? ,\Ad,A xHcAHP8cHa,||x@<`!8c#L1HK<HOxHO݀Hb<`!;8c#L1H<`"x8c`H$Q,|xA0;`<`! 8cL1HuxHH8a<@8|cH,|yx@8<`!; 8c#L1H-H<`!x8c$xL1HH!|ex<@x)})N!|ip|wx} x|HP= @|H|p98?x@P?@<@8xHE<@|xx|x@x!)})N!<@|~A!;x)})N!8x8(HOA,A <`!V岾8c$@$xL1H5H<`!8c$hL1H!Hq= "iaHa|"H G0,A!;<=) 9)U=xxH8<!8$88}L1H^= "8,88 )G=; A 8]8 ;8= "GP~x!8a8|J| P|yZ| N!KtԺ8!|N !|84a|#x||x#8 )})N!, @<`!8c$H ,( T@<`!8c$L1HHTc(4H^y,|{x@<`!8c#K؁<x) })N!,|~xA<`!8c$K<x,ex)T(4})N!,T(4|A<`!8c$Kl;D|0LH~x@t,@X~, ALD,}+:}KB@LDHPHL} HP|PP?DH;; |0A?D<`!8c$, Á=)<9)| U)=)=@"?D@<`@8H }c[x8T}8 G0|@|~xA,Dx8?H@,@@@܀@<`!8c%,A@H4<`!8c*PH <`!8c%@L1H@DHi8`H,;~x|@;,@lx,|xAX<) })N!|`xx,@||?P@k| P|}iN!|@T,; |A|cxH]98`4a8!0|N !|84a|#x||x#8,)})N!,,@<`!8c%PH 8, T@<`!8c$L1HHc8H[e,|{x@<`!8c#K؁<x$) })N!,|~xA<`!8c*PK<x8ex)8})N!8|4 8|A<`!8c%pKh;D|HLH~x@|,@\~ | [yALD,,$}+:}KB@LDHPHL} HP|PP?DH;|4|;8A?D<`!8c$, A=)<9)| U)=)?D@$,@8= "<`@ G0H8= " G0T}8|~x|@A,Dx8?He@,@@@܀@<`!8c%,A H<`!8c*PH8;~x|@Ā;,@> x}$Kx| KyA<) })N!|`xx,@|?P@k| P|$}iN! |ip|H@$|A(<`!8c%@L1H@DH8`H 8;8|ADcxHY8`4a8!0|N <E#`LF9@| @0= =`Tak|H@|X@9@}CSxN <E#`LF9@| @0= =`Tak|H@|X@9@}CSxN !|<`!<!T8c%|88%88800HL1HE0! !i}+I!`| | KyA?"<`!GH;888c%L1H<!8 x8Da0H!,@,<!x8%8HE,@GH0H(<`!<!8c%8%88L1Hea00<`!;;,8c%AP= "a09)@x}J|H;;H9,@<`!8c&L1H<`!8c L1HHT8!P|N !|a4?`"G,@Kq?$<`!8l8c&8|#xH5l,@<`!x8c&8H5l,@<`!8c&(L1H%H@?!?$x888,8`Hm,@ <`!x8cL1H8`H;`,A?!88"HD,@8"Ht }i[x,A ,\@}+Kx ,@, A8 H9=`8, = $ih,A<!8&HHCE?$;`~`Kޱ= "|`x<`!8c&L GL1H<`!8c&pL1H G,@p<!8`8&H*,A<!8&HB,AD~`Hy,|xA,<!8'HB,A<`!x8c'L1H yK<`!8c'tL1H e8`4a8!0|N |BT>,M 8|c(x| P|*TM ||fx|l8c B|||78 B|L,N < `&||<@`B|8|LdN !0|9aȐ|#x|˥@$!(A0a8؁@ءHPX`89@p| 8|+xq8ؐt8ax@XapU@:}!( 9 @ !pxU+:9)}`Z!pHat8 t 9J B,@ W:}!Z8 9kB= "8a)GP})N!8`,@W:}!iԻ8!|N !0|9aȐ|#x|˥@$!(A0a8؁@ءHPX`89@p| 8|+xq8ؐt8ax@XapU@:}!( 9 @ !pxU+:9)}`Z!pHat8 t 9J B,@ W:}!Z8 9kB= "8a)GP})N!8,@,8`@p,W:8p|d@X;8 p(@ !pxU+:9)}`Z!pHat8 t8+ B|`x|xȀ8!|N !0|9aĐ|~x|˥@$!(A0a8؁@ءHPX`89|(8= !9)'|8!p8q8ؐt8x@X|apU:}!( 9I@ !pxU+:9)}`Z!pHat8 t 9 BT:8p= ")GP;8; 8a })N! ,A <`!x8c'L1H8`H Ի8!|N |fx8<`!88c'L1K|fx8<`!88c'L1K|`x|#x<`!|+x|3x8c'|x88L1Kl= "|kx|#xiG@|+x}d[x|xK= "|`xiGD|+x|#x|x,}%KxAK8`N !|Xd;|~xK58?,<!9 x8DAKM<!|`x}!,8'x@<`!x8c'HH8 H<<!|`x9 ,x8'A,H<x,9 <`!8c'AL1H-9 d}#KxX8!`|N !|= "|`x<`! GP8c(K]= ",iG@@H <`!8c( K== "|`x<"<`!88c(,8GH GDK},AH Q<`!<"8c(@8GL8KY,A<`!8c(4L1H 9<`!<"8c(H8G88K),A<`!8c(PL1H <`!<"8c(h8G<8K,A<`!8c(lL1H<`!8cL1H<`!8c(H <`!8c(H <`!8c)H 8!|N !|$|}xH;A$|gxx<`!|8c%888! L1K|fx8<`!88c)L1K,!|a4|{x|+x|#x8`Ad; <`!88fx8c)xxL1KQ8,|x<!<`!8c%|8)8@L1K%7@x4a8!0|N |fx|#x<`!|+x8c)88L1K!|fx<`!||#x8c)888L1K c8`|c8!|N |+x|3x!|fx}j[x<`!|8c)}GSx}cx88L1KY c8`|c8!|N |`x|#x<`!88c)|xL1K|dx8<`!8c)L1K!|a4|#x|~x|+x|3xK|}xx(A;|Kx,8x@xK |ex |)4|+xa8!0|N !|$= "<`!GL8c)8889L1KI,|xA,@<`!8c)L1H,@,,@  ,[@ |t`H |t$8! |N !|= "<`!8c)88GL89L1K8,@ |t|x8!|N !|<!= !a8* 889=`", 8i)@ GHHGH8i)8889L1K8!|N !|$|~x$, Ai |#x})|| H9@h |})}+9A| @@(<`!}P|#x8c)88xL1K,A0<`!<!8c)8* 88x9;L1KU?x, @`$8! |N !|$?"|}x8|eH@U$x8e|8! K!||#x|dx$?"8}mH@$= "8miGH|8! K!|9a|Ū@$!(A0a8؁@ءHPX`88pp8q8t8xK%8!|N !|=`"|`xkGH9a |@$!(A0a8؁@ءHPX`|x8p8p8q8t8xK8!|N ,@<`!8c*H,@<`!8c*,H,@<`!8c*LH,@<`!8c*\H,@<`!8c*tH,@<`!8c*H,@<`!8c*Hp,@<`!8c*H\,@<`!8c*HH,@<`!8c+H4,@<`!8c+H ,@<`!8c+0H <`!8c+\L1K,!|$|#x|+x;At= "|dxH,AdW>,@(<!8`8+p@D= ";iGHK]H4= "t9)C| p AK;H 8`K8|@K, |x//@|8` K8|$8! |N !||3x|+x<!|`x|#x<`!|;x8c'|8+t|x88aL1K8!|N <`!88c+|8L1Kt!|=`"|`xkGH9a |@$!(A0a8؁@ءHPX`|x8p8p8q8t8xKKy8!|N !|$|}xHH|@$8! |N |fx|#x<`!|+x8c+88L1K|fx|#x<`!88c+8L1Kl|ix|#x|+x|T<`!,08c+88L =`"G"|#x;v>|+x~D|3xU)~H;W:~8cH89`| @|{x@Ui:8| .9kB; ,A`x88v~xK?PA|}xcRT,xA<`!x8c,HK W >..p}~}@&UJU(4U :|P}kx! }hY0<!}`P9|zx$x8,x~óx8;9A| .| @9| CxA<`!x8c-L1K𱀞|A<`!8c-0L1KA<`!Dx8c-XL1K}.p|T (4T:|.})PH0|H9AH<`!x8c-tL1KEH0|}l.}@P9}AK},@T 8!P|} N !|8|dxa4?`"||x;v8xH$<!8-xH$xK,|}x@<`!x8c-H,K(|xA;(@<`!x8c-L1KaHx88xK,A<`!8c,Hؠv,ER@xxx8KH,U@(,@xxx8KH,@Dx8 K,A0 8a88899 K<`!8c-H<xxxK,Axxx8KyH<`!8c-L1KYxKջa4a8!0|N !}&|$|x|#x;K5,8`@lxK |x8`.ATH8cH6m|}xH0,xA$,A|AԀc,@A xH%x$8! |} N ,!|$AH5,x@$8! |N T`F>P`.P`BP`|xN !|= "4a|{x|#x A|+x|3x;A,A@?cxxx)x})N!= ",iG4@,@Ȁ4a|8!0N !p|9a |@$!(A0a8؁@ءHPX`8|}xp<`!88c.Hq8t8xL1K1x8pKq<`!= "8c.\G|= "GlL1K<`"88c~H =!p|9a |x<`!|8c.x@$!(A0a8؁@ءHPX`8p8q8t8xL1Kx8pK<`!= "8c.\G|= "GlL1KY8!|N = "=" G`9@,|x@0= " Gh(Gd| 9iA hGd| t}CSxN 8 G`N = "iG`N !|= "iGT,A@8 GTH^@l<``<`8Kݵ,~@$<`!8c0L1K ~Kԅ9`H08<`Hـ~K9`|dx|cp~ $$}c[x8! |N !|$|#x|}xc|+x|xK-$}|jx9 |}J`})Y=]8! N !|$|~x|#x#$|+x| P|@@|xx|JH$~x9 x}J`})Y|>^8! N !|$|x|#xcK8,Ax9 ?_8|x$8! |N  9 |kx|#x|H@8`HA@ $| @A + K$+KN !|<`$|xc,AK̀Kҕ$8`8! |N !||+x9at|˥@$!(A0a8؁@ءHPX`L1K׵t8!p|N !|9 D? "|~xG|3x;;,@Ѐ9 ,@,= "8G?";@;`8= " G;GGFfA4H9 EP9`| I|P}jY|:} Q|Z?#8>"8GH <!88-H 8K9 ,~A= "8Cx888H;,A ;H=GiTc"iGG7G|Y|H||QA= "? ")G?@"GxiYրG#)})N!= ",8iG@X= "?"G?`"GxwGpG||~PG|yG}J@})9G|(P}kG|G=]yGGwGGG?",AG,A= "?"iG8= "GkG#)})N!= ",|x8iG@|= "GiGGH = "G<"G9 Gg} Cx|BG}J`})YG'GG= "9`iG! | = "T( A | xH,8 (A 8 H8 (AH8 T >| (@8|0@A|0@| H@@ ;H |)|Zj, @| @AD,AD,/AA <`H|<``cHp|;xAh|gH`,AT|@P,@Dh= "9)C| Xp A 8 T >, x@,0@8Hd8`8! N ,9@T8 ,0@D8,x@4= "9)C| p DA8c8H|)8c}Zc= "9)CUj>}kt| P9kp DT / T /A @8 AT >9j| (@A,Ad}CxN !|9#,-A8!|K}#KxK|c8!|N ,!;;@p8 ,0@`8,x@P= "9)C| p DA88c8H,9 }(8c|I}%|Z})}`J81= "9)CT>|t| X9J9kp DUf>T / T /A@|+x9@|t9F@9K}Fp}GSx|0@ P@0Al@Ad,Adxx8! N !|9#,-A8!|K}#KxK |c8!|N C= "8C|hx 8`|p M 9* (}*Kx# |tj})|X8ip M KД!`|alq@@}7Kx= !}YSx|zx|+x|3x|;x}Cx:i0A = !:i0s)AW9<88`("A4s W)|&T/:|T6:0A<,@:-#H s A :+Hs)A : ;{s A$,@ ;{Hj! | `Py;@80;H\yAT~ݳx;xxxxH}!| xxxx; HE|~x|#x|`y@|@xs)wP@,`x;{,@,8 ;{;ZA,A ;Zs A4,@80H,@80!;Zs)@(`x;{,@,;{;ZA~x:|@|80:;ZAx;,@ }!, ;;ZA`x;{,@,8 ;{;ZACxal8!|N !|4!|yx|+x|}x,A,%@d;`!8 | x)})t8 (AH= !T:9)0| .|J| N c{Kc{Kc{Kc{ Kc{Kj?"9>C;U`>| pA8aK=||xH\, *@T9*!(@ ?U :9)|k?H8,@ c{a;@ ,.@9K9>CAkU`>| pA8aK|zxHL, *@L9*!(@ ?U :9)|k?H8C,@;@A9 | tiih } Ii`l |}'y@, LA , Z@*8 }(t!8 )})t8 (SAP= !T:9)1 | .|J| N si@$7@8 ;;Bx;(@ ?U :9)}k?H8 7  @l8 ;BHT(@ ?U :9)|k?H8,@ = !;0xK|@@Cxs`@,x;|@|8 ;;A,@|i;;Bx;|@|8 ;;AH|,@ ;c{(@ ?U :9)}k?H8 8xxIxjx8H(@ ?U :9)}k?H8 +|P H8%H<8HLc{@8H@c{H88%;! ,A;H8 H|,L@h(@4?T})??U :9)|?H ?89)U%88H,lA,Z@D(@ ?U :9)}k?H8 8H,h@T(@ ?U :9)}k?H8 si8A\|4|xHL(@ ?U :9)}k?H8 s`8A |3x|pxxIxjxK=|}x!8 |x ,@8|yP4!8!0|N !|9a|Ū8p@$!(A0a8؁@ءHPX`8p8q8t8xKA8!|N |kx 9k| t8 (A9)  }GI8|t8(A8c } x|cHP0}}Cx|SyL K= "|"iG= "GN 8= " G= " GN !|<"|fx9eG, }K8AL= "8 )G<`!9KT:|H@8c2p}HSx@L1K9H= "GȐIGЀ}Cx8!|N !|=@"9 $|x G,A= "|#x G}"|@<= "<`! G8c2x| @@L1K19 H@jGȐH4Kx0} |~x1| }+9A K]x$}#Kx8! |N =`" G,M = " G9#|L +GN = " G,M N = " G,M iGN !|$|}xK8cKAx,|xAK$x8! |N ,M 8cC, @A@D88, M H,#, A| @A#, A|| @@܍#, Ah| P@9c$ 8c|#x|H@4, M $ /|H@M $ |HA, |;xM Kl8`N |`xTcT B|cKxT .|cKxTF>|cxN !|D?#|yx98 ;iIW:x}8||.x>"K97EW}|H.= ";9)EZ| ,x_x|tzx_>x@;;W8|y.;@xxK!W:8E= "}k9)EW| +@;|t,Jx_>_xzxx@;;Wx|y.x;K= "W:8E}k9)E W| ;+,|txJ_x_>zxx@;;W8|y.]x;K9= "W:8E}k9)EW| ;+,|txJ_x_>zxx@98x I}k:|  }JD}x|8!@I N =`"= #9)9kD||8= " GN !|= "4a|#x|~x GT|"}|" G, ?A|dx<`#8c||HX?`#x;; @||KxK-}#CxxK>"cxxK;!xCxK?"K8|lx9u97D||||xCxxGK8xK,@;#x8Km,Ax8aKYy@$s8CxA|zK9qAK;|lxs;!9u97D8||||GACxxH #x8Kp<UU`UV||P|AcxxK<I`$|||p|P|ACxxKs#x8@ CxxKi;K,|lx@4};;8i,A},9i H9l},k 8},T@.}kxU)}hKxU= "9C8A(iF#}CSx| 8})t|t| @H)F| 8}CSx,UѾ8A;,@h 8U= "9J8A(iF#}CSx| 8})t|t| @8H)F| 8}CSx,UѾ8A@ |tT|+x $|8!P} N ,!|= "$|3x|x?#8GA8H9 EP9`| I|P}jY|:} Q|ZH9 9@&F|#x8<!8}X82?#L1K-8}XK}9` }  !@| | Ky@\= "GH 9|`xx,8~XAKy9`H,K8~XH9`,@KQ= "iG$}c[x8! |N !||+xH 8!|N |ix|#x8`8N !|$|x,|xAK8$8`8! |N !|=`"TM49kGATH,Kk|;x|pTH,}Kx||81|xcxx}Cx}=KxKmx,x8`A KE4A8!0|N C9 U X(c UH]~T} xUk]~TX(UJX(8}l[x|cKx9`|Sx|c[x|cxN #8`T~T`T~U)~}*Kx}cx9 T|cKx|SxN 8`TN T`tk0|Ti>T 8/T`.9k|@9 T '8A |`\0= !9)2T>| |t}+}#KxN |@8A4}0|)| @@@AA| @@ @8|xN !|=`#|#x9kp9 }}c|P|kIH98!|N !|= #4a|{x|#xxH4|ix|#x8|0|8}CSx|8a8!0Kd!|D?`#|vx|#x;{p?#xHIx|yx|#x88`H8`;x88Hi0Cx;x8K=`"|ex|#xkG98pA;pxK8`R,T 8@;9)=`#U)x9k})ZD |P8!@N !|= #TD9)p |t,A,APHȀ L=`#= #9kp9)Ԑ (+HHa(KU8l04H?#9=p P0a04;p?"K9|kx|#x9!~G}e[x}cx8<8K9!09,Ax~GX8h8||x}`| A<= "}j[x G8}iphh}kH8}P8}i[xa(HH>hp8`| 8 h@H<=`" G9)U)8h;xp|}J`})Yh(HK<<`#88ctxH!x9<U)8;xH>h})9)>h= #89)pxi`9ki`|ᮀ4A8!0|N !|=#4A9hp?#+9^p8|zx})t @, AAh, A`H, e9 kd!|*`T:jd \H4?"9 |G9@9p?#+K8p8|{x8 H ?p<XD`2B| @h;p|G=cx89)}*Kx9 +KH̀p;| PdH|K= # 9)pp| Pi@ dHX;p8`8Hw)DK19^p9p h ! }(Ih!||Ky@  DK=`#89kpG9 9@ `8(H h4CxA8!0|K|!|= "8889ȀiG迡9!K= XF,9`a)SB@|H@t<#;pT>,@|8!xA00Hdahp;8cpWx?; _$KX8c9` }c[x8!|N !|= #T!|#x|ux u?",@L?G|#x= #9)|JKpGxxh}J`})Y(HH0G+ ~"~p|H@A|H@ $|@@$;`;KmH>`">@#92pGt=]xHt%xFx~xxKI,A||yxHt~p| @A| @| @@ PHx} PK􅃳G92p|{x|#x#xDxHtx|kx|#x~xexx|8PxK)~Gxph}J`})Y(HH|@A|@|@@#xDxxHt ~p| @A| @$| @@x||{Hs|#xHxG,xphP}J`})Y(HA$8:BH y,@K,|}x@,= ")G |qPT!8!P|N !|=`#D|? x+p|~x9kp:9)kptU)6})wxx|In8T6cxxK= #9)p9` ak8 x|K| t, A<"T>9&C| p AH8`| A8`8H<= "9@iG8`9 $+KH, @A8`8= " GH, /@,/AxH;9FC|tk@/,T>WK>|T A| Xh T| H9@88KU|dx9 x,A K |ix, 8@0wxx? | KyA  x]KK-,@8= " G8`]a }a[x|N !|a4?"|~x}FH|+x|#x8x8|3xKFH,A8H9 _P9`| I|P}jY|:} Q|Z $H9 9@& F$?#<!x8828L1K8K9` } ~ !@| | Ky@THdx|`x8,A~K9`H,K%8H9`,@~K= "iG4}c[xa8!0|N |+xH8|ix|#x8`8N !|$|x,|xAKU8$8`8! |N !|= "4a|x|;xIFH|+x|3x :,@89`|| x $8|jx|9 }J})|Y|9|*|:|P|IKx,8dxAK|`x|xa48!0|N = "|#x)FH|`x|+x8(i|K !߰|}&= $  T>"|zxtFH|#x |+x>|3xK,;`,k0;*|xx;A};, AhU`BUi})x;U`.;})xU`F>}>y@l};UiBU`|KxUi.|KxUkF>|[x|A;AH0cx88K8,APT BT })[xT .})[xTF>}>xH0k;UiBU`|KxUi.|KxUkF>|[x|A~W:}a,9 8A9 @8}*9@,@|{88c8|c8KU8,A@dW:;}!)0U+BU |[xU+.|[xU)F>|Kx|AAH$|PT:4FH||8)( ,};9);};8@L= "x)FH~ųx~x~xiK|`x|x  T } 8! P|N !|8 ! $ D?@"8:FH? $;`,xKU8`T BT })[xT .})[xTF>}?x|@@:FH80 >T BT })[xT .})[xTF>})x;88 xK<`!88c3K,@ |@|(!|H@la$;|88 U`BUi})xU`.})xUkF>})[x}?J9)}?8xKq ! | @a$$| @ 9Y`;|P@@U`BUi})xU`.})xU`F>})xU):}=J9)| P@A8}]SxH9@}H,9Ja$U@:}, UiBU`|Kx;Ui.UkF>|Kx9 |[x@|&T@9 | H9@@DU@:9J}! @;!$U+BU |[xU+.|[xU)F>|Kx| @A8|8KXaUi.ZFHTBUkF>|Kx= "|X)G| >!i|kI D! $8! @|N !|88!?";aTD.|Kx 4TD.|Kx :+:, A9J8|P0}(9AK89@paFHUiBU`|Kx4Ui.UkF>|Kx(|[x8(}J0a$9JH|[x,@<`!|;x8c4H(:8 (#U@<`!U$>8c4@H,A4|<`!|88c4h| @Kq8Cxfx8K !?#|FH8U BU#|cx:U .8`|cxU)F>|cKxK,@<`!8c4L1KH@`= "iFH8`T >TD.|Kx 66(@<`!8c4L1KA8H ,@:|3x|e2KǍ8|x!8!|N !|<"$T:?"&FH|#x|}xI:}Ji<8= #G8`|X}$Q:@@x|ApH | Q:&FHx8x:K9`,A@W:T >TD.|Kx|A8GH= "x)FH}*J@$}c[x8! |N !|<#$?"9&`^FH?#9xj:J}+J 8T >TD.|Kx}k}kB|X@4;>FH8i6| T>W:}@JA\ \,A| 8f`AX <|@A :||`H<8j@T>xKU8,AH := #9)h|JH>FHW:9}JJU>T >j\TD.x|KxUh8| T 6})9kj\|hJ9JP@ 8 T BT|cKxT .|cKxTF>|cxK+,8APAt>FH9}x :|Z= "IFHT >TD.j:|Kx= #}k9)`}kJ8j|x$8! |N !|!4?@"? ":FH?`#8|}x6|#xG;`,@T98T >TD.|Kx| (@WBWBWTBWT});x|[x}JCxT.W.|[x})CxTF>WF>|[x})Cx|H@W.}J;xWF>}J;xAX@DdUiBU`|KxUi.|KxUiF>|Kx|P@A(@$ | Ky@98| (ALFH| (W:9l})9)P@9`T 6i |U8});)W>U BU#|cxU .|cxU)F>|cKxK||x8`,A,A=@"9{`*FH9 := #9)x}`Z|J T >TD.|Kx| (@x9(|@\|@P,@D ,@8JFH9`8`*:T >TD.|[x})})B*H8A88`G4!8!0|N !|4!?@"|{xZFH?"8|#xjyxj#G| X@ 4*(I)3@T >TD.| Ky@@#U+BU |[xU+.|[xU)F>|Kx9 | @A4| @@|@H 8cH |@A|@ |@@:FHiKHdG,@h?@"zFHk #| @L 4+(@T >TD.| Ky@8T BT })[xT .})[xTF>})x}*Kx9 }J})H8cH }D}#:FH; 4i(T >TD.|Kx@T >TD.| Ky@,# U+BU |[xU+.|[xU)F>|Kx,H8cHa,@8|@@0P|@@x:FHcxx|K)HzFH 4(@kT >TD.| Ky@0+) U+BU |[xU+.|[xU)F>|Kx,H8cH,@:FHW 8}}0|@@= " FH(8H:hL08 U):})X.8PPU+BU |@|[xU+.U)F>|[x|Kx@xhxgxK-= "QiFHx9 { h}J`})Y(HAKXK}= " GK= "|yP G,A8`4!8!0|N !|(t9>"<G|~x=a}sxK9 ,Ad> "9`QFHakT >TD.|KxT&|X@!:@9), !@9 8Hȁ*J }IT >TD.|Kx,@  8 8Vs VVV~x~x V@.~֣xT@.~x |xVV>V.~sxU@.UIV9U>T9@})[x}JcxTF>~xVc>8T@.U}exV|.Tk;T>});x}JCxT@.}dx})+xW@.}J3xTc>WF>}}xVz})x}J#xWF>W[>Vx})x}Jx;@WF>})x}Jx;}+x}LxH,?U+BU |[xU+.|[xU)F>|Kx9`| x})i $,A<= "T>9)C| p @$:R|,T >A| Xp AqFH~Jx~Ipk$k }P}kI( A, @( @9 8H́1FH;8x)i$|K9@qFH9   (HKa,A<1FHx)$K1FH|kp) |X@ $|A9 8H8<x=,/A!}{x!K܈| t, A<"T>9&C| p A8`|A9 8Hȁ*9@ 9 >^T >TD.|Kx,@  8 8Vs VVV~x~x V@.~֣xT@.~x |xVV>V.~sxU@.UIV9U>T9@})[x}JcxTF>~xVc>8T@.U}exV|.Tk;T>});x}JCxT@.}dx})+xW@.}J3xTc>WF>}}xVz})x}J#xWF>W[>Vx})x}Jx;@WF>})x}Jx;}+x}LxH,?U+BU |[xU+.|[xU)F>|Kx9`| x1FH~ $aiK|ixHx, /@,/AT&x,@A9 8GHD;9FC|tj/,T>V>|T A| Xh T| H9@8K9 ,A>"TFH* |p@ )T >TD.|[yU >jU)D.})x}|[xJ@x< tFHTz,_U >kU)D.}Zt})x~J~ijxA8KE_,A,6~߳x;AKD89 G울H(}sxxKt}#Kx(8!p|N !899!!$}cD}iE8`T`WW>W.WU@.T>9UI9@cxW>})[xTF>}JcxTT@.W.ex})x}J#xT@.U>T}J3x|xT>Uf@.UF>})+x|x});x}JCxWUkF>})[x}JcxWT>8UlF>});x}JCx9`}Jcx})[x!AT'>WC>!$8!@N !899!!$}cD}iE;WAaW}Wj>Wl.WfU@.W>9UI9@<xWG>})[xTF>}JcxWT@.WK.%x})x}JxT@.U>T}J3xxT>Uf@.UF>})+x|x});x}JCxWGUkF>})[x}JcxWKT>8UlF>});x}JCx9`}Jcx})[x!$!A8!@T>N ,8+A0,/A 8H,8A8A8|xN !@|!Aa|3x|}x|#x|+x|;x}Cx}:Kxdx8H);|y@!8U)&`| Az8`Hx,;@<`+`c@H,,Ad}KŅ|~x<+1>})I`F}?9@|}8#8 x|N!|yAxKƁHHxH88Ax$xxx~x9H,|xA xK9x|!Aa8!N !|!$A(a,048<D |3x||x,/|#x|;x}Cx}=Kx}YSx@a ;;7x8A;,/A 78Ad;,/@,AL xx9H1|cy@L xdxGxx9! K|cyA|H !H aL8` D|!$A(a,048<8!@N !|!$A(a,048<D};Kx9!}^Sx8! |x|#x}Cx!Hhxx9AKq|cy@x,@ H\;xxxH0|cy@@,A,xxgxxxK|cy@8`D|!$A(a,048<8!@N !|Aa $(,4|}x=<+`| |#x|+x|3x|;xA<`+`cHh}K|x<+0|c`F|c9@DxK|gxxexx99 xAxKQ|}xxK x4|Aa $(,8!0N !|Aa $(,4|}x=<+`| |#x|+x|3x|;xA<`+`cHh}K9|x<+0|c`F|c9@DxK|gxxexx99 xAxKm|}xxK)x4|Aa $(,8!0N !|Aa $|}x=<+`| |#x|+x|3x|;xA<`+`cHX}KU|x<+1?})I`F}#9@4xxfxIxx8xK|}xxKUx$|Aa 8! N !| !Aa $(,4|3x=p p|yx|#x|+x;`;@0}}#Kx8}h$x8~x~ȳx=(N!|{x,A s`A( Jxp}P}gI} H=i |@@ |@@<+`5ccH p A}8KH$i8# |N!},A ccH4= p AD,@8^x_7U@F>UI.UKB|Kx|[xUJ|Sx;@Ԁp ;Ap;H(} ;1L}+=] ;;|@}}x}h x=(N!p`xAHx;H(;} ;1L}+=] ;|@H,AЁ}}x}h x=(N!p`xAc{= p @s Ap @c|AD,@8^x_7U@F>UI.UKB|Kx|[xUJ|Sx;@ԁ=i8# |N!0|x`8|Kx}T|,@8s`@0}8$x}h~x~ȳx=(}8N!{xcx4| !Aa $(,8!0N !| !Aa $(,4|3x}+p };p|yx|#x|+x;@;@0}c[x}8$x}h8~x~ȳx=(N!|zx,A s@A,|ր | x| p}P}gI} H=i |@@ |@@<+`6cCHX p A} 8K H$i8# |N!},A cCH= p AD, @8~x_7U@F>UI.UKB|Kx|[xUJ|Sx;@Ԁ p ;AD;H;;;|@xxxK]p`xAHp;H;;;|@X,@( jxip}P}gI} KĀxxxKp`xAZx= p @s Ap @c\AD, @8~x_7U@F>UI.UKB|Kx|[xUJ|Sx;@ԁ=i8# |N!0|x@8|Kx}T|,@8s@@0}8$x}h~x~ȳx=(}8N!ZxCx4| !Aa $(,8!0N !| !$A(a,048<D|3x}+p }:p|xx|#x|+x; :@0}c[x}8x}h8~dzx~x=(N!|yx,A s A0||ր | x| p}P}gI} H=i |@@ |@@<+`7c#H\ p A}$8KuH$i8#$ |N!},A c#H= p AD,$@8^x_7U@F>UI.UKB|Kx|[xUJ|Sx;@Ԁ$p ;AD;H;;;|@xxxKp`~xAHtz;H;;;|@X,@( jxip}P}gI} KĀxxxKp`~xA9x= p @rAp @c<AD,$@8^x_7U@F>UI.UKB|Kx|[xUJ|Sx;@ԁ=i8#$ |N!0|x 8|Kx}T|,@8s @0}8x}h~dzx~x=(}8N!9x#xD| !$A(a,048<8!@N !|}& !Aa $(,4|{x;<+`| |#x|+x|3x|;x}Cx:;@A<`+`cHHs AHcx~ijx8HHY,a@$H:T&,@A<`+,`cR@cx~ijx8H|iy@\9 -9@|p̑!БAԓaȒ!@4T<|cK<+1#})I`F})9aA}#KxH!{})| ! H,@ls @dcx~ijx8HHi,a@l:,A8a8cx}h8l889~xN!|zxs@@ds ;;Nx;|.,@A8acxx}hЀ8x~xN!Zxs@@!ЁA;, 1}i;;aБ@8,@ s A(8a888 8KZxs@@H x p}P}kIaБԀ<,@ s A(8a<88 8KZxs@@XH(|րЁ| x| p}P}gIaБԀ@,@ s A8a@888K1Zxs@Ad,;H@xcx~ijxH|iy@8| 9Ap9a9 | X.| Q.9)Bcx~ijxxHa|iy@@aKWCz|cЀ|cp|84| !Aa $(,} 8!0N !| |3x|N!|8!N !|$ <!8``9K$|8! N |cy@ 8`N ,A}##| !|@ }#KxK8`N !| #|#x d8`p ALx8K,@,x8K,@x8Kq,A 8`H8`| 8!N !|Aa $|zxz|#x# ,AzT,@\ 8|N!zx#8 8|N!:|}xi}#Kx |N!xH;;}>.|.| Ax;,;zA<}>.|.| A,};,9k;A}+.| .| @#|R |P|"|T<8N!|}y@h;,;@hzTx8L1K8`$|Aa 8! N C L,L 89` 9 *X LjTN !| !$A(a,048<D||x<<+`| :A<`+`cHL<8`:K}<i0|Zp @A8`K}?+|wx0|cF|9@Ā| |`KQ|vx0||9@ 8|)K-;`8~xL1K~޳x~xH"$|@@p?_ >~^ ?_>~^xH);{; |@; AH $x~xK|zy@؁< `p @Ƞ :T< :<q+@A ~x8L1K~xH!I<p ):@|@;@xxK,A+|O|&T|| qj@8U)>|KxAT>T D.T>})x7ZH < Z,A,|$x#8 ~x|N!|zy@؀p @d ;`|@~ݳx@P;|x#8 x|;N!|zy@ x<|@;JA<; |@9A<8 Z<,Ax|N!|zy@(|T# |N!|zx<:p @A$,A ~xK,A ~óxKCxD| !$A(a,048<8!@N !| |x?<+`| A<`+`cHLp AxK|cy@0<,Ax|N!|cy@xH8`| 8!N !| |yA?<+`| @,A# |N! ,AK8 ,AKm8T,AKU8T$,AK=8$0,AH9,,AHH,AHـL;,HAH%,AH9xKр| 8!N !| |yAP?<+` | @<;,A Kq,A K]xKQ| 8!N !||cyA(#<+` | @<+` KM|8!N !||cyA(#<+`| @<+` K|8!N !| |x?;,@8,A Km,A KYxKI| 8!N !| |x?<+`| @, ,AK8 8 xK| 8!N !| |yAd?<+` | @P,AK8?9`, A L|@iL8xKU| 8!N #, @ 8`N 9@| @089c9J+|I.c9 | A8`N !|a $|x8`,@8`Ke?+|ix0 |c޷F|8y?@}#Kx88L1K1K!0||9}AKMcxH?8i9 _8 ?  T(4|cTc:K0||9}@xK8`H$}K͓}Kx$|a 8! N !|a $|}x=<+`| |#x|+xA<`+`cHH,@844x8HH,A}H,A KH48``K|x<+0|c`F|c9@\x88`L1K<+`= L,A )XH9 8?(0=,9)?A H 8 _? $U)(4})i  *?+i(c޷F (}|hK0||99 ?@$?8?<+`| |#x|+xA<`+`cH@,A(|xDxexN!<+`A|@\,@xK|cy@@>9` }&Kx| @,| x|#x |A\9k| P8A,A> }'Kx|@@<`+`c)H؀p ApL,AX|H|pT>~||>p9Z} >X|ցi } PP#LB,AXHpU=80Hh(9z} |ց'L}@XP, AXHU]80$U (4})g,9k \0@<`+`c;H|A4~#x 8|N!|cy@ȁ>~^ 9 })0 9)H8 8cx8L1KL,;AX!}kY}k[>}`XIT0X8}x9 }%P0||(@@(P$xxcxL1K;~~# x8|PN!|cyA>8 H܁>|{~xL1KmH(cx88H$xxcxL1KEp Axdxex8Hy~dx+K 9)| S|Q} HP+^8  T (4})U):IA.~ +T(4|cTc:|cJ8cL1K8`4|!Aa $(,8!0N !`|Aa|x?<+`| |#x|+xA<`+`cHD,A(|xxxN!<+`A|@,| xAP99`H 9k9 |@@*| H.|kJ|@8cx8L1KHxK|cy@q`@<`+`cHh,A? |@@<`+`c)HDq`@Axx88HHx8a8L1K-?9} (IL}%Kx}+| , |XPAXHT80$U)(4}),8 0@<`+`c;H_9 eL})@09) , H8@:;AXx !;})I})K}+H|iH8Uk0}>[xA4#x 8|N!|cy@ ??9@ }}}J0| P@@}PPPH;;xexCxL1K# x8|N!|cy@,A#; x|8N!|cyA?8 H`?|xkL1K]#x 8|N!|cy@8``|Aa8!N !`||x?<+`| |#x|+xA<`+`cH? |@@<`+`c)Hl4,A$x|xxN!,8`A@xx8K|cy@(8| 9a09 | X.| .9)B8`|8!N !p||x?<+`| |#xA<`+`cH? |@@<`+`c)Hh8,A$|xxN!<+`A|@<xx8K|cy@$a<+Tc&hc@|c|cp`J|c8|8!N !| |~x|;x|8`@<8K,@$8` ? 9)? H8`| 8!N !|$#<+`| |;xA<`+`cHP8 <!}&Kx889H|cy@<`+0|`cL|8$|8! N !| !Aa $(,4|;x:<+`||x| <`+|#x|+x|3x}Cx`c@8`KA?+|}x0|c޷F|9x@88xL1K<+`x8|WN!|y@D=x\Ku8cK0||9} @xK~8`K0||9}@s At8`LK}|fx0||9X@̀}8#8 |N!|y@X<+$`| A<`+`cH;`,A@,@?+cGH`}~x#;; |N!8THH}8#;` ; |N!8`K<+1#})I`F}?9}T@}dx#8 |N!|y@̀}T,A8L1K~̀}=8,SA q @Aa @H9}8+8`S| A?+cHd L(@?+cHLs@T `T 7@<+`| |#xA<`+`cH,@\x88K|cy@a$( A$>} pTM})})Np}+K8H8xHA|cy@D;9 <!?x8888xK|cy@|8!N !|!Aa  !$A(a,048<D4d6TF>h8l CTF>$U .UF>0W.UJF>}HW.CWF>T.TF> T.TF>TF>HT.$ TF>T$T.T.,U.(0|cx|}  |sx}{xT.} US.T F>W.T.WF>TF>$0<HTx|x|ԣx|x}xA(a4@XL }Jx}kx})xTBWBTBTBUB $xރxWBTBTB:(,0޳xTBUB (|x}xxTBӛx` a,TB4@LXWBxx|x|x|{xA8!DP\ W`$T0}JsxWTd,});xTWhTUW T>}kcxWTD.(T>TTD.lU||x|ƓxWcT>TD.}x|x#  }x,x|{x8VD.|sxD})x|cxP~x}x# \~x}Jx}kxV>C(c,#0468|x:<|x@LDHTC$p|>UF>tCPARUF>XTF>Z|\T.UF>`\WF>Ā`W.T.ȀdU.TF>ԀdT.؀ȀT.䃣W.WF>|x|׻x}x؀ԑU.ԣx|3xVBUBTF>ܑx\|xTB`ȃ}k;xTBT.dV.UBWBVF>xTB}xU.UF>})xx| }Jx;x샡pTB|TF>̀|CxWD.ޫxUBUB} x|x|ԣx|xU}JxВatWD.`WD.WD.\WTD.WWD.dWWW}kxptW>W>W>W>})xW>W>|xWB|U{xVD|xU|sxH|ғx~x|xTЃ|Cx`~x;x||;xd|xU}}Jcx}kCx})x|xxW|xCLcȑ#ಃ@CPRXZ\#U F>U+.U*B|[x|SxU)|KxD|!Aa  !$A(a,048<8!@N !a T.T.T.TF>TF>TF>}J;x})Cx|[x cTBTBTB}JCx})[x|;xWD.WD.WkD.TTTW>W>W{>}J3x})+x|#x}x|x}kxcC# a 8! N ,9`AT&h !+}iYT D.T>})x$@ U)&i)})})p8 }iH8}+x%, U D.U)>|Kx%U+.U F>U*B|[x|SxU)|Kx%U+.U F>U*B|[x|SxU)|Kx% U+.U F>U*B|[x|SxU)|Kx %U+.U F>U*B|[x|SxU)|Kx%U+.U F>U*B|[x|SxU)|Kx%U+D.U)>}kKxdT D.T>})x$eUi.U`F>UjB|Kx|SxUk|[x% U F>U+.U*B|[x|SxU)|Kx A,AH8| 8(8(9}H0.U@F>UI.UKB|Kx|[xUJ|Sx|9.9BH0|(A(8| 9D(9e(9 | X.| Q.9)B%dU+.U F>U*B|[x|SxU)|Kxd%hU+.U F>U*B|[x|SxU)|Kxh%lU+.U F>U*B|[x|SxU)|Kxl%pU F>U+.U*B|[xU)|Sx|Kxp#iH,A(A,AN %$U+.U F>U*B|[x|SxU)|Kx$%t$teuduvT D.T>})x$vxT D.T>})x$xzT D.T>})x$ze|U`F>Ui.UjB|Kx|SxUk|[x|N %$U+.U F>U*B|[x|SxU)|Kx$%t$teuduvT D.T>})x$vexUi.U`F>UjB|Kx|SxUk|[xx%|U F>U+.U*B|[x|SxU)|Kx|N !|Aa $|}x|#x|+x|3x8`K~?+|x0|cc޷F|c9@x88L1Kl<+,`@ 8 Tc:K},0||ix|8 @xK~xH@,A }#KxdxT:L1KlH8T:KlE8`$|Aa 8! N !||fx|#x88K|8!N !| |x|#x xKy|cy@>8` | 8!N !| |x?<+`| |#xA<`+`cHT?|HAL8 d T:K||cy@<`+`cFH  8`,A?9)?H? , }*Kx9 A(U :})X.}`[x| @ 8`H| @@UI:Y.8 K}GSx9|8|;x| x@H |A|@@ 8H,9|X9)@ |A|@@}Cx}HSx|8T:@(U :? 9}jJ |8| I.9JA 8`Y.?9)?| 8!N #<+`| @#, @ 8`N c 9I|kx|9AUI:| X.|@ 8`N |P@xU@| | q} &U)HLUi:| .|A|@@ }j[xH}h[x|P@4|RT |J| p}iBx } I}`Rx |}'yA8`N !| |x?<+`| <`+|#x`c@H8` Ky<+1#})I`F})9@$<+`#~8`H}#Kx| 8!N #<+`| @4c<++`| @C | A88`N k UI:| X.9JC8`N !||cyA$#<+`| @8Kz|8!N !|#<+`| @|HA<`+`cH4|@ c T:Ki |`H8`|8!N !|}&!4A8a<@DHLT0|~x><+`| <`+|#x|+x|3x|;x}Cx`c@xKI|y@.a @,~Kw<+1#})I`F}?9aA H`8<!A! xx8L889Ke|x@aKx,@ a HxT0|!4A8a<@DHL} 8!PN !| !Aa $(,4,|yx|#x}?Kx;;`;@;@ 8`H|+x| p}ix})XP})pU)a=#xH,A8`Hh;H4|(@(~|Z|(A$( @q`@>9)| X@<+`#8`H|.,@p A ,A x|xN!|{xHX,AL|+x||3xx?xxN!/9=|{x|&T|})x8|Kxs`9:Os`|&T|})x@8O|Kx@|(A,A$#xH,8`@W<4| !Aa $(,8!0N !| |x|+x#8 x|N!|cy@?x}%J9)T2|H@|T@/<+}$Kx`Ʒ#APEU@.UKF>UIB}kx}kKxUD.TD.UJU>T>}kSx|Cx});xe%| xT>(@ p A<`+8`c#%|9)X| @O|&T||x|`8|KxAX| 8!N !|a $|}x|#xp @|+x;AԀ}KsM|~x<+1>})I`F}?9@耽xxL1Kbxx|| @@E|+x( @ q@A?+c#HfU`.UiF>})xU`B|R})xU D.TD.UkU>T>| @})[x}JCx|;x&FAHx}x#dx 8|N!|x,A xKsx$|a 8! N ,  !|ix|#x/A$|}H,0|`0@|k,0} x}c[x}cx8! N 9`|l<0K,  !|ix|#x/A$||h(0}@0@}L(0} x}c[x}cx8! N 9}K80K,!Г;!Aa $(,A4,A|+y|x|#x@|@@|4,A  80|0|80}?x|80TDŽ>T>|;Tk>} 9|x}@!} PU|[x|P@@$}28|0@A|P@@ 8}2} @PTk>|;} 9|x}@!| @PT|[x|P@@$|28|0@AP@|&T|8PT8|;x,|+x|#xxxA |c!Aa $(,8!0N ,@ 8|3|4,@T>P8Tń>|+Tk>} )| x}@} PU|[x|P@@$}29|0@A|P@@ 9}2} @PTk>|+} )|x}@| @PT|[x|P@@$|28|0@AP@|&T|8PUK!G |80T0Tń>}d+|iT080|KxT>|c80W>:x|+x}+)}{[x}| PT|Sx|`@@$|2;k|0@A|`@@ ;{|2|8PW>|C} A| x}} 8PU|[x|`@@$}29J|0@A|`@@ 9J}2W`@P|SxK| @88A}4,@0|`||}&9 })I| Ky|&T K!G }80|T0T0},x|jT0U>80}d+U>|Sx|c80|80W>}+)}{[x}K| PT|Cx|P@@$|b;k|`@A|P@@ ;{|b|8PW>|+} )|x}@|8PT|[x|P@@$|b8|`@A|P@@ |b8W`|8P|+x|0|8@}%1A$|:x!`| })})I})| H9A88K |K; |cK,!: !$A(a,048T>| ST˄>} Q|!} `PU|[x|8@@}*|(@A|8@@}*}@PT>|S} Q|!| @PT|[x|8@@|*|(@A|8@@|*,|P|0;A ,A!A !}ia a  !$A(a,048<8!@N ,@ 8|+|4,@dT>}`PT>| T˄>} |} `PU|[x|8@@}*|(@A|8@@}*}@PT>|} |K#[ |0}0T>}g|0}0| KxT>U>?x|0|hx}+||8PT|Sx| @@|*|(@A| @@|*|8PU>|C} A|| 8PT|[x| @@|*|(@A| @@|*}PK|@@|#x||x Kd4,@@|||}% 9 })I| KyA}e }}f[x,|3x}cxK#[ 0|0|g0}?x|j0W>W>}g#|0}LxU>|0|0}+!}y[x|k|8PT|Cx|@@$|;+|@A|@@ ;9||8PU>|#} !| x|`|8PT|[x|@@$|9J|@A|@@ 9J|| PW |Sx|(| @}`)A$|"x! | }+0})I})| H9A|X|9| x,A}+0}!}0})0}0|KxK |K: |cK|+y!|3x|#x,|x!Aa $(@|@@|4,A  |i80|0|80}?x|80T>T>|;T˄>} 9| x}Q|iPT`|[x|@@@$|c*9|(@A|@@@ 9|c*|hPT>|;} 9|x}Q| PT|[x|@@@$|*8|(@A@@|&T|8PU9@|;x|}x}\Sxxx!Aa $(,8!0N ,@ 8|+|4,@T>P9@T>|#T˄>} !| x}|iPT`|[x|@@@$|c*9|(@A|@@@ 9|c*|hPT>|#} !|x}| PT|[x|@@@$|*8|(@A@@|&T|8PUK!G |80T0T>}c#|T080|KxT>|80W>;x|#x}+!}h[x}|PT|Sx|`@@$|*9 |(@A|`@@ 9|*|8PW>|Ӗ} | x}|i8PT`|[x|`@@$|c*9J|(@A|`@@ 9J|c*UP| SxK| @9@8`A(}4,@0|`||}% 9 })I| Ky|`&Tc cK!G }80|T0T0},x|T0U>80}c#U>|Sx|80|80W>}+!}{[x}K|PT|Cx|P@@$|b;k|`@A|P@@ ;{|b|8PW>|#} !|x}@|8PT|[x|P@@$|b8c|`@A|P@@ |b8cW`|8P|x|(|8@|)A$|:x! | }%0})I})| H9A8c9@K!|lx<|+y|3x :!$|#xA(a,048@0|@@|4,A  |i0|0|0},x|0T>T>| ST˄>} Q|!} `PU|[x|8@@}*|(@A|8@@}*}@PT>|S} Q|!| @PT|[x|8@@|*|(@A|8@@|*,|P|0;A a  !$A(a,048<8!@N ,@ 8|+|4,@dT>}`PT>| T˄>} |} `PU|[x|8@@}*|(@A|8@@}*}@PT>|} |K #[ |0}0T>}g|0}0| KxT>U>?x|0|hx}+||8PT|Sx| @@|*|(@A| @@|*|8PU>|C} A|| 8PT|[x| @@|*|(@A| @@|*}PK|@@|#x||x K4,@@|||}% 9 })I| KyA}e }}f[x,|3x}cxK4#[ 0|0|g0}?x|j0W>W>}g#|0}LxU>|0|0}+!}y[x|k|8PT|Cx|@@$|;+|@A|@@ ;9||8PU>|#} !| x|`|8PT|[x|@@$|9J|@A|@@ 9J|| PW |Sx|(| @}`)A$|"x! | }+0})I})| H9A|X|9| x,A,}+0}!}0})0}0|KxKbootargsDefault supplied on the command line: %s timeoutboot: single-key %srestrictedimageTo specify arguments for this image you must enter the password.This image is restricted.help Press the tab key for a list of defined images. The label marked with a "*" is is the default image, press to boot it. To boot any other label simply type its name and press . To boot a kernel image which is not defined in the yaboot configuration file, enter the kernel image name as [[device:][partno],]/path, where "device:" is the OpenFirmware device path to the disk the image resides on, and "partno" is the partition number the image resides on. Note that the comma (,) is only required if you specify an OpenFirmware device, if you only specify a filename you should not start it with a "," If you omit "device:" and "partno" yaboot will use the values of "device=" and "partition=" in yaboot.conf, right now those are set to: device=%s partition=%d haltRestricted command.byeOpenFirmware commands are restricted.To boot a custom image you must enter the password./vmlinuxinitrd/root.binsysmap/boot/System.mapblackbluegreencyanredpurplebrownlight-graydark-graylight-bluelight-greenlight-cyanlight-redlight-purpleyellowwhiteType go to continue. Can't claim malloc buffer (%d bytes at 0x%08x) device_typechrpmodelIBMpartition/etc/yaboot.msg%s: Unable to parse %s:%d,%sCan't alloc config file buffer /etc/yaboot.confCan't open config file Error, can't read config file Config file read, %d bytes Syntax error or read error config init-codepasswordfgcolorInvalid fgcolor: "%s". bgcolorInvalid bgcolor: "%s". %x to background-color %x to foreground-colorinit-messagemessageboot: %sliteralrootroot=read-onlyread-writeramdiskramdisk=initrd-sizeramdisk_size=novideovideo=ofonlyappendpause-afterpause-message %s Password: $1$Incorrect password. Try again. ___________________ < Permission denied > ------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || reset-allPlease wait, loading kernel... \\ Can't read Elf e_ident/e_type/e_machine info Elf32 kernel loaded... Elf64 kernel loaded... %s: Not a valid ELF image Loading System.map ... malloc error Claim failed for sysmap memory System.map loaded at %p, size: %lu Kbytes System.map load failed ! Malloc error Loading ramdisk... Claim failed for initrd memory Claim failed for initrd memory at %p rc=%p ramdisk loaded at %p, size: %lu Kbytes ramdisk load failed ! yaboot Can't read Elf32 image header Can only load kernels with one program header seek error read error Can't find a loadable segment ! Claim error, can't allocate kernel memory Read failed Can't read Elf64 image header Read error interpret" _screen-ihandle" $find if execute else 0 theninstance-to-packagedisplayopenscreenNo screen device found !/nbootpathboot-deviceCouldn't determine boot device \Welcome to yaboot version 1.3.13 Enter "help" to get some basic usage information ptypewarningI_know_the_partition_type_is_wrong_and_will_NOT_send_mail_when_booting_breaksApple_Bootstrap WARNING: Bootstrap partition type is wrong: "%s" type should be: "Apple_Bootstrap" Bye. call-methodmethod '%s' failed %p finddevicefind-packagegetpropblockcan't get for device: %s networkUnkown device type <%s> /chosen/optionsstdout Can't open stdinmemory Can't get mem handlemmu Can't get mmu handlehex : D2NIP decode-int nip nip ; : GPP$ get-package-property 0= ; : ^on0 0= if -1 throw then ; : $CM $call-method ; " /chosen" find-package if dup " memory" rot GPP$ if D2NIP swap " mmu" rot GPP$ if D2NIP else 0 then else 0 0 then else 0 0 then value mmu# value mem# : ^mem mem# $CM ; : ^mmu mmu# $CM ; closeread 10 mswriteseekloadblock-sizeEOF on console %s: Unexpected End Of File %s: No such file or directory %s: Seek error %s: Input/output error %s: Path too long %s: Not a regular file %s: Not a directory %s: Unknown or corrupt filesystem %s: Too many levels of symbolic links %s: File too large %s: Filesystem busy %s: Unable to open file, Invalid device %s: Unknown error  color!exitclaimreleasemapsetpropcan't set args millisecondsenterethernetenetbootpWARNING ! default_read called ! WARNING ! default_seek called ! WARNING ! default_close called ! defaultsCan't read partition %d LinuxCD001Can't read volume desc block %d Can't read boot blocks Can't read boot block %d Can't read partition block %d Amiga partition table corrupted at block %d block type is not partition but %08x block checsum is bad : %d partition table is looping, block %d already traveled :0Can't open device <%s> block_size %d not supported ! ISO9660 disk No supported partition table detected defaultinitrd-promptlabelaliasConfig file error: near line %d in file %s Config file warning: EOF in quoted stringBad use of \ in quoted stringnewline is not allowed in quoted stringsQuoted string is too long\ precedes EOFToken is too longSyntax errorValue expected at EOFSyntax error after %smalloc error in cfg_set '%s' doesn't have a valueValue expected for '%s'Duplicate entry '%s'*%s %sbuilt-inbuilt-in network:%02d,Can't claim memory for TFTP download ext2linux I/O Managerext2: i/o error %ld in read iso96600123456789abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZBBBBBBBBBBBBBBBBBFF"GGD|GC