PNG  IHDRxsBIT|d pHYs+tEXtSoftwarewww.inkscape.org<,tEXtComment File Manager

File Manager

Path: /proc/self/root/lib/python3.9/site-packages/up2date_client/

Viewing File: hardware_gudev.py

# Copyright (c) 2010--2016 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
#

try:
    import gi
    gi.require_version('GUdev', '1.0')
    from gi.repository import GUdev
    gi_gudev = True
except (ImportError, ValueError):
    import gudev
    import glib
    gi_gudev = False

import os
import re

from hwdata import PCI, USB

def get_devices():
    """ Returns list of dictionaries with keys for every device in system
        (values are provide as example):
        'bus' : 'pci'
        'driver' : 'pcieport-driver'
        'pciType' : '1'
        'detached' : '0'
        'class' : 'OTHER'
        'desc' : 'Intel Corporation|5000 Series Chipset PCI Express x4 Port 2'
    """
    # listen to uevents on all subsystems
    if gi_gudev:
        client = GUdev.Client()
    else:
        client = gudev.Client([""])
    # FIX ME - change to None to list all devices once it is fixed in gudev
    devices = client.query_by_subsystem("pci") + client.query_by_subsystem("usb") + client.query_by_subsystem("block") + client.query_by_subsystem("ccw") + client.query_by_subsystem("scsi")
    result = []
    for device in devices:
        subsystem = device.get_subsystem()
        result_item = {
            'bus':      subsystem,
            'driver':   device.get_driver(),
            'pciType':  _clasify_pci_type(subsystem),
            'detached': '0', # always zero?
            'class':    _clasify_class(device),
            'desc':     _get_device_desc(device),
        }
        if result_item['class'] is None:
            result_item['class'] = 'OTHER'
        if result_item['driver'] is None:
            result_item['driver'] = 'unknown'
        if subsystem == 'block':
            if device.has_property('ID_BUS'):
                result_item['bus'] = device.get_property('ID_BUS')
            result_item['device'] = device.get_name()
            if device.get_devtype() == 'partition':
                # do not report partitions, just whole disks
                continue
            if device.get_property('DM_NAME'):
                # LVM device
                continue
            if device.get_property('MAJOR') == '1':
                # ram device
                continue
            if device.get_property('MAJOR') == '7':
                # character devices for virtual console terminals
                continue
            # This is interpreted as Physical. But what to do with it?
            # result_item['prop1'] = ''
            # This is interpreted as Logical. But what to do with it?
            # result_item['prop2'] = ''
        elif subsystem == 'pci':
            pci_class = device.get_property('PCI_ID')
            if pci_class:
                (result_item['prop1'], result_item['prop2']) = pci_class.split(':')
            pci_subsys = device.get_property('PCI_SUBSYS_ID')
            if pci_subsys:
                (result_item['prop3'], result_item['prop4']) = pci_subsys.split(':')
        elif subsystem == 'usb':
           if device.has_property('ID_VENDOR_ID'):
                result_item['prop1'] = device.get_property('ID_VENDOR_ID')
           if device.has_property('ID_MODEL_ID'):
                result_item['prop2'] = device.get_property('ID_MODEL_ID')
        if device.has_property('ID_BUS') and device.get_property('ID_BUS') == 'scsi':
            if device.has_property('ID_PATH') or device.has_property('DEVPATH'):
                if device.has_property('ID_PATH'):
                    path = device.get_property('ID_PATH')
                    m = re.search('.*scsi-(\d+):(\d+):(\d+):(\d+)', path)
                else: # device.has_property('DEVPATH')
                    path = device.get_property('DEVPATH')
                    m = re.search('.*/(\d+):(\d+):(\d+):(\d+)/block/', path)
                if m: # do not fail, if regexp did not match
                    result_item['prop1'] = m.group(1) # DEV_HOST
                    result_item['prop2'] = m.group(2) # DEV_ID
                    result_item['prop3'] = m.group(3) # DEV_CHANNEL
                    result_item['prop4'] = m.group(4) # DEV_LUN
        result.append(result_item)
    return result

def get_computer_info():
    """ Return dictionaries with keys (values are provided as example):
        'system.formfactor': 'unknown'
        'system.kernel.version': '2.6.18-128.1.6.el5xen'
            'system.kernel.machine': 'i686'
        'system.kernel.name': 'Linux'
    """
    uname = os.uname()
    result = {
        'system.kernel.name': uname[0],
        'system.kernel.version': uname[2],
        'system.kernel.machine': uname[4],
    }
    return result

#PCI DEVICE DEFINES
# These are taken from pci_ids.h in the linux kernel source and used to
# properly identify the hardware
PCI_BASE_CLASS_STORAGE =        '1'
PCI_CLASS_STORAGE_SCSI =        '00'
PCI_CLASS_STORAGE_IDE =         '01'
PCI_CLASS_STORAGE_FLOPPY =      '02'
PCI_CLASS_STORAGE_IPI =         '03'
PCI_CLASS_STORAGE_RAID =        '04'
PCI_CLASS_STORAGE_OTHER =       '80'

PCI_BASE_CLASS_NETWORK =        '2'
PCI_CLASS_NETWORK_ETHERNET =    '00'
PCI_CLASS_NETWORK_TOKEN_RING =  '01'
PCI_CLASS_NETWORK_FDDI =        '02'
PCI_CLASS_NETWORK_ATM =         '03'
PCI_CLASS_NETWORK_OTHER =       '80'

PCI_BASE_CLASS_DISPLAY =        '3'
PCI_CLASS_DISPLAY_VGA =         '00'
PCI_CLASS_DISPLAY_XGA =         '01'
PCI_CLASS_DISPLAY_3D =          '02'
PCI_CLASS_DISPLAY_OTHER =       '80'

PCI_BASE_CLASS_MULTIMEDIA =     '4'
PCI_CLASS_MULTIMEDIA_VIDEO =    '00'
PCI_CLASS_MULTIMEDIA_AUDIO =    '01'
PCI_CLASS_MULTIMEDIA_PHONE =    '02'
PCI_CLASS_MULTIMEDIA_OTHER =    '80'

PCI_BASE_CLASS_BRIDGE =         '6'
PCI_CLASS_BRIDGE_HOST =         '00'
PCI_CLASS_BRIDGE_ISA =          '01'
PCI_CLASS_BRIDGE_EISA =         '02'
PCI_CLASS_BRIDGE_MC =           '03'
PCI_CLASS_BRIDGE_PCI =          '04'
PCI_CLASS_BRIDGE_PCMCIA =       '05'
PCI_CLASS_BRIDGE_NUBUS =        '06'
PCI_CLASS_BRIDGE_CARDBUS =      '07'
PCI_CLASS_BRIDGE_RACEWAY =      '08'
PCI_CLASS_BRIDGE_OTHER =        '80'

PCI_BASE_CLASS_COMMUNICATION =  '7'
PCI_CLASS_COMMUNICATION_SERIAL = '00'
PCI_CLASS_COMMUNICATION_PARALLEL = '01'
PCI_CLASS_COMMUNICATION_MULTISERIAL = '02'
PCI_CLASS_COMMUNICATION_MODEM = '03'
PCI_CLASS_COMMUNICATION_OTHER = '80'

PCI_BASE_CLASS_INPUT =          '9'
PCI_CLASS_INPUT_KEYBOARD =      '00'
PCI_CLASS_INPUT_PEN =           '01'
PCI_CLASS_INPUT_MOUSE =         '02'
PCI_CLASS_INPUT_SCANNER =       '03'
PCI_CLASS_INPUT_GAMEPORT =      '04'
PCI_CLASS_INPUT_OTHER =         '80'

PCI_BASE_CLASS_SERIAL =         'C'
PCI_CLASS_SERIAL_FIREWIRE =     '00'
PCI_CLASS_SERIAL_ACCESS =       '01'
PCI_CLASS_SERIAL_SSA =          '02'
PCI_CLASS_SERIAL_USB =          '03'
PCI_CLASS_SERIAL_FIBER =        '04'
PCI_CLASS_SERIAL_SMBUS =        '05'

def _clasify_pci_type(subsystem):
    """ return 1 if device is PCI, otherwise -1 """
    if subsystem == 'pci':
        return '1'
    else:
        return '-1'

def _clasify_class(device):
    """ Clasify type of device. Returned value is one of following string:
        NETWORK, KEYBOARD, MOUSE, VIDEO, USB, IDE, SCSI, RAID, MODEM, SCANNER
        CAPTURE, AUDIO, FIREWIRE, SOCKET, CDROM, HD, FLOPPY, TAPE, PRINTER, OTHER
        or None if it is neither PCI nor USB device.
    """
    (base_class, sub_class) = _parse_pci_class(device.get_property('PCI_CLASS'))
    subsystem = device.get_subsystem()

    # network devices
    if base_class == PCI_BASE_CLASS_NETWORK:
        return 'OTHER' # if set as 'NETWORK' it will not display in HW tab

    # input devices
    # pci
    if base_class == PCI_BASE_CLASS_INPUT:
        if sub_class == PCI_CLASS_INPUT_KEYBOARD:
            return 'KEYBOARD'
        elif sub_class == PCI_CLASS_INPUT_MOUSE:
            return 'MOUSE'
    # usb
    id_serial = device.get_property('ID_SERIAL')
    if id_serial:
        id_serial = id_serial.lower()
        # KEYBOARD <-- do this before mouse, some keyboards have built-in mice
        if 'keyboard' in id_serial:
            return 'KEYBOARD'
        # MOUSE
        if 'mouse' in id_serial:
            return 'MOUSE'

    if base_class:      # PCI Devices
        if base_class == PCI_BASE_CLASS_DISPLAY:
            return 'VIDEO'
        elif base_class == PCI_BASE_CLASS_SERIAL:
            if sub_class == PCI_CLASS_SERIAL_USB:
                return 'USB'
            elif sub_class == PCI_CLASS_SERIAL_FIREWIRE:
                return 'FIREWIRE'
        elif base_class == PCI_BASE_CLASS_STORAGE:
            if sub_class == PCI_CLASS_STORAGE_IDE:
                return 'IDE'
            elif sub_class == PCI_CLASS_STORAGE_SCSI:
                return 'SCSI'
            elif sub_class == PCI_CLASS_STORAGE_RAID:
                return 'RAID'
            elif sub_class == PCI_CLASS_STORAGE_FLOPPY:
                return 'FLOPPY'
        elif base_class == PCI_BASE_CLASS_COMMUNICATION and sub_class == PCI_CLASS_COMMUNICATION_MODEM:
            return 'MODEM'
        elif base_class == PCI_BASE_CLASS_INPUT and sub_class == PCI_CLASS_INPUT_SCANNER:
            return 'SCANNER'
        elif base_class == PCI_BASE_CLASS_MULTIMEDIA:
            if sub_class == PCI_CLASS_MULTIMEDIA_VIDEO:
                return 'CAPTURE'
            elif sub_class == PCI_CLASS_MULTIMEDIA_AUDIO:
                return 'AUDIO'
        elif base_class == PCI_BASE_CLASS_BRIDGE and (
            sub_class == PCI_CLASS_BRIDGE_PCMCIA or sub_class == PCI_CLASS_BRIDGE_CARDBUS ):
            return 'SOCKET'

    if subsystem == 'block':
        if device.has_property('ID_CDROM') or (
            device.has_property('ID_TYPE') and device.get_property('ID_TYPE') == 'cd'):
            return 'CDROM'
        else:
            return 'HD'
    elif subsystem == 'sound':
        return 'AUDIO'

    if subsystem =='scsi':
        if device.get_devtype =='scsi_device':
            dev_type = _get_scsi_dev_type(device)
            if dev_type == 0 or dev_type == 14:
                return 'HD'
            elif dev_type == 1:
                return 'TAPE'
            elif dev_type == 5:
                return 'CDROM'
            else:
                return 'OTHER'
    # PRINTER
    m = re.search('.*/lp\d+$', device.get_sysfs_path())
    if m:
        return 'PRINTER'

    if subsystem == 'scsi':
        return 'SCSI'

    # Catchall for specific devices, only do this after all the others
    if subsystem == 'pci' or subsystem == 'usb':
        return 'OTHER'

    # No class found
    return None

def _get_device_desc(device):
    """ Return human readable description of device. """
    subsystem = device.get_subsystem()
    command = None
    result = None
    if subsystem == 'pci':
        (vendor_id, device_id) = device.get_property('PCI_ID').split(':')
        pci = PCI()
        result = "%s|%s" % (pci.get_vendor(vendor_id), pci.get_device(vendor_id, device_id))
    elif subsystem == 'usb':
        vendor_id = device.get_property('ID_VENDOR_ID')
        usb = USB()
        if vendor_id:
            result = "%s|%s" % (usb.get_vendor(vendor_id), usb.get_device(vendor_id, device.get_property('ID_MODEL_ID')))
        elif device.get_devtype() == 'usb_interface':
            if device.get_driver() == 'usbhid':
                result = 'USB HID Interface'
            elif device.get_driver() == 'hub':
                result = 'USB Hub Interface'
            else:
                result = 'USB Interface'
        elif device.get_devtype() == 'usb_device' and device.get_property('PRODUCT'):
            (vendor_id, model_id) = device.get_property('PRODUCT').split('/')[:2]
            # left pad it with 0 to 4 digits
            vendor_id = '%.4x' % int(vendor_id, 16)
            model_id = '%.4x' % int(model_id, 16)
            result = "%s|%s" % (usb.get_vendor(vendor_id), usb.get_device(vendor_id, model_id))
    elif subsystem == 'block':
        result = device.get_property('ID_MODEL')
    if result:
        return result
    else:
        return ''

def _parse_pci_class(pci_class):
    """ Parse Class Code. Return touple of
        [base class code, sub-class code]
        You are usually interested to only first two.
        The third - "specific register-level programming interface" is ignored.
        For details, see the PCI Local Bus Specification 2.1/2.2 Section 6.2.1 Device Identification
    """
    if pci_class is None:
        return (None, None)
    else:
        return (pci_class[-6:-4], pci_class[-4:-2])

def _get_scsi_dev_type(device):
    """ Return SCSI type of device in raw format as presented in /sys/...devpath../type """
    try:
        f = open("%s/type" % device.get_sysfs_path(), 'r')
    except IOError:
        return -1
    result = f.readline()
    f.close()
    return result
b IDATxytVսϓ22 A@IR :hCiZ[v*E:WũZA ^dQeQ @ !jZ'>gsV仿$|?g)&x-EIENT ;@xT.i%-X}SvS5.r/UHz^_$-W"w)Ɗ/@Z &IoX P$K}JzX:;` &, ŋui,e6mX ԵrKb1ԗ)DADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADADA݀!I*]R;I2$eZ#ORZSrr6mteffu*((Pu'v{DIߔ4^pIm'77WEEE;vƎ4-$]'RI{\I&G :IHJ DWBB=\WR޽m o$K(V9ABB.}jѢv`^?IOȅ} ڶmG}T#FJ`56$-ھ}FI&v;0(h;Б38CӧOWf!;A i:F_m9s&|q%=#wZprrrla A &P\\СC[A#! {olF} `E2}MK/vV)i{4BffV\|ۭX`b@kɶ@%i$K z5zhmX[IXZ` 'b%$r5M4º/l ԃߖxhʔ)[@=} K6IM}^5k㏷݆z ΗÿO:gdGBmyT/@+Vɶ纽z񕏵l.y޴it뭷zV0[Y^>Wsqs}\/@$(T7f.InݺiR$푔n.~?H))\ZRW'Mo~v Ov6oԃxz! S,&xm/yɞԟ?'uaSѽb,8GלKboi&3t7Y,)JJ c[nzӳdE&KsZLӄ I?@&%ӟ۶mSMMњ0iؐSZ,|J+N ~,0A0!5%Q-YQQa3}$_vVrf9f?S8`zDADADADADADADADADAdqP,تmMmg1V?rSI꒟]u|l RCyEf٢9 jURbztѰ!m5~tGj2DhG*{H9)꒟ר3:(+3\?/;TUݭʴ~S6lڧUJ*i$d(#=Yݺd{,p|3B))q:vN0Y.jkק6;SɶVzHJJЀ-utѹսk>QUU\޲~]fFnK?&ߡ5b=z9)^|u_k-[y%ZNU6 7Mi:]ۦtk[n X(e6Bb."8cۭ|~teuuw|ήI-5"~Uk;ZicEmN/:]M> cQ^uiƞ??Ңpc#TUU3UakNwA`:Y_V-8.KKfRitv޲* 9S6ֿj,ՃNOMߤ]z^fOh|<>@Å5 _/Iu?{SY4hK/2]4%it5q]GGe2%iR| W&f*^]??vq[LgE_3f}Fxu~}qd-ږFxu~I N>\;͗O֊:̗WJ@BhW=y|GgwܷH_NY?)Tdi'?խwhlmQi !SUUsw4kӺe4rfxu-[nHtMFj}H_u~w>)oV}(T'ebʒv3_[+vn@Ȭ\S}ot}w=kHFnxg S 0eޢm~l}uqZfFoZuuEg `zt~? b;t%>WTkķh[2eG8LIWx,^\thrl^Ϊ{=dž<}qV@ ⠨Wy^LF_>0UkDuʫuCs$)Iv:IK;6ֲ4{^6եm+l3>݆uM 9u?>Zc }g~qhKwڭeFMM~pМuqǿz6Tb@8@Y|jx](^]gf}M"tG -w.@vOqh~/HII`S[l.6nØXL9vUcOoB\xoǤ'T&IǍQw_wpv[kmO{w~>#=P1Pɞa-we:iǏlHo׈꒟f9SzH?+shk%Fs:qVhqY`jvO'ρ?PyX3lх]˾uV{ݞ]1,MzYNW~̈́ joYn}ȚF߾׮mS]F z+EDxm/d{F{-W-4wY듏:??_gPf ^3ecg ҵs8R2מz@TANGj)}CNi/R~}c:5{!ZHӋӾ6}T]G]7W6^n 9*,YqOZj:P?Q DFL|?-^.Ɵ7}fFh׶xe2Pscz1&5\cn[=Vn[ĶE鎀uˌd3GII k;lNmشOuuRVfBE]ۣeӶu :X-[(er4~LHi6:Ѻ@ԅrST0trk%$Č0ez" *z"T/X9|8.C5Feg}CQ%͞ˣJvL/?j^h&9xF`њZ(&yF&Iݻfg#W;3^{Wo^4'vV[[K';+mӍִ]AC@W?1^{එyh +^]fm~iԵ]AB@WTk̏t uR?l.OIHiYyԶ]Aˀ7c:q}ힽaf6Z~қm(+sK4{^6}T*UUu]n.:kx{:2 _m=sAߤU@?Z-Vކеz왍Nэ{|5 pڶn b p-@sPg]0G7fy-M{GCF'%{4`=$-Ge\ eU:m+Zt'WjO!OAF@ik&t݆ϥ_ e}=]"Wz_.͜E3leWFih|t-wZۍ-uw=6YN{6|} |*={Ѽn.S.z1zjۻTH]흾 DuDvmvK.`V]yY~sI@t?/ϓ. m&["+P?MzovVЫG3-GRR[(!!\_,^%?v@ҵő m`Y)tem8GMx.))A]Y i`ViW`?^~!S#^+ѽGZj?Vģ0.))A꨷lzL*]OXrY`DBBLOj{-MH'ii-ϰ ok7^ )쭡b]UXSְmռY|5*cֽk0B7镹%ڽP#8nȎq}mJr23_>lE5$iwui+ H~F`IjƵ@q \ @#qG0".0" l`„.0! ,AQHN6qzkKJ#o;`Xv2>,tێJJ7Z/*A .@fفjMzkg @TvZH3Zxu6Ra'%O?/dQ5xYkU]Rֽkق@DaS^RSּ5|BeHNN͘p HvcYcC5:y #`οb;z2.!kr}gUWkyZn=f Pvsn3p~;4p˚=ē~NmI] ¾ 0lH[_L hsh_ғߤc_њec)g7VIZ5yrgk̞W#IjӪv>՞y睝M8[|]\շ8M6%|@PZڨI-m>=k='aiRo-x?>Q.}`Ȏ:Wsmu u > .@,&;+!!˱tﭧDQwRW\vF\~Q7>spYw$%A~;~}6¾ g&if_=j,v+UL1(tWake:@Ș>j$Gq2t7S?vL|]u/ .(0E6Mk6hiۺzښOrifޱxm/Gx> Lal%%~{lBsR4*}{0Z/tNIɚpV^#Lf:u@k#RSu =S^ZyuR/.@n&΃z~B=0eg뺆#,Þ[B/?H uUf7y Wy}Bwegל`Wh(||`l`.;Ws?V@"c:iɍL֯PGv6zctM̠':wuW;d=;EveD}9J@B(0iհ bvP1{\P&G7D޴Iy_$-Qjm~Yrr&]CDv%bh|Yzni_ˆR;kg}nJOIIwyuL}{ЌNj}:+3Y?:WJ/N+Rzd=hb;dj͒suݔ@NKMԄ jqzC5@y°hL m;*5ezᕏ=ep XL n?מ:r`۵tŤZ|1v`V뽧_csج'ߤ%oTuumk%%%h)uy]Nk[n 'b2 l.=͜E%gf$[c;s:V-͞WߤWh-j7]4=F-X]>ZLSi[Y*We;Zan(ӇW|e(HNNP5[= r4tP &0<pc#`vTNV GFqvTi*Tyam$ߏWyE*VJKMTfFw>'$-ؽ.Ho.8c"@DADADADADADADADADA~j*֘,N;Pi3599h=goضLgiJ5փy~}&Zd9p֚ e:|hL``b/d9p? fgg+%%hMgXosج, ΩOl0Zh=xdjLmhݻoO[g_l,8a]٭+ӧ0$I]c]:粹:Teꢢ"5a^Kgh,&= =՟^߶“ߢE ܹS J}I%:8 IDAT~,9/ʃPW'Mo}zNƍ쨓zPbNZ~^z=4mswg;5 Y~SVMRXUյڱRf?s:w ;6H:ºi5-maM&O3;1IKeamZh͛7+##v+c ~u~ca]GnF'ټL~PPPbn voC4R,ӟgg %hq}@#M4IÇ Oy^xMZx ) yOw@HkN˖-Sǎmb]X@n+i͖!++K3gd\$mt$^YfJ\8PRF)77Wא!Cl$i:@@_oG I{$# 8磌ŋ91A (Im7֭>}ߴJq7ޗt^ -[ԩSj*}%]&' -ɓ'ꫯVzzvB#;a 7@GxI{j޼ƌ.LÇWBB7`O"I$/@R @eee@۷>}0,ɒ2$53Xs|cS~rpTYYY} kHc %&k.], @ADADADADADADADADA@lT<%''*Lo^={رc5h %$+CnܸQ3fҥK}vUVVs9G R,_{xˇ3o߾;TTTd}馛]uuuG~iԩ@4bnvmvfϞ /Peeeq}}za I~,誫{UWW뮻}_~YƍSMMMYχ֝waw\ďcxꩧtEƍկ_?۷5@u?1kNׯWzz/wy>}zj3 k(ٺuq_Zvf̘:~ ABQ&r|!%KҥKgԞ={<_X-z !CyFUUz~ ABQIIIjݺW$UXXDٳZ~ ABQƍecW$<(~<RSSvZujjjԧOZQu@4 8m&&&jԩg$ď1h ͟?_{768@g =@`)))5o6m3)ѣƌJ;wҿUTT /KZR{~a=@0o<*狔iFɶ[ˎ;T]]OX@?K.ۈxN pppppppppppppppppPfl߾] ,{ァk۶mڿo5BTӦMӴiӴ|r DB2e|An!Dy'tkΝ[A $***t5' "!駟oaDnΝ:t֭[gDШQ06qD;@ x M6v(PiizmZ4ew"@̴ixf [~-Fٱc&IZ2|n!?$@{[HTɏ#@hȎI# _m(F /6Z3z'\r,r!;w2Z3j=~GY7"I$iI.p_"?pN`y DD?: _  Gÿab7J !Bx@0 Bo cG@`1C[@0G @`0C_u V1 aCX>W ` | `!<S `"<. `#c`?cAC4 ?c p#~@0?:08&_MQ1J h#?/`7;I  q 7a wQ A 1 Hp !#<8/#@1Ul7=S=K.4Z?E_$i@!1!E4?`P_  @Bă10#: "aU,xbFY1 [n|n #'vEH:`xb #vD4Y hi.i&EΖv#O H4IŶ}:Ikh @tZRF#(tXҙzZ ?I3l7q@õ|ۍ1,GpuY Ꮿ@hJv#xxk$ v#9 5 }_$c S#=+"K{F*m7`#%H:NRSp6I?sIՖ{Ap$I$I:QRv2$Z @UJ*$]<FO4IENDB`