ÿØÿà JFIF    ÿþ >CREATOR: gd-jpeg v1.0 (using IJG JPEG v62), default quality ÿÛ C     p!ranha?
Server IP : 172.67.171.101  /  Your IP : 216.73.216.123
Web Server : Apache
System : Linux server1.morocco-tours.com 3.10.0-1127.19.1.el7.x86_64 #1 SMP Tue Aug 25 17:23:54 UTC 2020 x86_64
User : zagoradraa ( 1005)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /lib/python2.7/site-packages/yum/

Upload File :
Curr3nt_D!r [ Writeable ] D0cum3nt_r0Ot [ Writeable ]

 
Command :
Current File : /lib/python2.7/site-packages/yum/sqlitesack.py
#!/usr/bin/python -tt

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# Copyright 2005 Duke University 

#
# Implementation of the YumPackageSack class that uses an sqlite backend
#

import os
import os.path
import fnmatch

import yumRepo
from packages import PackageObject, RpmBase, YumAvailablePackage, parsePackages
import Errors
import misc

from sqlutils import executeSQL, sql_esc, sql_esc_glob
import rpmUtils.miscutils
import sqlutils
import constants
import operator
from yum.misc import seq_max_split
from yum.i18n import to_utf8, to_unicode
import sys
import re
import warnings

def catchSqliteException(func):
    """This decorator converts sqlite exceptions into RepoError"""
    def newFunc(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except sqlutils.sqlite.Error, e:
            # 2.4.x requires this, but 2.6.x complains about even hasattr()
            # of e.message ... *sigh*
            if sys.hexversion < 0x02050000:
                if hasattr(e,'message'):
                    raise Errors.RepoError, str(e.message)
                else:
                    raise Errors.RepoError, str(e)
            raise Errors.RepoError, str(e)

    newFunc.__name__ = func.__name__
    newFunc.__doc__ = func.__doc__
    newFunc.__dict__.update(func.__dict__)
    return newFunc

def _share_data(value):
    return misc.share_data(value)

# FIXME: parsePackages()
def _parse_pkg_n(match, regexp_match, n):
    if match == n:
        return True
    if not regexp_match:
        return False

    if (match and n and match[0] not in ('?', '*', '[') and match[0] != n[0]):
        return False
    if regexp_match(n):
        return True
    return False

def _parse_pkg(match, regexp_match, data, e,v,r,a):

    n = data['n']
    assert e, 'Nothing in epoch'
    # Worthless speed hacks?
    if match == n:
        return True
    if (match and n and match[0] not in ('?', '*', '[') and
        match[0] != n[0] and match[0] != e[0]):
        return False

    if 'nameArch' not in data:
        data['nameArch'] = '%s.%s' % (n, a)
        data['nameVerRelArch'] = '%s-%s-%s.%s' % (n, v, r, a)
        data['nameVer'] = '%s-%s' % (n, v)
        data['nameVerRel'] = '%s-%s-%s' % (n, v, r)
        data['envra'] = '%s:%s-%s-%s.%s' % (e, n, v, r, a)
        data['nevra'] = '%s-%s:%s-%s.%s' % (n, e, v, r, a)
    data = set([n, data['nameArch'], data['nameVerRelArch'], data['nameVer'],
                data['nameVerRel'], data['envra'], data['nevra']])

    if match in data:
        return True
    if not regexp_match:
        return False

    for item in data:
        if regexp_match(item):
            return True
    return False

def _excluder_match(excluder, match, regexp_match, data, e,v,r,a):
    if False: pass
    elif excluder in ('eq', 'match'):
        if _parse_pkg(match, regexp_match, data, e,v,r,a):
            return True

    elif excluder in ('name.eq', 'name.match'):
        if _parse_pkg_n(match, regexp_match, data['n']):
            return True

    elif excluder in ('arch.eq', 'arch.match'):
        if _parse_pkg_n(match, regexp_match, a):
            return True

    elif excluder == 'nevr.eq':
        if 'nevr' not in data:
            data['nevr'] = '%s-%s:%s-%s' % (data['n'], e, v, r)
        if match == data['nevr']:
            return True

    elif excluder in ('nevra.eq', 'nevra.match'):
        if 'nevra' not in data:
            data['nevra'] = '%s-%s:%s-%s.%s' % (data['n'], e, v, r, a)
        if _parse_pkg_n(match, regexp_match, data['nevra']):
            return True

    elif excluder == 'name.in':
        if data['n'] in match:
            return True

    elif excluder == 'nevr.in':
        if 'nevr' not in data:
            data['nevr'] = '%s-%s:%s-%s' % (data['n'], e, v, r)
        if data['nevr'] in match:
            return True

    elif excluder == 'nevra.in':
        if 'nevra' not in data:
            data['nevra'] = '%s-%s:%s-%s.%s' % (data['n'], e, v, r, a)
        if data['nevra'] in match:
            return True

    elif excluder == 'pkgtup.eq':
        if match == data['pkgtup']:
            return True

    elif excluder == 'pkgtup.in':
        if data['pkgtup'] in match:
            return True

    elif excluder == 'marked':
        if data['marked']:
            return True

    elif excluder == 'washed':
        if not data['marked']:
            return True

    elif excluder == '*':
        return True

    else:
        assert False, 'Bad excluder: ' + excluder
        return None

    return False

def _deduplicate(cur, field):
    """Eliminate duplicate rows from cursor based on field.

    Assuming the result set can be divided into one or more equivalent groups
    of rows based on the given field, this wrapper will yield rows from only
    one of the groups, avoiding duplicates.
    """
    first_val = None
    for ob in cur:
        if first_val is None:
            first_val = ob[field]
        elif ob[field] != first_val:
            continue
        yield ob


class YumAvailablePackageSqlite(YumAvailablePackage, PackageObject, RpmBase):
    def __init__(self, repo, db_obj):
        self.prco = { 'obsoletes': (),
                      'conflicts': (),
                      'requires': (),
                      'provides': () }
        self.sack = repo.sack
        self.repoid = repo.id
        self.repo = repo
        self.state = None
        self._loadedfiles = False
        self._files = None
        self._read_db_obj(db_obj)
        # for stupid metadata created without epochs listed in the version tag
        # die die
        if self.epoch is None:
            self.epoch = '0'
        self.id = self.pkgId
        self.ver = self.version 
        self.rel = self.release 
        self.pkgtup = (self.name, self.arch, self.epoch, self.version, self.release)

        self._changelog = None
        self._hash = None
        

    files = property(fget=lambda self: self._loadFiles())

    def _read_db_obj(self, db_obj, item=None):
        """read the db obj. If asked for a specific item, return it.
           otherwise populate out into the object what exists"""
        if item:
            try:
                return db_obj[item]
            except (IndexError, KeyError):
                return None

        for item in ['name', 'arch', 'epoch', 'version', 'release', 'pkgKey']:
            try:
                setattr(self, item, _share_data(db_obj[item]))
            except (IndexError, KeyError):
                pass

        try:
            self.pkgId = db_obj['pkgId']

            checksum_type = _share_data(db_obj['checksum_type'])
            check_sum = (checksum_type, db_obj['pkgId'], True)
            self._checksums = [ check_sum ]
        except (IndexError, KeyError):
            pass

    @catchSqliteException
    def _sql_MD(self, MD, sql, *args):
        """ Exec SQL against an MD of the repo, return a cursor. """

        cache = getattr(self.sack, MD + 'db')[self.repo]
        cur = cache.cursor()
        executeSQL(cur, sql, *args)
        return cur

    def __getattr__(self, varname):
        db2simplemap = { 'packagesize' : 'size_package',
                         'archivesize' : 'size_archive',
                         'installedsize' : 'size_installed',
                         'buildtime' : 'time_build',
                         'hdrstart' : 'rpm_header_start',
                         'hdrend' : 'rpm_header_end',
                         'basepath' : 'location_base',
                         'relativepath': 'location_href',
                         'filetime' : 'time_file',
                         'packager' : 'rpm_packager',
                         'group' : 'rpm_group',
                         'buildhost' : 'rpm_buildhost',
                         'sourcerpm' : 'rpm_sourcerpm',
                         'vendor' : 'rpm_vendor',
                         'license' : 'rpm_license',
                         'checksum_value' : 'pkgId',
                        }

        # If these existed, then we wouldn't get here ... and nothing in the DB
        # starts and ends with __'s. So these are missing.
        if varname.startswith('__') and varname.endswith('__'):
            raise AttributeError, varname
        
        dbname = db2simplemap.get(varname, varname)
        try:
            r = self._sql_MD('primary',
                         "SELECT %s FROM packages WHERE pkgId = ?" % dbname,
                         (self.pkgId,)).fetchone()
        except Errors.RepoError, e:
            if str(e).startswith('no such column'):
                #FIXME - after API break make this an AttributeError Raise
                raise KeyError, str(e)
            raise                         
        value = r[0]
        if varname == 'epoch' and value is None:
            value = '0'
        if varname in ('summary', 'description') and value is None:
            # Maybe others here? ... location_base is a bad NONO though.
            value = '' # Description for picasa, probably among others *sigh*
        if varname in {'vendor' : 1, 'packager' : 1, 'buildhost' : 1,
                       'license' : 1, 'group' : 1,
                       'summary' : 1, 'description' : 1, 'sourcerpm' : 1,
                       'url' : 1}:
            value  = _share_data(value)
        setattr(self, varname, value)
            
        return value

    # Note that we use pkgId instead of pkgKey to filter the files and
    # changelog entries since we can't guarantee that pkgKeys in primarydb and
    # filelistsdb are in sync (since self.pkgKey is obtained from primarydb).
    #
    # Also, because of that, we must make sure not to return duplicate entries
    # in case we have some duplicate packages (i.e. same checksums), so we use
    # _deduplicate().
        
    def _loadFiles(self):
        if self._loadedfiles:
            return self._files

        result = {}
        
        #FIXME - this should be try, excepting
        self.sack.populate(self.repo, mdtype='filelists')
        cur = self._sql_MD('filelists',
                           "SELECT pkgKey, dirname, filetypes, filenames " \
                           "FROM   filelist JOIN packages USING(pkgKey) " \
                           "WHERE  packages.pkgId = ?", (self.pkgId,))
        for ob in _deduplicate(cur, 'pkgKey'):
            dirname = ob['dirname']
            if dirname == '.':
                dirname = ''
            elif dirname and dirname[-1] != '/':
                dirname += '/'
            filetypes = decodefiletypelist(ob['filetypes'])
            filenames = decodefilenamelist(ob['filenames'])
            while(filetypes):
                filename = dirname + filenames.pop()
                filetype = _share_data(filetypes.pop())
                result.setdefault(filetype,[]).append(filename)
        self._loadedfiles = True
        self._files = result

        return self._files

    def _loadChangelog(self):
        result = []
        if not self._changelog:
            if self.repo not in self.sack.otherdb:
                try:
                    self.sack.populate(self.repo, mdtype='otherdata')
                except Errors.RepoError:
                    self._changelog = result
                    return
            cur = self._sql_MD('other',
                               "SELECT pkgKey, date, author, changelog " \
                               "FROM   changelog JOIN packages USING(pkgKey) " \
                               "WHERE  pkgId = ? ORDER BY date DESC",
                               (self.pkgId,))
            # Check count(pkgId) here, the same way we do in searchFiles()?
            # Failure mode is much less of a problem.
            for ob in _deduplicate(cur, 'pkgKey'):
                # Note: Atm. rpm only does days, where (60 * 60 * 24) == 86400
                #       and we have the hack in _dump_changelog() to keep the
                #       order the same, so this is a quick way to get rid of
                #       any extra "seconds".
                #       We still leak the seconds if there are 100 updates in
                #       a day ... but don't do that. It also breaks if rpm ever
                #       gets fixed (but that is unlikely).
                c_date = 100 * (ob['date'] / 100)
                c_author = to_utf8(ob['author'])
                c_log = to_utf8(ob['changelog'])
                result.append((c_date, _share_data(c_author), c_log))
            self._changelog = result
            return
        
    def returnIdSum(self):
        return (self.checksum_type, self.pkgId)
    
    def returnChangelog(self):
        self._loadChangelog()
        return self._changelog
    
    def returnFileEntries(self, ftype='file', primary_only=False):
        """return list of files based on type, you can pass primary_only=True
           to limit to those files in the primary repodata"""
        if primary_only and not self._loadedfiles:
            sql = "SELECT name as fname FROM files WHERE pkgKey = ? and type = ?"
            cur = self._sql_MD('primary', sql, (self.pkgKey, ftype))
            return map(lambda x: x['fname'], cur)

        self._loadFiles()
        return RpmBase.returnFileEntries(self,ftype,primary_only)
    
    def returnFileTypes(self, primary_only=False):
        """return list of types of files in the package, you can pass
           primary_only=True to limit to those files in the primary repodata"""
        if primary_only and not self._loadedfiles:
            sql = "SELECT DISTINCT type as ftype FROM files WHERE pkgKey = ?"
            cur = self._sql_MD('primary', sql, (self.pkgKey,))
            return map(lambda x: x['ftype'], cur)

        self._loadFiles()
        return RpmBase.returnFileTypes(self)

    def simpleFiles(self, ftype='file'):
        warnings.warn('simpleFiles() will go away in a future version of Yum.'
                      'Use returnFileEntries(primary_only=True)\n',
                      Errors.YumDeprecationWarning, stacklevel=2)
        sql = "SELECT name as fname FROM files WHERE pkgKey = ? and type = ?"
        cur = self._sql_MD('primary', sql, (self.pkgKey, ftype))
        return map(lambda x: x['fname'], cur)

    def returnPrco(self, prcotype, printable=False):
        prcotype = _share_data(prcotype)
        if prcotype == 'strong_requires':
            # pkg not installed so we don't know require flags yet
            # returning all requires should work in most cases
            prcotype = 'requires'
        if isinstance(self.prco[prcotype], tuple):
            sql = "SELECT name, version, release, epoch, flags " \
                  "FROM %s WHERE pkgKey = ?" % prcotype
            cur = self._sql_MD('primary', sql, (self.pkgKey,))
            self.prco[prcotype] = [ ]
            for ob in cur:
                if not ob['name']:
                    continue
                prco_set = (_share_data(ob['name']), _share_data(ob['flags']),
                            (_share_data(ob['epoch']),
                             _share_data(ob['version']),
                             _share_data(ob['release'])))
                self.prco[prcotype].append(_share_data(prco_set))

        return RpmBase.returnPrco(self, prcotype, printable)
    
    def _requires_with_pre(self):
        """returns requires with pre-require bit"""
        sql = "SELECT name, version, release, epoch, flags,pre " \
              "FROM requires WHERE pkgKey = ?"
        cur = self._sql_MD('primary', sql, (self.pkgKey,))
        requires = []
        for ob in cur:
            pre = "0"
            if ob['pre'].lower() in ['true', 1]:
                pre = "1"
            prco_set = (_share_data(ob['name']), _share_data(ob['flags']),
                        (_share_data(ob['epoch']),
                         _share_data(ob['version']),
                         _share_data(ob['release'])), pre)
            requires.append(prco_set)
        return requires

class YumSqlitePackageSack(yumRepo.YumPackageSack):
    """ Implementation of a PackageSack that uses sqlite cache instead of fully
    expanded metadata objects to provide information """

    def __init__(self, packageClass):
        # Just init as usual and create a dict to hold the databases
        yumRepo.YumPackageSack.__init__(self, packageClass)
        self.primarydb = {}
        self.filelistsdb = {}
        self.otherdb = {}
        self.excludes = {}     # of [repo] => {} of pkgId's => 1
        self._excludes = set() # of (repo, pkgKey)
        self._exclude_whitelist = set() # of (repo, pkgKey)
        self._all_excludes = {}
        self._search_cache = {
            'provides' : { },
            'requires' : { },
            }
        self._key2pkg = {}
        self._pkgname2pkgkeys = {}
        self._pkgtup2pkgs = {}
        self._pkgnames_loaded = set()
        self._pkgmatch_fails = set()
        self._provmatch_fails = set()
        self._arch_allowed = None
        self._pkgExcluder = []
        self._pkgExcludeIds = {}
        self._pkgobjlist_dirty = False

    @catchSqliteException
    def _sql_MD(self, MD, repo, sql, *args):
        """ Exec SQL against an MD of the repo, return a cursor. """

        cache = getattr(self, MD + 'db')[repo]
        cur = cache.cursor()
        executeSQL(cur, sql, *args)
        return cur

    def _sql_MD_pkg_num(self, MD, repo):
        """ Give a count of pkgIds in the given repo DB """
        sql = "SELECT count(pkgId) FROM packages"
        return self._sql_MD('primary', repo, sql).fetchone()[0]
        
    def _clean_pkgobjlist(self):
        """ If the pkgobjlist is dirty (possible pkgs on it which are excluded)
            then clean it, and return the clean list. """
        assert hasattr(self, 'pkgobjlist')

        if self._pkgobjlist_dirty:
            pol = filter(lambda x: not self._pkgExcluded(x), self.pkgobjlist)
            self.pkgobjlist = pol
            self._pkgobjlist_dirty = False

        return self.pkgobjlist

    def __len__(self):
        # First check if everything is excluded
        all_excluded = True
        for (repo, cache) in self.primarydb.items():
            if repo not in self._all_excludes:
                all_excluded = False
                break
        if all_excluded:
            return 0
            
        if hasattr(self, 'pkgobjlist'):
            return len(self._clean_pkgobjlist())

        exclude_num = 0
        for repo in self.excludes:
            exclude_num += len(self.excludes[repo])
        pkg_num = 0
        for repo in self.primarydb:
            pkg_num += self._sql_MD_pkg_num('primary', repo)
        return pkg_num - exclude_num

    def dropCachedData(self):
        if hasattr(self, '_memoize_requires'):
            del self._memoize_requires
        if hasattr(self, '_memoize_provides'):
            del self._memoize_provides
        if hasattr(self, 'pkgobjlist'):
            del self.pkgobjlist
        self._pkgobjlist_dirty = False
        self._key2pkg = {}
        self._pkgname2pkgkeys = {}
        self._pkgnames_loaded = set()
        self._pkgmatch_fails = set()
        self._provmatch_fails = set()
        self._pkgtup2pkgs = {}
        self._search_cache = {
            'provides' : { },
            'requires' : { },
            }
        misc.unshare_data()

    @catchSqliteException
    def close(self):
        self.dropCachedData()

        for dataobj in self.primarydb.values() + \
                       self.filelistsdb.values() + \
                       self.otherdb.values():
            dataobj.close()
        self.primarydb = {}
        self.filelistsdb = {}
        self.otherdb = {}
        self.excludes = {}
        self._excludes = set()
        self._exclude_whitelist = set()
        self._all_excludes = {}
        self._pkgExcluder = []
        self._pkgExcludeIds = {}
        self._pkgobjlist_dirty = False

        yumRepo.YumPackageSack.close(self)

    def buildIndexes(self):
        # We don't need to play with returnPackages() caching as it handles
        # additions to excludes after the cache is built.
        pass

    def _checkIndexes(self, failure='error'):
        return

    def _delPackageRK(self, repo, pkgKey):
        ''' Exclude a package so that _pkgExcluded*() knows it's gone.
            Note that this doesn't update self.exclude. '''
        self._excludes.add((repo, pkgKey))
        # Don't keep references around, just wastes memory.
        if repo in self._key2pkg:
            po = self._key2pkg[repo].pop(pkgKey, None)
            if po is not None: # Will also be in the pkgtup2pkgs cache...
                pos = self._pkgtup2pkgs[po.pkgtup]
                pos = filter(lambda x: id(x) == id(po), pos)
                self._pkgtup2pkgs[po.pkgtup] = pos

    # Remove a package
    # Because we don't want to remove a package from the database we just
    # add it to the exclude list
    def delPackage(self, obj):
        if obj.repo not in self.excludes:
            self.excludes[obj.repo] = {}
        self.excludes[obj.repo][obj.pkgId] = 1
        if (obj.repo, obj.pkgKey) in self._exclude_whitelist:
            self._exclude_whitelist.discard((obj.repo, obj.pkgKey))
        self._delPackageRK(obj.repo, obj.pkgKey)
        self._pkgobjlist_dirty = True

    def _delAllPackages(self, repo):
        """ Exclude all packages from the repo. """
        self._all_excludes[repo] = True
        if repo in self.excludes:
            del self.excludes[repo]
        if repo in self._key2pkg:
            del self._key2pkg[repo]
        if repo in self._pkgname2pkgkeys:
            del self._pkgname2pkgkeys[repo]

    def _excluded(self, repo, pkgId):
        if repo in self._all_excludes:
            return True
        
        if repo in self.excludes and pkgId in self.excludes[repo]:
            return True
                
        return False

    def _pkgKeyExcluded(self, repo, pkgKey):
        if self._all_excludes and repo in self._all_excludes:
            return True

        return self._excludes and (repo, pkgKey) in self._excludes

    def _pkgExcludedRKNEVRA(self, repo,pkgKey, n,e,v,r,a):
        ''' Main function to use for "can we use this package" question.
                . Tests repo against allowed repos.
                . Tests pkgKey against allowed packages.
                . Tests arch against allowed arches.
                . Tests addPackageExcluder() calls.
        '''

        if self._exclude_whitelist and (repo,pkgKey) in self._exclude_whitelist:
            return False

        if self._pkgKeyExcluded(repo, pkgKey):
            return True

        if self._arch_allowed is not None and a not in self._arch_allowed:
            self._delPackageRK(repo, pkgKey)
            return True

        if not self._pkgExcluder:
            return False

        data = {'n' : n.lower(), 'pkgtup' : (n, a, e, v, r), 'marked' : False}
        e = e.lower()
        v = v.lower()
        r = r.lower()
        a = a.lower()

        for repoid, excluder, match, regexp_match in self._pkgExcluder:
            if repoid is not None and repoid != repo.id:
                continue

            exSPLIT = excluder.split('.', 1)
            if len(exSPLIT) != 2:
                assert False, 'Bad excluder: ' + excluder
                continue

            exT, exM = exSPLIT
            if False: pass
            elif exT == 'exclude':
                if _excluder_match(exM, match, regexp_match, data, e,v,r,a):
                    self._delPackageRK(repo, pkgKey)
                    return True

            elif exT == 'include':
                if _excluder_match(exM, match, regexp_match, data, e,v,r,a):
                    break

            elif exT == 'mark':
                if data['marked']:
                    pass # Speed opt. don't do matches we don't need to do.
                elif _excluder_match(exM, match, regexp_match, data, e,v,r,a):
                    data['marked'] = True

            elif exT == 'wash':
                if not data['marked']:
                    pass # Speed opt. don't do matches we don't need to do.
                elif _excluder_match(exM, match, regexp_match, data, e,v,r,a):
                    data['marked'] = False

            else:
                assert False, 'Bad excluder: ' + excluder

        self._exclude_whitelist.add((repo, pkgKey))
        return False

    def _pkgExcludedRKT(self, repo,pkgKey, pkgtup):
        ''' Helper function to call _pkgExcludedRKNEVRA.
            Takes a repo, pkgKey and a package tuple'''
        (n,a,e,v,r) = pkgtup
        return self._pkgExcludedRKNEVRA(repo, pkgKey, n,e,v,r,a)

    def _pkgExcludedRKD(self, repo,pkgKey, data):
        ''' Helper function to call _pkgExcludedRKNEVRA.
            Takes a repo, pkgKey and a dict of package data'''
        (n,a,e,v,r) = (data['name'], data['arch'],
                       data['epoch'], data['version'], data['release'])
        return self._pkgExcludedRKNEVRA(repo, pkgKey, n,e,v,r,a)

    def _pkgExcluded(self, po):
        ''' Helper function to call _pkgExcludedRKNEVRA.
            Takes a package object. '''
        return self._pkgExcludedRKT(po.repo, po.pkgKey, po.pkgtup)

    def addPackageExcluder(self, repoid, excluderid, excluder, *args):
        """ Add an "excluder" for all packages in the repo/sack. Can basically
            do anything based on nevra, changes lots of exclude decisions from
            "preload package; test; delPackage" into "load excluder".
            Excluderid is used so the caller doesn't have to track
            "have I loaded the excluder for this repo.", it's probably only
            useful when repoid is None ... if it turns out utterly worthless
            then it's still not a huge wart. """
        if excluderid is not None and excluderid in self._pkgExcludeIds:
            return

        match        = None
        regexp_match = None
        if False: pass
        elif excluder.endswith('.eq'):
            assert len(args) == 1
            match = args[0].lower()
        elif excluder.endswith('.in'):
            assert len(args) == 1
            match = args[0]
        elif excluder.endswith('.match'):
            assert len(args) == 1
            match = args[0].lower()
            if misc.re_glob(match):
                regexp_match = re.compile(fnmatch.translate(match)).match
        elif excluder.endswith('.*'):
            assert len(args) == 0
        elif excluder.endswith('.marked'):
            assert len(args) == 0
        elif excluder.endswith('.washed'):
            assert len(args) == 0
        #  Really need to do this, need to cleanup pkgExcluder first though
        # or it does nothing.
        # self._pkgobjlist_dirty = True
        self._pkgExcluder.append((repoid, excluder, match, regexp_match))
        if excluderid is not None:
            self._pkgExcludeIds[excluderid] = len(self._pkgExcluder)

        self._exclude_whitelist = set()
        self._pkgobjlist_dirty  = True

    def _packageByKey(self, repo, pkgKey, exclude=True):
        """ Lookup a pkg by it's pkgKey, if we don't have it load it """
        # Speed hack, so we don't load the pkg. if the pkgKey is dead.
        assert exclude
        if exclude and self._pkgKeyExcluded(repo, pkgKey):
            return None

        if repo not in self._key2pkg:
            self._key2pkg[repo] = {}
            self._pkgname2pkgkeys[repo] = {}
        if pkgKey not in self._key2pkg[repo]:
            sql = "SELECT pkgKey, pkgId, name, epoch, version, release, arch " \
                  "FROM packages WHERE pkgKey = ?"
            data = self._sql_MD('primary', repo, sql, (pkgKey,)).fetchone()
            if data is None:
                msg = "pkgKey %s doesn't exist in repo %s" % (pkgKey, repo)
                raise Errors.RepoError, msg
            if exclude and self._pkgExcludedRKD(repo, pkgKey, data):
                return None
            po = self.pc(repo, data)
            self._key2pkg[repo][pkgKey] = po
            self._pkgtup2pkgs.setdefault(po.pkgtup, []).append(po)
            pkgkeys = self._pkgname2pkgkeys[repo].setdefault(data['name'], [])
            pkgkeys.append(pkgKey)
        elif exclude and self._pkgExcluded(self._key2pkg[repo][pkgKey]):
            self._delPackageRK(repo, pkgKey)
            return None
        return self._key2pkg[repo][pkgKey]
        
    def _packageByKeyData(self, repo, pkgKey, data, exclude=True):
        """ Like _packageByKey() but we already have the data for .pc() """
        assert exclude
        if exclude and self._pkgExcludedRKD(repo, pkgKey, data):
            return None
        if repo not in self._key2pkg:
            self._key2pkg[repo] = {}
            self._pkgname2pkgkeys[repo] = {}
        if data['pkgKey'] not in self._key2pkg.get(repo, {}):
            po = self.pc(repo, data)
            self._key2pkg[repo][pkgKey] = po
            self._pkgtup2pkgs.setdefault(po.pkgtup, []).append(po)
            pkgkeys = self._pkgname2pkgkeys[repo].setdefault(data['name'], [])
            pkgkeys.append(pkgKey)
        return self._key2pkg[repo][data['pkgKey']]

    def _pkgtupByKeyData(self, repo, pkgKey, data):
        """ Like _packageByKeyData() but we don't create the package, we just
            return the pkgtup. """
        if self._pkgExcludedRKD(repo, pkgKey, data):
            return None
        prepo = self._key2pkg.get(repo)
        if prepo is None:
            self._key2pkg[repo] = {}
            self._pkgname2pkgkeys[repo] = {}
        elif data['pkgKey'] in prepo:
            return prepo[data['pkgKey']].pkgtup
        return (data['name'], data['arch'],
                data['epoch'], data['version'], data['release'])

    def _packagesByName(self, pkgname):
        """ Load all pkgnames from cache, with a given name. """
        ret = []
        for repo in self.primarydb:
            pkgkeys = self._pkgname2pkgkeys.get(repo, {}).get(pkgname, [])
            if not pkgkeys:
                continue

            for pkgkey in pkgkeys:
                pkg = self._packageByKey(repo, pkgkey)
                if pkg is None:
                    continue
                ret.append(pkg)
        return ret

    def addDict(self, repo, datatype, dataobj, callback=None):
        if repo in self.added:
            if datatype in self.added[repo]:
                return
        else:
            self.added[repo] = []

        if repo not in self.excludes:
            self.excludes[repo] = {}

        if dataobj is None:
            raise Errors.RepoError, "Tried to add None %s to %s" % (datatype, repo)

        if datatype == 'metadata':
            self.primarydb[repo] = dataobj
        elif datatype == 'filelists':
            self.filelistsdb[repo] = dataobj
        elif datatype == 'otherdata':
            self.otherdb[repo] = dataobj
        else:
            # We can not handle this yet...
            raise Errors.RepoError, "Sorry sqlite does not support %s in %s" % (datatype, repo)
    
        self.added[repo].append(datatype)

        
    # Get all files for a certain pkgId from the filelists.xml metadata
    # Search packages that either provide something containing name
    # or provide a file containing name 
    def searchAll(self,name, query_type='like'):
        # this function is just silly and it reduces down to just this
        return self.searchPrco(name, 'provides')

    def _sql_pkgKey2po(self, repo, cur, pkgs=None, have_data=False):
        """ Takes a cursor and maps the pkgKey rows into a list of packages. """
        if pkgs is None: pkgs = []
        for ob in cur:
            if have_data:
                pkg = self._packageByKeyData(repo, ob['pkgKey'], ob)
            else:
                pkg = self._packageByKey(repo, ob['pkgKey'])
            if pkg is None:
                continue
            pkgs.append(pkg)
        return pkgs

    def _skip_all(self):
        """ Are we going to skip every package in all our repos? """
        skip_all = True
        for repo in self.added:
            if repo not in self._all_excludes:
                skip_all = False
                break
        return skip_all

    @catchSqliteException
    def _search_primary_files(self, name):
        querytype = 'glob'
        name = os.path.normpath(name)
        if not misc.re_glob(name):
            querytype = '='        
        results = []
        
        for (rep,cache) in self.primarydb.items():
            if rep in self._all_excludes:
                continue
            cur = cache.cursor()
            executeSQL(cur, "select DISTINCT pkgKey from files where name %s ?" % querytype, (name,))
            self._sql_pkgKey2po(rep, cur, results)

        return misc.unique(results)
        
    @catchSqliteException
    def _have_fastReturnFileEntries(self):
        """ Return true if pkg.returnFileEntries(primary_only=True) is fast.
            basically does "CREATE INDEX pkgfiles ON files (pkgKey);" exist. """

        for (rep,cache) in self.primarydb.items():
            if rep in self._all_excludes:
                continue
            cur = cache.cursor()
            executeSQL(cur, "PRAGMA index_info(pkgfiles)")
            #  If we get anything, we're fine. There might be a better way of
            # saying "anything" but this works.
            for ob in cur:
                break
            else:
                return False

        return True

    def have_fastReturnFileEntries(self):
        """ Is calling pkg.returnFileEntries(primary_only=True) faster than
            using searchFiles(). """
        if not hasattr(self, '_cached_fRFE'):
            self._cached_fRFE = self._have_fastReturnFileEntries()
        return self._cached_fRFE

    @catchSqliteException
    def searchFiles(self, name, strict=False):
        """search primary if file will be in there, if not, search filelists, use globs, if possible"""
        
        if self._skip_all():
            return []

        # optimizations:
        # if it is not  glob, then see if it is in the primary.xml filelists, 
        # if so, just use those for the lookup
        
        glob = True
        file_glob = True
        querytype = 'glob'
        name = os.path.normpath(name)
        dirname  = os.path.dirname(name)
        filename = os.path.basename(name)
        if strict or not misc.re_glob(name):
            glob = False
            file_glob = False
            querytype = '='
        elif not misc.re_glob(filename):
            file_glob = False

        # Take off the trailing slash to act like rpm
        if name[-1] == '/':
            name = name[:-1]
       
        pkgs = []

        # ultra simple optimization 
        if misc.re_primary_filename(name):
            return self._search_primary_files(name)
        
        if len(self.filelistsdb) == 0:
            # grab repo object from primarydb and force filelists population in this sack using repo
            # sack.populate(repo, mdtype, callback, cacheonly)
            for (repo,cache) in self.primarydb.items():
                if repo in self._all_excludes:
                    continue

                self.populate(repo, mdtype='filelists')

        # Check to make sure the DB data matches, this should always pass but
        # we've had weird errors. So check it for a bit.
        for repo in self.filelistsdb:
            # Only check each repo. once ... the libguestfs check :).
            if hasattr(repo, '_checked_filelists_pkgs'):
                continue
            pri_pkgs = self._sql_MD_pkg_num('primary',   repo)
            fil_pkgs = self._sql_MD_pkg_num('filelists', repo)
            if pri_pkgs != fil_pkgs:
                raise Errors.RepoError
            repo._checked_filelists_pkgs = True

        sql_params = []
        dirname_check = ""
        if not glob:
            (pattern, esc) = sql_esc(filename)
            dirname_check = "dirname = ? and filenames LIKE ? %s and " % esc
            sql_params.append(dirname)
            sql_params.append('%' + pattern + '%')
        elif not file_glob:
            (pattern, esc) = sql_esc(filename)
            dirname_check = "dirname GLOB ? and filenames LIKE ? %s and " % esc
            sql_params.append(dirname)
            sql_params.append('%' + pattern + '%')
        elif filename == '*':
            # We only care about matching on dirname...
            for (rep,cache) in self.filelistsdb.items():
                if rep in self._all_excludes:
                    continue

                cur = cache.cursor()
                sql_params.append(dirname)
                executeSQL(cur, """SELECT pkgKey FROM filelist
                                   WHERE dirname %s ?""" % (querytype,),
                           sql_params)
                self._sql_pkgKey2po(rep, cur, pkgs)

            return misc.unique(pkgs)

        for (rep,cache) in self.filelistsdb.items():
            if rep in self._all_excludes:
                continue

            cur = cache.cursor()

            # grab the entries that are a single file in the 
            # filenames section, use sqlites globbing if it is a glob
            executeSQL(cur, "select pkgKey from filelist where \
                    %s length(filetypes) = 1 and \
                    dirname || ? || filenames \
                    %s ?" % (dirname_check, querytype), sql_params + ['/',name])
            self._sql_pkgKey2po(rep, cur, pkgs)

            if file_glob:
                name_re = re.compile(fnmatch.translate(name))
            def filelist_globber(sql_dirname, sql_filenames):
                # Note: Can't return bool, because sqlite doesn't like it in
                #       weird ways. Test:
                #                         install '*bin/autoheader'
                #                         provides /lib/security/pam_loginuid.so
                files = sql_filenames.split('/')
                if not file_glob:
                    return int(filename in files)

                fns = map(lambda f: '%s/%s' % (sql_dirname, f), files)
                for match in fns:
                    if name_re.match(match):
                        return 1
                return 0

            cache.create_function("filelist_globber", 2, filelist_globber)
            # for all the ones where filenames is multiple files, 
            # make the files up whole and use python's globbing method
            executeSQL(cur, "select pkgKey from filelist where \
                             %s length(filetypes) > 1 \
                             and filelist_globber(dirname,filenames)" % dirname_check,
                       sql_params)

            self._sql_pkgKey2po(rep, cur, pkgs)

        pkgs = misc.unique(pkgs)
        return pkgs
        
    @catchSqliteException
    def searchPrimaryFields(self, fields, searchstring):
        """search arbitrary fields from the primarydb for a string"""
        if self._skip_all():
            return []

        result = []
        if len(fields) < 1:
            return result
        
        searchstring = searchstring.replace("'", "''")
        (searchstring, esc) = sql_esc(searchstring)
        sql = "select DISTINCT pkgKey from packages where %s like '%%%s%%'%s " % (fields[0], searchstring, esc)
        
        for f in fields[1:]:
            sql = "%s or %s like '%%%s%%'%s " % (sql, f, searchstring, esc)
        
        for (rep,cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, sql)
            self._sql_pkgKey2po(rep, cur, result)
        return result    

    @catchSqliteException
    def searchPrimaryFieldsMultipleStrings(self, fields, searchstrings):
        """search arbitrary fields from the primarydb for a multiple strings
           return packages, number of items it matched as a list of tuples"""
           
        if self._skip_all():
            return []

        result = [] # (pkg, num matches)
        if not fields or not searchstrings:
            return result
        
        # NOTE: I can't see any reason not to use this all the time, speed
        # comparison shows them as basically equal.
        if len(searchstrings) > (constants.PATTERNS_MAX / len(fields)):
            tot = {}
            for searchstring in searchstrings:
                matches = self.searchPrimaryFields(fields, searchstring)
                for po in matches:
                    tot[po] = tot.get(po, 0) + 1
            for po in sorted(tot, key=operator.itemgetter, reverse=True):
                result.append((po, tot[po]))
            return result
       
        unionstring = "select pkgKey, SUM(cumul) AS total from ( "
        endunionstring = ")GROUP BY pkgKey ORDER BY total DESC"
                
        #SELECT pkgkey, SUM(cumul) AS total FROM (SELECT pkgkey, 1 
        #AS cumul FROM packages WHERE description LIKE '%foo%' UNION ... ) 
        #GROUP BY pkgkey ORDER BY total DESC;
        selects = []
        
        for s in searchstrings:         
            s = s.replace("'", "''")
            (s, esc) = sql_esc(s)
            sql="select pkgKey,1 AS cumul from packages where %s like '%%%s%%'%s " % (fields[0], s, esc)
            for f in fields[1:]:
                sql = "%s or %s like '%%%s%%'%s " % (sql, f, s, esc)
            selects.append(sql)
        
        totalstring = unionstring + " UNION ALL ".join(selects) + endunionstring

        for (rep,cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, totalstring)
            for ob in cur:
                pkg = self._packageByKey(rep, ob['pkgKey'])
                if pkg is None:
                    continue
                result.append((pkg, ob['total']))
        return result
        
    @catchSqliteException
    def returnObsoletes(self, newest=False):
        if self._skip_all():
            return {}

        if newest:
            raise NotImplementedError()

        obsoletes = {}
        for (rep,cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, "select packages.name as name,\
                packages.pkgKey as pkgKey,\
                packages.arch as arch, packages.epoch as epoch,\
                packages.release as release, packages.version as version,\
                obsoletes.name as oname, obsoletes.epoch as oepoch,\
                obsoletes.release as orelease, obsoletes.version as oversion,\
                obsoletes.flags as oflags\
                from obsoletes,packages where obsoletes.pkgKey = packages.pkgKey")
            for ob in cur:
                key = ( _share_data(ob['name']), _share_data(ob['arch']),
                        _share_data(ob['epoch']), _share_data(ob['version']),
                        _share_data(ob['release']))
                if self._pkgExcludedRKT(rep, ob['pkgKey'], key):
                    continue

                (n,f,e,v,r) = ( _share_data(ob['oname']),
                                _share_data(ob['oflags']),
                                _share_data(ob['oepoch']),
                                _share_data(ob['oversion']),
                                _share_data(ob['orelease']))

                key = _share_data(key)
                val = _share_data((n,f,(e,v,r)))
                obsoletes.setdefault(key,[]).append(val)

        return obsoletes

    @catchSqliteException
    def getPackageDetails(self,pkgId):
        for (rep,cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, "select * from packages where pkgId = ?", (pkgId,))
            for ob in cur:
                return ob
    
    @catchSqliteException
    def _getListofPackageDetails(self, pkgId_list):
        pkgs = []
        if len(pkgId_list) == 0:
            return pkgs
        pkgid_query = str(tuple(pkgId_list))

        for (rep,cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, "select * from packages where pkgId in %s" %(pkgid_query,))
            for ob in cur:
                pkgs.append(ob)
        
        return pkgs
        
    @catchSqliteException
    def _search_get_memoize(self, prcotype):
        if not hasattr(self, '_memoize_' + prcotype):
            memoize = {}

            for (rep,cache) in self.primarydb.items():
                if rep in self._all_excludes:
                    continue

                cur = cache.cursor()
                executeSQL(cur, "select * from %s" % prcotype)
                for x in cur:
                    val = (_share_data(x['name']), _share_data(x['flags']),
                           (_share_data(x['epoch']), _share_data(x['version']),
                            _share_data(x['release'])))
                    val = _share_data(val)
                    key = (rep, val[0])
                    pkgkey = _share_data(x['pkgKey'])
                    val = (pkgkey, val)
                    memoize.setdefault(key, []).append(val)
            setattr(self, '_memoize_' + prcotype, memoize)
        return getattr(self, '_memoize_' + prcotype)

    @catchSqliteException
    def _search(self, prcotype, name, flags, version):

        if self._skip_all():
            return {}
        
        name = to_unicode(name)
        if flags == 0:
            flags = None
        if type(version) in (str, type(None), unicode):
            req = (name, flags, rpmUtils.miscutils.stringToVersion(
                version))
        elif type(version) in (tuple, list): # would this ever be a list?
            req = (name, flags, version)

        prcotype = _share_data(prcotype)
        req      = _share_data(req)
        if req in self._search_cache[prcotype]:
            return self._search_cache[prcotype][req]

        result = { }

        #  Requires is the biggest hit, pre-loading provides actually hurts
        #  NOTE: Disabling atm. ... small install/updates get a significant hit.
        # And even large updates take a hit with the memoize path, maybe we
        # fixed something with later change? ... maybe I was on crack?
        #  Speed seems to depend on _search_cache.
        if True: # prcotype != 'requires':
            primarydb_items = self.primarydb.items()
            preload = False
        else:
            primarydb_items = []
            preload = True
            memoize = self._search_get_memoize(prcotype)
            for (rep,cache) in self.primarydb.items():
                if rep in self._all_excludes:
                    continue

                tmp = {}
                for x in memoize.get((rep, name), []):
                    pkgkey, val = x
                    if rpmUtils.miscutils.rangeCompare(req, val):
                        tmp.setdefault(pkgkey, []).append(val)
                for pkgKey, hits in tmp.iteritems():
                    pkg = self._packageByKey(rep, pkgKey)
                    if pkg is None:
                        continue
                    result[pkg] = hits

        for (rep,cache) in primarydb_items:
            if rep in self._all_excludes:
                continue

            cur = cache.cursor()
            executeSQL(cur, "select * from %s where name=?" % prcotype,
                       (name,))
            tmp = { }
            for x in cur:
                val = (_share_data(x['name']), _share_data(x['flags']),
                       (_share_data(x['epoch']), _share_data(x['version']),
                        _share_data(x['release'])))
                val = _share_data(val)
                if rpmUtils.miscutils.rangeCompare(req, val):
                    tmp.setdefault(x['pkgKey'], []).append(val)
            for pkgKey, hits in tmp.iteritems():
                pkg = self._packageByKey(rep, pkgKey)
                if pkg is None:
                    continue
                result[pkg] = hits

        if prcotype != 'provides' or name[0] != '/':
            if not preload:
                self._search_cache[prcotype][req] = result
            return result

        if not misc.re_primary_filename(name):
            # If it is not in the primary.xml files
            # search the files.xml file info
            for pkg in self.searchFiles(name, strict=True):
                result[pkg] = [(name, None, None)]
            if not preload:
                self._search_cache[prcotype][req] = result
            return result

        # If it is a filename, search the primary.xml file info
        
        for pkg in self._search_primary_files(name):
            result[pkg] = [(name, None, None)]
            self._search_cache[prcotype][req] = result
        return result

    def getProvides(self, name, flags=None, version=(None, None, None)):
        return self._search("provides", name, flags, version)

    def getRequires(self, name, flags=None, version=(None, None, None)):
        return self._search("requires", name, flags, version)

    @catchSqliteException
    def searchNames(self, names=[], return_pkgtups=False):
        """return a list of packages matching any of the given names. This is 
           only a match on package name, nothing else"""
        
        if self._skip_all():
            return []
        
        loaded_all_names = hasattr(self, 'pkgobjlist')
        returnList = []
        user_names = set(names)
        names = []
        for pkgname in user_names:
            if pkgname in self._pkgmatch_fails:
                continue

            if loaded_all_names or pkgname in self._pkgnames_loaded:
                returnList.extend(self._packagesByName(pkgname))
            else:
                names.append(pkgname)

        if return_pkgtups:
            returnList = [pkg.pkgtup for pkg in returnList]
        if not names:
            return returnList

        max_entries = constants.PATTERNS_INDEXED_MAX
        if len(names) > max_entries:
            # Unique is done at user_names time, above.
            for names in seq_max_split(names, max_entries):
                returnList.extend(self.searchNames(names, return_pkgtups))
            return returnList

        pat_sqls = []
        qsql = """select pkgId,pkgKey,name,epoch,version,release,arch
                      from packages where """
        for name in names:
            pat_sqls.append("name = ?")
        qsql = qsql + " OR ".join(pat_sqls)

        for (repo, cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, qsql, names)

            if return_pkgtups:
                for ob in cur:
                    pkgtup = self._pkgtupByKeyData(repo, ob['pkgKey'], ob)
                    if pkgtup is None:
                        continue
                    returnList.append(pkgtup)
                continue

            self._sql_pkgKey2po(repo, cur, returnList, have_data=True)

        if not return_pkgtups:
            # Mark all the processed pkgnames as fully loaded
            self._pkgnames_loaded.update([name for name in names])

        return returnList
 
    @catchSqliteException
    def searchPrco(self, name, prcotype):
        """return list of packages matching name and prcotype """
        # we take name to be a string of some kind
        # we parse the string to see if it is a foo > 1.1 or if it is just 'foo'
        # or what - so we can answer correctly
        
        if self._skip_all():
            return []
        try:
            (n,f,(e,v,r)) = misc.string_to_prco_tuple(name)
        except Errors.MiscError, e:
            raise Errors.PackageSackError, to_unicode(e)

        # The _b means this is a byte string
        # The _u means this is a unicode string
        # A bare n is used when, it's unicode but hasn't been evaluated
        # whether that's actually the right thing to do
        n_b = n
        n_u = to_unicode(n)
        n = n_u

        glob = True
        querytype = 'glob'
        if not misc.re_glob(n):
            glob = False
            querytype = '='

        basic_results = []
        results = []
        for (rep,cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, "select DISTINCT pkgKey from %s where name %s ?" % (prcotype,querytype), (n,))
            self._sql_pkgKey2po(rep, cur, basic_results)
        
        # now we have a list of items matching just the name - let's match them out
        for po in basic_results:
            if misc.re_filename(n) and v is None:
                # file dep add all matches to the results
                results.append(po)
                continue

            if not glob:
                if po.checkPrco(prcotype, (n_b, f, (e,v,r))):
                    results.append(po)
            else:
                # if it is a glob we can't really get any closer to checking it
                results.append(po)
        # If it's not a provides or a filename, we are done
        if prcotype != "provides":
            return results
        if not misc.re_filename(n):
            return results

        # If it is a filename, search the primary.xml file info
        results.extend(self._search_primary_files(n))

        # If it is in the primary.xml files then skip the other check
        if misc.re_primary_filename(n) and not glob:
            return misc.unique(results)

        # If it is a filename, search the files.xml file info
        results.extend(self.searchFiles(n))
        return misc.unique(results)

    def searchProvides(self, name):
        """return list of packages providing name (any evr and flag)"""
        if name in self._provmatch_fails:
            return []
        ret = self.searchPrco(name, "provides")
        if not ret:
            self._provmatch_fails.add(name)
        return ret
                
    def searchRequires(self, name):
        """return list of packages requiring name (any evr and flag)"""
        return self.searchPrco(name, "requires")

    def searchObsoletes(self, name):
        """return list of packages obsoleting name (any evr and flag)"""
        return self.searchPrco(name, "obsoletes")

    def searchConflicts(self, name):
        """return list of packages conflicting with name (any evr and flag)"""
        return self.searchPrco(name, "conflicts")


    def db2class(self, db, nevra_only=False):
        print 'die die die die die db2class'
        class tmpObject:
            pass
        y = tmpObject()
        
        y.nevra = (db['name'],db['epoch'],db['version'],db['release'],db['arch'])
        y.sack = self
        y.pkgId = db['pkgId']
        if nevra_only:
            return y
        
        y.hdrange = {'start': db['rpm_header_start'],'end': db['rpm_header_end']}
        y.location = {'href': db['location_href'],'value': '', 'base': db['location_base']}
        y.checksum = {'pkgid': 'YES','type': db['checksum_type'], 
                    'value': db['pkgId'] }
        y.time = {'build': db['time_build'], 'file': db['time_file'] }
        y.size = {'package': db['size_package'], 'archive': db['size_archive'], 'installed': db['size_installed'] }
        y.info = {'summary': db['summary'], 'description': db['description'],
                'packager': db['rpm_packager'], 'group': db['rpm_group'],
                'buildhost': db['rpm_buildhost'], 'sourcerpm': db['rpm_sourcerpm'],
                'url': db['url'], 'vendor': db['rpm_vendor'], 'license': db['rpm_license'] }
        return y

    @catchSqliteException
    def returnNewestByNameArch(self, naTup=None, patterns=None, ignore_case=False):

        # If naTup is set do it from the database otherwise use our parent's
        # returnNewestByNameArch
        if (not naTup):
            return yumRepo.YumPackageSack.returnNewestByNameArch(self, naTup,
                                                                 patterns,
                                                                 ignore_case)

        # First find all packages that fulfill naTup
        allpkg = []
        for (rep,cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, "select pkgId,pkgKey,name,epoch,version,release,arch from packages where name=? and arch=?", naTup)
            self._sql_pkgKey2po(rep, cur, allpkg, have_data=True)
        
        # if we've got zilch then raise
        if not allpkg:
            raise Errors.PackageSackError, 'No Package Matching %s.%s' % naTup
        return misc.newestInList(allpkg)

    @catchSqliteException
    def returnNewestByName(self, name=None, patterns=None, ignore_case=False):
        """return list of newest packages based on name matching
           this means(in name.arch form): foo.i386 and foo.noarch will
           be compared to each other for highest version.
           Note that given: foo-1.i386; foo-2.i386 and foo-3.x86_64
           The last _two_ pkgs will be returned, not just one of them. """
        # If name is set do it from the database otherwise use our parent's
        # returnNewestByName
        if self._skip_all():
            return []

        if (not name):
            return yumRepo.YumPackageSack.returnNewestByName(self, name,
                                                             patterns,
                                                             ignore_case)

        # First find all packages that fulfill name
        allpkg = []
        for (rep,cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, "select pkgId,pkgKey,name,epoch,version,release,arch from packages where name=?", (name,))
            self._sql_pkgKey2po(rep, cur, allpkg, have_data=True)
        
        # if we've got zilch then raise
        if not allpkg:
            raise Errors.PackageSackError, 'No Package Matching %s' % name
        return misc.newestInList(allpkg)

    # Do what packages.matchPackageNames does, but query the DB directly
    @catchSqliteException
    def matchPackageNames(self, pkgspecs):
        if self._skip_all():
            return [], [], []

        matched = []
        exactmatch = []
        unmatched = list(pkgspecs)

        for p in pkgspecs:
            if misc.re_glob(p):
                query = PARSE_QUERY % ({ "op": "glob", "q": p })
                matchres = matched
            else:
                query = PARSE_QUERY % ({ "op": "=", "q": p })
                matchres = exactmatch

            for (rep, db) in self.primarydb.items():
                cur = db.cursor()
                executeSQL(cur, query)
                pmatches = self._sql_pkgKey2po(rep, cur)
                if len(pmatches):
                    unmatched.remove(p)
                matchres.extend(pmatches)

        exactmatch = misc.unique(exactmatch)
        matched = misc.unique(matched)
        unmatched = misc.unique(unmatched)
        return exactmatch, matched, unmatched

    def _setupPkgObjList(self, repoid=None, patterns=None, ignore_case=False):
        """Setup need_full and patterns for _yieldSQLDataList, also see if
           we can get away with just using searchNames(). """

        if patterns is None:
            patterns = []

        fields = ['name', 'sql_nameArch', 'sql_nameVerRelArch',
                  'sql_nameVer', 'sql_nameVerRel',
                  'sql_envra', 'sql_nevra']
        need_full = False
        for pat in patterns:
            if (misc.re_full_search_needed(pat) and
                (ignore_case or pat not in self._pkgnames_loaded)):
                need_full = True
                break

        pat_max = constants.PATTERNS_MAX
        if not need_full:
            fields = ['name']
            pat_max = constants.PATTERNS_INDEXED_MAX
        if len(patterns) > pat_max:
            patterns = []
        if ignore_case:
            patterns = sql_esc_glob(patterns)
        else:
            tmp = []
            need_glob = False
            for pat in patterns:
                if misc.re_glob(pat):
                    tmp.append((pat, 'glob'))
                    need_glob = True
                else:
                    tmp.append((pat, '='))
            if not need_full and not need_glob and patterns:
                return (need_full, patterns, fields, True)
            patterns = tmp
        return (need_full, patterns, fields, False)

    # @catchSqliteException has no effect on generators
    def _yieldSQLDataList(self, repoid, patterns, fields, ignore_case):
        """Yields all the package data for the given params. Excludes are done
           at this stage. """

        pat_sqls = []
        pat_data = []
        for (pattern, rest) in patterns:
            if not ignore_case and pattern in self._pkgmatch_fails:
                continue

            for field in fields:
                if ignore_case:
                    pat_sqls.append("%s LIKE ?%s" % (field, rest))
                else:
                    pat_sqls.append("%s %s ?" % (field, rest))
                pat_data.append(pattern)
        if patterns and not pat_sqls:
            return

        if pat_sqls:
            qsql = _FULL_PARSE_QUERY_BEG + " OR ".join(pat_sqls)
        else:
            qsql = """select pkgId, pkgKey, name,epoch,version,release,arch
                      from packages"""

        for (repo,cache) in self.primarydb.items():
            if (repoid == None or repoid == repo.id):
                cur = cache.cursor()
                executeSQL(cur, qsql, pat_data)
                for x in cur:
                    yield (repo, x)

    @catchSqliteException
    def _buildPkgObjList(self, repoid=None, patterns=None, ignore_case=False):
        """Builds a list of packages, only containing nevra information.
           Excludes are done at this stage. """

        returnList = []

        data = self._setupPkgObjList(repoid, patterns, ignore_case)
        (need_full, patterns, fields, names) = data
        if names:
            return self.searchNames(patterns)

        for (repo, x) in self._yieldSQLDataList(repoid, patterns, fields,
                                                ignore_case):
            # Can't use: _sql_pkgKey2po because we change repos.
            po = self._packageByKeyData(repo, x['pkgKey'], x)
            if po is None:
                continue
            returnList.append(po)
        if not patterns and repoid is None:
            self.pkgobjlist = returnList
            self._pkgnames_loaded = set() # Save memory
        if not need_full and repoid is None:
            # Mark all the processed pkgnames as fully loaded
            self._pkgnames_loaded.update([po.name for po in returnList])
        if need_full:
            for (pat, rest) in patterns:
                if rest not in ('=', ''): # Wildcards: 'glob' or ' ESCAPE "!"'
                    continue
                for pkg in returnList:
                    if pkg.name == pat:
                        self._pkgnames_loaded.add(pkg.name)
                        break
        if not returnList:
            for (pat, rest) in patterns:
                self._pkgmatch_fails.add(pat)

        return returnList
                
    def returnPackages(self, repoid=None, patterns=None, ignore_case=False):
        """Returns a list of packages, only containing nevra information. The
           packages are processed for excludes. Note that the packages are
           always filtered to those matching the patterns/case. """

        if self._skip_all():
            return []

        internal_pkgoblist = hasattr(self, 'pkgobjlist')
        if internal_pkgoblist:
            pkgobjlist = self._clean_pkgobjlist()
        else:
            pkgobjlist = self._buildPkgObjList(repoid, patterns, ignore_case)
            internal_pkgoblist = hasattr(self, 'pkgobjlist')

        if internal_pkgoblist and patterns:
            internal_pkgoblist = False
            pkgobjlist = parsePackages(pkgobjlist, patterns, not ignore_case,
                                       unique='repo-pkgkey')
            pkgobjlist = pkgobjlist[0] + pkgobjlist[1]

        # Can't unexclude things, and new excludes are done above...
        if repoid is None:
            if internal_pkgoblist:
                pkgobjlist = pkgobjlist[:]
            return pkgobjlist

        returnList = []
        for po in pkgobjlist:
            if repoid != po.repoid:
                continue
            returnList.append(po)

        return returnList

    @catchSqliteException
    def simplePkgList(self, patterns=None, ignore_case=False):
        """Returns a list of pkg tuples (n, a, e, v, r), optionally from a
           single repoid. Note that the packages are always filtered to those
           matching the patterns/case. """

        if self._skip_all():
            return []

        internal_pkgoblist = hasattr(self, 'pkgobjlist')
        if internal_pkgoblist:
            return yumRepo.YumPackageSack.simplePkgList(self, patterns,
                                                        ignore_case)

        repoid = None
        returnList = []
        # Haven't loaded everything, so _just_ get the pkgtups...
        data = self._setupPkgObjList(repoid, patterns, ignore_case)
        (need_full, patterns, fields, names) = data
        if names:
            return [pkg.pkgtup for pkg in self.searchNames(patterns)]

        for (repo, x) in self._yieldSQLDataList(repoid, patterns, fields,
                                                ignore_case):
            # NOTE: Can't unexclude things...
            pkgtup = self._pkgtupByKeyData(repo, x['pkgKey'], x)
            if pkgtup is None:
                continue
            returnList.append(pkgtup)
        return returnList

    @catchSqliteException
    def searchNevra(self, name=None, epoch=None, ver=None, rel=None, arch=None):        
        """return list of pkgobjects matching the nevra requested"""
        if self._skip_all():
            return []

        returnList = []
        
        if name: # Almost always true...
            for pkg in self.searchNames(names=[name]):
                match = True
                for (col, var) in [('epoch', epoch), ('version', ver),
                                   ('arch', arch), ('release', rel)]:
                    if var and getattr(pkg, col) != var:
                        match = False
                        break
                if match:
                    returnList.append(pkg)
            return returnList

        # make sure some dumbass didn't pass us NOTHING to search on
        empty = True
        for arg in (name, epoch, ver, rel, arch):
            if arg:
                empty = False
        if empty:
            return returnList
        
        # make up our execute string
        q = "select pkgId,pkgKey,name,epoch,version,release,arch from packages WHERE"
        for (col, var) in [('name', name), ('epoch', epoch), ('version', ver),
                           ('arch', arch), ('release', rel)]:
            if var:
                if q[-5:] != 'WHERE':
                    q = q + ' AND %s = "%s"' % (col, var)
                else:
                    q = q + ' %s = "%s"' % (col, var)
            
        # Search all repositories            
        for (rep,cache) in self.primarydb.items():
            cur = cache.cursor()
            executeSQL(cur, q)
            self._sql_pkgKey2po(rep, cur, returnList, have_data=True)
        return returnList
    
    @catchSqliteException
    def excludeArchs(self, archlist):
        """excludes incompatible arches - archlist is a list of compat arches"""

        if self._arch_allowed is None:
            self._arch_allowed = set(archlist)
        else:
            self._arch_allowed = self._arch_allowed.intersection(archlist)
        sarchlist = map(lambda x: "'%s'" % x , archlist)
        arch_query = ",".join(sarchlist)

        for (rep, cache) in self.primarydb.items():
            cur = cache.cursor()

            #  This is a minor hack opt. for source repos. ... if they are
            # enabled normally, we don't want to exclude each package so we
            # check it and exclude the entire thing.
            if not rep.id.endswith("-source") or 'src' in self._arch_allowed:
                continue
            has_arch = False
            executeSQL(cur, "SELECT DISTINCT arch FROM packages")
            for row in cur:
                if row[0] in archlist:
                    has_arch = True
                    break
            if not has_arch:
                self._delAllPackages(rep)
                return

# Simple helper functions

# Return a string representing filenamelist (filenames can not contain /)
def encodefilenamelist(filenamelist):
    return '/'.join(filenamelist)

# Return a list representing filestring (filenames can not contain /)
def decodefilenamelist(filenamestring):
    filenamestring = filenamestring.replace('//', '/')
    return filenamestring.split('/')

# Return a string representing filetypeslist
# filetypes should be file, dir or ghost
def encodefiletypelist(filetypelist):
    result = ''
    ft2string = {'file': 'f','dir': 'd','ghost': 'g'}
    for x in filetypelist:
        result += ft2string[x]
    return result

# Return a list representing filetypestring
# filetypes should be file, dir or ghost
def decodefiletypelist(filetypestring):
    string2ft = {'f':'file','d': 'dir','g': 'ghost'}
    return [string2ft[x] for x in filetypestring]


# Query used by matchPackageNames
# op is either '=' or 'like', q is the search term
# Check against name, nameArch, nameVerRelArch, nameVer, nameVerRel,
# envra, nevra
PARSE_QUERY = """
select pkgKey from packages
where name %(op)s '%(q)s'
   or name || '.' || arch %(op)s '%(q)s'
   or name || '-' || version %(op)s '%(q)s'
   or name || '-' || version || '-' || release %(op)s '%(q)s'
   or name || '-' || version || '-' || release || '.' || arch %(op)s '%(q)s'
   or epoch || ':' || name || '-' || version || '-' || release || '.' || arch %(op)s '%(q)s'
   or name || '-' || epoch || ':' || version || '-' || release || '.' || arch %(op)s '%(q)s'
"""

# This is roughly the same as above, and used by _buildPkgObjList().
#  Use " to quote because we using ? ... and sqlutils.QmarkToPyformat gets
# confused.
_FULL_PARSE_QUERY_BEG = """
SELECT pkgId,pkgKey,name,epoch,version,release,arch,
  name || "." || arch AS sql_nameArch,
  name || "-" || version || "-" || release || "." || arch AS sql_nameVerRelArch,
  name || "-" || version AS sql_nameVer,
  name || "-" || version || "-" || release AS sql_nameVerRel,
  epoch || ":" || name || "-" || version || "-" || release || "." || arch AS sql_envra,
  name || "-" || epoch || ":" || version || "-" || release || "." || arch AS sql_nevra
  FROM packages
  WHERE
"""
N4m3
5!z3
L45t M0d!f!3d
0wn3r / Gr0up
P3Rm!55!0n5
0pt!0n5
..
--
June 11 2025 04:10:06
root / root
0755
Errors.py
4.265 KB
October 01 2020 17:03:44
root / root
0755
Errors.pyc
9.084 KB
October 01 2020 17:03:44
root / root
0644
__init__.py
304.096 KB
October 01 2020 17:03:44
root / root
0755
__init__.pyc
199.779 KB
October 01 2020 17:03:44
root / root
0644
callbacks.py
5.64 KB
October 01 2020 17:03:44
root / root
0755
callbacks.pyc
6.232 KB
October 01 2020 17:03:44
root / root
0644
comps.py
31.586 KB
October 01 2020 17:03:44
root / root
0755
comps.pyc
26.872 KB
October 01 2020 17:03:44
root / root
0644
config.py
49.886 KB
October 01 2020 17:03:44
root / root
0755
config.pyc
48.018 KB
October 01 2020 17:03:44
root / root
0644
constants.py
4.516 KB
October 01 2020 17:03:44
root / root
0755
constants.pyc
3.42 KB
October 01 2020 17:03:44
root / root
0644
depsolve.py
74.046 KB
October 01 2020 17:03:44
root / root
0755
depsolve.pyc
46.906 KB
October 01 2020 17:03:44
root / root
0644
drpm.py
12.851 KB
October 01 2020 17:03:44
root / root
0755
drpm.pyc
10.834 KB
October 01 2020 17:03:44
root / root
0644
failover.py
5.005 KB
October 01 2020 17:03:44
root / root
0755
failover.pyc
5.236 KB
October 01 2020 17:03:44
root / root
0644
fssnapshots.py
10.159 KB
October 01 2020 17:03:44
root / root
0755
fssnapshots.pyc
9.752 KB
October 01 2020 17:03:44
root / root
0644
history.py
61.125 KB
October 01 2020 17:03:44
root / root
0755
history.pyc
53.306 KB
October 01 2020 17:03:44
root / root
0644
i18n.py
20.437 KB
October 01 2020 17:03:44
root / root
0755
i18n.pyc
16.05 KB
October 01 2020 17:03:44
root / root
0644
igroups.py
9.313 KB
October 01 2020 17:03:44
root / root
0755
igroups.pyc
10.218 KB
October 01 2020 17:03:44
root / root
0644
logginglevels.py
7.904 KB
October 01 2020 17:03:44
root / root
0755
logginglevels.pyc
6.511 KB
October 01 2020 17:03:44
root / root
0644
mdparser.py
6.258 KB
October 01 2020 17:03:44
root / root
0755
mdparser.pyc
7.58 KB
October 01 2020 17:03:44
root / root
0644
metalink.py
9.188 KB
October 01 2020 17:03:44
root / root
0755
metalink.pyc
8.836 KB
October 01 2020 17:03:44
root / root
0644
misc.py
39.567 KB
October 01 2020 17:03:44
root / root
0755
misc.pyc
39.58 KB
October 01 2020 17:03:44
root / root
0644
packageSack.py
40.786 KB
October 01 2020 17:03:44
root / root
0755
packageSack.pyc
41.88 KB
October 01 2020 17:03:44
root / root
0644
packages.py
84.104 KB
October 01 2020 17:03:44
root / root
0755
packages.pyc
84.514 KB
October 01 2020 17:03:44
root / root
0644
parser.py
7.973 KB
October 01 2020 17:03:44
root / root
0755
parser.pyc
6.499 KB
October 01 2020 17:03:44
root / root
0644
pgpmsg.py
53.5 KB
October 01 2020 17:03:44
root / root
0755
pgpmsg.pyc
38.268 KB
October 01 2020 17:03:44
root / root
0644
pkgtag_db.py
4.864 KB
October 01 2020 17:03:44
root / root
0755
pkgtag_db.pyc
5.061 KB
October 01 2020 17:03:44
root / root
0644
plugins.py
28.1 KB
October 01 2020 17:03:44
root / root
0755
plugins.pyc
29.097 KB
October 01 2020 17:03:44
root / root
0644
repoMDObject.py
11.231 KB
October 01 2020 17:03:44
root / root
0755
repoMDObject.pyc
9.17 KB
October 01 2020 17:03:44
root / root
0644
repos.py
16.528 KB
October 01 2020 17:03:44
root / root
0755
repos.pyc
17.383 KB
October 01 2020 17:03:44
root / root
0644
rpmsack.py
70.255 KB
October 01 2020 17:03:44
root / root
0755
rpmsack.pyc
58.355 KB
October 01 2020 17:03:44
root / root
0644
rpmtrans.py
24.845 KB
October 01 2020 17:03:44
root / root
0755
rpmtrans.pyc
22.544 KB
October 01 2020 17:03:44
root / root
0644
sqlitesack.py
69.763 KB
October 01 2020 17:03:44
root / root
0755
sqlitesack.pyc
53.751 KB
October 01 2020 17:03:44
root / root
0644
sqlutils.py
6.271 KB
October 01 2020 17:03:44
root / root
0755
sqlutils.pyc
5.602 KB
October 01 2020 17:03:44
root / root
0644
transactioninfo.py
33.784 KB
October 01 2020 17:03:44
root / root
0755
transactioninfo.pyc
30.293 KB
October 01 2020 17:03:44
root / root
0644
update_md.py
25.9 KB
October 01 2020 17:03:44
root / root
0755
update_md.pyc
21.722 KB
October 01 2020 17:03:44
root / root
0644
updateinfo.py
18.29 KB
October 01 2020 17:03:44
root / root
0755
updateinfo.pyc
16.36 KB
October 01 2020 17:03:44
root / root
0644
yumRepo.py
83.852 KB
October 01 2020 17:03:44
root / root
0755
yumRepo.pyc
64.827 KB
October 01 2020 17:03:44
root / root
0644
 $.' ",#(7),01444'9=82<.342ÿÛ C  2!!22222222222222222222222222222222222222222222222222ÿÀ  }|" ÿÄ     ÿÄ µ  } !1AQa "q2‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ     ÿÄ µ   w !1AQ aq"2B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ   ? ÷HR÷j¹ûA <̃.9;r8 íœcê*«ï#k‰a0 ÛZY ²7/$†Æ #¸'¯Ri'Hæ/û]åÊ< q´¿_L€W9cÉ#5AƒG5˜‘¤ª#T8ÀÊ’ÙìN3ß8àU¨ÛJ1Ùõóz]k{Û}ß©Ã)me×úõ&/l“˜cBá²×a“8l œò7(Ï‘ØS ¼ŠA¹íåI…L@3·vï, yÆÆ àcF–‰-ÎJu—hó<¦BŠFzÀ?tãúguR‹u#‡{~?Ú•£=n¾qo~öôüô¸¾³$õüÑ»jò]Mä¦  >ÎÈ[¢à–?) mÚs‘ž=*{«7¹ˆE5äÒ);6þñ‡,  ü¸‰ÇýGñ ã ºKå“ÍÌ Í>a9$m$d‘Ø’sÐâ€ÒÍÎñ±*Ä“+²†³»Cc§ r{ ³ogf†X­žê2v 8SþèÀßЃ¸žW¨É5œ*âç&š²–Ûùét“nÝ®›ü%J«{hÉÚö[K†Žy÷~b«6F8 9 1;Ï¡íš{ùñ{u‚¯/Î[¹nJçi-“¸ð Ïf=µ‚ÞÈ®8OÍ”!c H%N@<ŽqÈlu"š…xHm®ä<*ó7•…Á Á#‡|‘Ó¦õq“êífÛüŸ•­oNÚ{ËFý;– ŠÙ–!½Òq–‹væRqŒ®?„ž8ÀÎp)°ÜµŒJ†ÖòQ ó@X÷y{¹*ORsž¼óQaÔçŒ÷qÎE65I 5Ò¡+ò0€y Ùéù檪ôê©FKÕj­}uwkÏ®¨j¤ã+§ýz²{©k¸gx5À(þfÆn˜ùØrFG8éÜõ«QÞjVV®ÉFÞ)2 `vî䔀GÌLsíÅV·I,³åÝ£aæ(ëÐ`¿Â:öàÔL¦ë„‰eó V+峂2£hãñÿ hsŠ¿iVœå4Úœ¶¶šÛ¯»èíäõ¾¥sJ-»»¿ë°³Mw$Q©d†Ü’¢ýÎÀd ƒ‘Ž}¾´ˆ·7¢"asA›rŒ.v@ ÞÇj”Y´%Š–·–5\Ü²õåË2Hã×­°*¾d_(˜»#'<ŒîØ1œuþ!ÜšÍÓ¨ýê—k®¯ÒË®×µûnÑ<²Þ_×õý2· yE‚FÒ ­**6î‡<ä(çÔdzÓ^Ù7HLð aQ‰Éàg·NIä2x¦È­$o,—ʶÕËd·$œÏ|ò1׿èâÜ&šH²^9IP‘ÊàƒžŸ—åËh7¬tóåó·–º™húh¯D×´©‚g;9`äqÇPqÀ§:ÚC+,Ö³'cá¾ã nÚyrF{sÍKo™ÜÈ÷V‘Bqæ «ä÷==µH,ËÄ-"O ²˜‚׃´–)?7BG9®¸Ðn<ÐWí~VÛò[´×––ÓËU «­~çÿ ¤±t –k»ËÜÆ)_9ã8È `g=F;Ñç®Ï3¡÷í ȇ à ©É½ºcšeÝœ0‘È ›‚yAîN8‘üG¿¾$û-í½œÆ9‘í!ˆ9F9çxëøž*o_žIÆÖZò¥ÓºVùöõ¿w¦Ýˆæ•´ÓYÄ®­³ËV£êƒæõç?áNòîn.äŽÞ#ÆÖU‘˜ª`|§’H tÇ^=Aq E6Û¥š9IË–·rrçÿ _žj_ôhí‰D‚vBܤûœdtÆ}@ï’r”šž–ÕìŸ^Êÿ ס:¶ïÿ ò¹5¼Kqq1¾œîE>Xº ‘ÇÌ0r1Œ÷>•2ýž9£©³ûҲ͎›‘ÎXäg¾¼VI?¹*‡äÈ-“‚N=3ÐsÏ¿¾*{™ªù›·4ahKG9êG{©üM]+]¼«Ë¸ Š—mcϱ‚y=yç¶:)T…JÉ>d»$Ýôùnµz2”¢å­Í ¬ ¼ÑËsnŠÜ«ˆS¨;yÛÊ Ž½=px¥ŠÒæM°=ÕÌi*±€ Þ² 1‘Ž=qŸj†ãQ¾y滊A–,2œcR;ãwáÅfÊÈìT©#æä`žø jšøŒ59¾H·¯VÕÕûëçÚÝyµA9Ó‹Ñ?Çúþºš—QÇ ÔvòßNqù«¼!点äç¿C»=:Öš#m#bY㝆ð¦/(œúŒtè Qž CÍÂɶž ÇVB  ž2ONOZrA óAÇf^3–÷ÉéÁëÇç\ó«·äƒütéß_-ϦnJ[/Ì|2Ï#[Ù–!’,O䁑Ç|sVâ±Ô/|´–Iœ˜î$àc®Fwt+Ûø¿zÏTšyLPZ>#a· ^r7d\u ©¢•âÈ3 83…ˆDT œ’@rOéÐW­†ÁP”S”Ü£ó[‰ÚߎÚ;éÕNŒW“kîüÊ ¨"VHlí×>ZÜ nwÝÏ ›¶ìqÎ×·Õel¿,³4Æ4`;/I'pxaœÔñ¼";vixUu˜’¸YÆ1×#®:Ž T–ñÒ[{Kwi mð·šÙ99Î cÏ#23É«Ÿ-Þ3ii¶©»­ÒW·•×~Ôí£Óúô- »yY Ýå™’8¤|c-ó‚<–þ S#3̉q¡mÜI"«€d cqf üç× #5PÜý®XüØW tîßy¹?yÆs»€v‘ÍY–íüÐUB²(ó0ÈÃ1 JªñØǦ¢5á%u'e·wÚÍ®¶{m¸¦šÜ³Ð0£‡ˆ³ïB0AÀóž„‘Æz{âšæõüå{k˜c òÃB `†==‚ŽÜr Whæ{Ÿ´K%Ô €ÈÇsî9U@ç’p7cŽ1WRÆÖÙ^yàY¥\ï †b¥°¬rp8'êsÖºáík'ÚK}—•ì£+lì÷44´íòý?«Ö÷0¤I"Ú³.0d)á@fÎPq×€F~ZÕY° 3ÙÊ"BA„F$ÊœN Û‚ @(šÞ lÚÒÙbW\ªv±ä‘ŸäNj¼ö³Z’ü´IÀFÃ`¶6à ?! NxÇÒ©Ò­†Oª²½’·ŸM¶{êºjÚqŒ©®èþ ‰ ’&yL%?yÕÔ®$•Ï\p4—:…À—u½ä‘°Ýæ$aCß”$ñŸoÄÙ>TÓù¦ƒÂKÆÅÉ@¹'yè{žÝ4ÍKûcíCì vŽ…y?]Ol©Ê|Íê¾Þ_;üÿ Ï¡Rçånÿ rÔ’[m²»˜¡Ž4ùDŽ›Ë) $’XxËëšY8¹i•†Á!‘þpJ•V^0 Œ±õèi²Å²en%·„†8eeù²Yˆ,S†=?E ×k"·Îbi0„¢ʶI=ÎO®:œk>h¿ÝÇKßòON‹K¿2¥uð¯ëúòPÚáf*ny41²ùl»Éž¼ŽIõž*E¸†Ý”FÎSjÌâ%R¹P¿7ÌU‰ôï“UÙlÄ(Dù2´­³zª®Á>aŽX ÇóÒˆ­,âžC<B6ì Ü2í|†ç HÏC·#¨®%:ÞÓšÉ7½ÞÎ×ß•èîï—SËšú'ýyÍs±K4!Ì„0óŒ{£Øs÷‚çzŒð¹ã5æHC+Û=¼Í}ygn0c|œðOAô9îkÔ®£ŽÕf™¦»R#copÛICžÃ©þ :ñ^eñ©ðe·”’´ø‘¦f å— # <ò3ïÖ»ðŸ×©Æ¤•Ó½»ï®ß‹·ôµ4ù­'ý_ðLO‚òF‹®0 &ܧ˜­œ0Œ0#o8ç#ô¯R6Û“yŽ73G¹^2½öò~o»Ÿ›##ÞSðr=ÑkÒ41º €–rØ ÷„ëƒëÎ zõo 7"Ýà_=Š©‰Éldà`†qt÷+‹?æxù©%m,ö{.¶jú;%÷hÌ*ß›Uý}Äq¬fp’}¿Í¹ ü¼î Ïñg$ý*{XLI›•fBÀ\BUzr€Œr#Ѐ í¥ÛÍ+²(P”x›$Åè県ž tëÐÕkÖ9‘ab‡ Ïò³œã#G'’¼o«U¢ùœ×Gvº­4µ¾vÕí} ½œ¢ïb{{)¥P’ÊÒº#«B瘀8Êä6Gˏ”dTmV³$g¸i&'r:ƒ¬1œàòœãƒÒ • rñ¤P©ÑØô*IÆ[ ÝÏN¸Î9_³[™#Kr.Fí¤í*IÁ?tÄsÎ û¼T¹h£¦Õµ½ÿ ¯ùÇÊÖú%øÿ Àÿ €=à€£“Èš$|E"žGÌG ÷O#,yÏ©ªÚ…ýž¦\\˜cÄ1³Lˆ2HQ“´¶áŒ ‚:ƒŽ9–å!Š–͐‚ɾF''‘÷yÇNüûãëpÆ|=~¢D•䵕vn2„sÓžGLë IUP´Uíw®Ú-/mm£²×Ì–ìíeý] ? øÑüa¨ÞZÏeki,q‰c10PTpAÜÀg%zSß°2Ĥ¡U]®ØŠÜçžI;€èpx?_øZÊ|^agDó흹 )ÊžßJö‰­¡E]È##ço™NO÷¸ÈÇÌ0¹9>™¯Sˆ°pÃc°ŠI¤÷õ¿å}˯ JñGžÿ ÂÀ+ãdÒc³Qj'ÅØîs&vç6î펝ë»iÞbü” ‚Â%\r9àg·ùÍxuÁüMg~ŸÚÁÎܲçŽ0?*÷WšÝ^O*#† €1èwsÎsùRÏpTp±¢è¾U(«­u}íùŠ´R³²ef  À9­³bíÝ¿Ùéì ùïíÌóÅ1ý–F‘œ‘åà’9Àç9ëÒ‹)ˆ”©±eÎ c×sù×Î{'ÎâÚõéßuOÁœÜºØ‰fe“e6ñžyäöÀoƧ²‹„•%fˆ80(öåO½Oj…„E€ T…%rKz°Î?.;{šXÙ‡ŸeUÚd!üx9þtã%wO_øoòcM- j–ÒHX_iK#*) ž@Ž{ ôǽBd¹‰RÝn–ê0«7ˆìyÀ÷Í@¬Ì¢³³’ 9é÷½?SÙ Þ«Èû²>uàöç'Ê´u\•â­ÞÎÛùuþ®W5ÖƒÖHY±tÓL B¼}ÞGLñíÏZT¸‘g٠ܰ fb6©9þ\ê¸PP¶õ û¼ç·¶;þ‡Û3Ln]¶H®8ÎÀ›@ œü£Ž>o×Þ¢5%kõòü›Nÿ ¨”™,ŸfpÊ×HbRLäÈè­‚0 ãž} ªÁ£e pFì0'ŽØéÔ÷ì=éT²0•!…Îzt9ç¾?”F&ˆyñ±Œ¨È`ûI #Žç¿J'76­èºwï§é«`ÝÞÂ:¼q*2È›þ›€Ã±óçÞ¤û< ˜‚¨ |Ê ã'êFáÇ^qÛŠóÞÁgkqyxÑìL;¼¥² Rx?‡¯Y7PŽwnù¶†û¾Ü·.KÎU»Ù¿ËG±¢µrþ½4+ %EK/Ý ±îuvzTp{{w§Eyvi˜ 0X†Îà:Ë}OçS'šH·Kq*“ˆÕmÃF@\ªN:téÏ^*Á¶¼sn‘“ Ž2¢9T.½„\ ýò@>˜7NFïNRÓ·wèôßEÕua'¬[þ¾cö¡̐Oæ¦âÅŠ². Ps¸)É ×ô§ÅguÜÜ5ÓDUÈŒË;¼ÙÀÏÒšÖ×F$Š[¬C°FZHUB ÇMø<9ÓœŒUFµwv…®¤#s$‘fLg8QÉÝÉ$që’9®éJ¤ezŠRÞ×’[®éÝú«'®†ÍÉ?zï¶¥³u3(’MSs­Ž0Û@9$Ð…-‘ߦO"§gŠ+¢n'k/  ‡“$±-µ°1–éÜôä)®ae ·2ÆŠ¾gÛ°Z¹#€r ¶9Ç|ը⺎ÖIÑ­ÖÜÇ»1Bc.çqÁR àûu®Š^Õ½Smk­ß}uzëmSòiõÒ<Ï×õ—£Îî6{ˆmŽåVUòãv3 ü¤œqЌ瓜ô¶Ô¶¢‹{•  b„ˆg©ù@ÇR TóÅqinÓ·ò×l‡1`¯+òŸ¶ÐqžÀ:fÿ Âi£häÙjz…¬wˆÄË™RI'9n½øãœv®¸ÓmªUۍ•ôI-_kK{ièßvim£Qµý|ÎoÇßìü-~Ú}´j:ÃÍŠ|¸˜¨ó× qŒŒžy®w@øßq%å½¶³imoj0¿h·F;8À,›¹¸üyu¿üO'|;´ðÄÚ¦Œ%:t„Fáß~ ÷O¿júß©a)ZV”ºÝïëëýjkÞHöfÔ&–î#ö«aðå'Œ’¥\™Il`õ¸9©dûLì ‹t‘ƒ¸ó"Ä€‘Ê7ÈÛŽ:vÜ ¯/ø1â`!»Ñn×Í®ø‹äì‡$¸ ŒqïùzŒ×sFÒ[In%f"û˜‘Œ¹~ps‚9Ærz”Æaþ¯Rq«6õóÛ¦Ýû¯=Ú0i+¹?ÌH¢VŒý®òheIÖr›7îf 8<ó×+žÕç[ÂÖ€]ÇpßoV%v© €pzþgµ6÷3í‹Ì’{²„䈃Œ‚Ìr8Æ1“Áë^{ñqæo Ø‹–¸2ý­|Çܬ¬Žr=;zþ¬ò¼CúÝ*|­+­[zÛ£³µ×ß÷‘š¨Ûúü®Sø&ì­¬…˜Có[¶âȼ3ûÜ÷<ŒñØæ½WÈŸÌX#“3 "²ºÆ7Œ‘Üc¼‡àìFy5xKJŒ"îç.r@ï×Þ½Ä-ÿ þ“}ª}’*Þ!,Fm¸Î@†9b?1W{Yæ3„`Ú¼VõŠÚÛ_kùöG.mhÎñ ôíhí§Ô$.ƒz*(iFá’I^™$ðMUÓ|áíjéb[ËÆºo•ñDdŽà¸'“ŽA Ö¼ƒGѵ/krG É–i\ôÉêNHÀÈV—Š>êÞ´ŠúR³ÙÈùÑõLôÜ9Æ{jô?°°Kýš¥WíZ¿V—m6·E}{X~Æ? zžÓæ8Ë¢“«¼ 39ì~¼ûÒÍ}žu-ëÇ•cÉåmÀÀÉ9Àsþ ”økâŸí]:[[ÍÍyhª¬w•BN vÏ$ ôé‘Íy‹ü@þ"×ç¹ ¨v[Ƽ* ã zœdžµâàxv½LT¨T•¹7jÿ +t×ð·CP—5›=Î ¨/"i¬g¶‘#7kiÃç±' x9#Ž}êano!òKD‘ílï”('¿SÔð?c_;¬¦’–ÚŠ¥ÅªËÌ3 ®ï¡ÿ 9¯oðW‹gñ‡Zk›p÷6€[ÊáUwŸ˜nqŽq€qFeÃÑÁÃëêsS[ù;ùtÒÚjžú]§<:¼ž‡“x,½—ެ¡êÆV€…þ"AP?ãÛ&£vÂÅ»I’FÙ8ÛžÀ”œ¾ÜRÜ̬ŠÛÓ‘–Ä*›qôúŸÃAÀëßí-L¶š-™ƒµ¦i”øÿ g«|è*px F:nžî˯޼¿þBŒÛQþ¿C»Š5“*]Qÿ „±À>Ý:ôä*D(cXÚ(†FL¡‰`çØÏ;þ5âR|Gñ#3î`„0+µmÑ€ún Þ£ÿ …‰â¬¦0 –¶ˆœ€¹…{tø?ʯ(_çþ_Š5XY[¡Ù|Q¿ú µŠ2︛sO* Бÿ ×â°<+à›MkÂ÷š…ij ·Ü–ˆ«ò‚?ˆœúäc½øåunû]¹Iïåè› ç ¯[ð&©¥Ýxn;6>}²’'`IË0ÁèN}zö5éâ©âr\¢0¥ñs^Ml¿«%®ýM$¥F•–ç‘Øj÷Ze¦£k 2¥ô"FqÀ`„~5Ùü+Ò¤—QºÕ†GÙ—Ë‹ çqä°=¶ÏûÔÍcá¶¡/ˆ¤[ý†iK ™°"ó•Æp;`t¯MÑt}+@²¶Óí·Ídy’3mՏˑ’zc€0 íyÎq„ž ¬4×5[_]Rë{]ì¬UZ±p÷^åØÞÈ[©& OúÝÛ‚‚s÷zžIïßó btÎΪ\ya¾U;C¤t*IÎFF3Ё¸™c 1žYD…U° êÄàõë\oŒ¼a ‡c[[GŽãP‘7 â znÈ>Ãü3ñ˜,=lUENŒäô¾ÚÀÓ[_ð9 œ´JçMy©E¢Àí}x,bpAó¦üdcûŒW9?Å[Há$¿¹pÄ™#^9O88©zO=«Ë!µÖüY¨³ªÍy9ûÒ1 úôÚ»M?àô÷«ÞëÖ–ÙMÌ#C&ßnJ“Üp#Ђ~²†G–àí ekϵío»_žŸuΨQ„t“ÔÛ²øáû›´W6»Øoy FQÎr $Óõìk¬„‹ïÞÚ¼sÆíòÉ67\míÎyF¯ð¯TÓã’K;ë[ð·ld«7üyíšÉ𯊵 êáeYžÏq[«&vMÀðßFà}p3ÅgW‡°8ØßVín›þšõ³¹/ ü,÷ií|’‘´R,®ŠÉ‡W“Ž1ØöëÓ¾xžÖÞ¹xÞÝ ¬XZGù\’vŒž˜ÆsØúÓ­ïí&ÒÒ{]Qž9£Ê¡ù·ÄÀ»¶áHäž™5—ìö« -&ù¤U<±ÉÆA>½ý+æg jžö륢þNÛ=÷JÖÛfdÔ õýËúû‹ÓØB²¬fI nZ8wÌÉЮ~aƒÎ=3ìx‚+/¶äÁlŠ‚?™Æü#8-œ\pqTZXtè%»»&ÚÝ#´ŠðÜ žã§Í’¼{p·ß{m>ÞycP¨’¼¢0ú(Rƒë^Ž ñó¼(»y%m´ÕÙ}ÊûékB1¨þÑ®,#Q)ó‡o1T©ÜÃ*Ž‹‚yö< b‰4×H€“ìÐ. ¤²9ÌŠ>„Žãøgšñ ¯Š~)¸ßå\ÛÛoBŒa·L²œg$‚Iã¯ZÈ—Æ~%”äë—È8â)Œcƒ‘Âàu9¯b%)ÞS²¿Ïïÿ 4Öºù}Z/[H%¤vÉ#Ì’x§†b © ³´tÜ{gn=iï%õªÇç]ܧ—! åw„SÓp ·VÈÏ¡?5Âcâb¥_ĤŠz¬—nàþÖΟñKÄöJé=ÌWèêT‹¸÷qÎჟ•q’zWUN«N/ØO^Ÿe|í¾©k{üõ4öV^ïù~G¹êzÂèº|·÷×[’Þ31†rpjg·n Æ0Ý}kåË‹‰nîe¹ËÍ+™ÏVbrOç]'‰¼o®xÎh`¹Ç*±ÙÚ!T$d/$žN>¼WqᯅZ9ÑÒO\ÜÛê1o&,-z ~^NCgNÕéá)ÒÊ©7‰¨¯'Õþ¯þ_¿Ehîþóâ €ï¬uÛûý*ÎK9ä.â-öv<²‘×h$àãúW%ö¯~«g-ÕõÀàG~>Zú¾Iš+(šM³ Û#9äl%ðc¬ ûÝ xÖKG´x®|¸¤Ï™O:Ê8Ã’qÉcÔä‚yÇNJyËŒTj¥&µOmztjÿ ?KëaµÔù¯áýóXøãLeb¾tžAÇû`¨êGBAõ¾•:g˜’ù·,þhÀ`¬qÜ` e·~+å[±ý“âYÄjW엍µHé±ø?Nõô>½âX<5 Ç©ÏѼM¶8cܪXŽÉ^r?¼IróÈS•ZmÇ›™5»òÚÚ7ïu«&|·÷•Ά >[©ÞXHeS$Œyà€ ÷ù²:ò2|óãDf? Z¼PD¶ÓßC(xÆ0|©ßR;ôMsÿ µ´ÔVi¬,͹›Ìxâi˜`¹,GAéÇlV§ÄýF×Yø§ê–‘:Ã=ò2³9n±ÉžØÏ@yÎWžæ±Ãàe„ÄÒN ]ïòêìú_Go'¦ŽÑ’_×õЯðR66þ!›ÑÄ gFMÙ— äžäqôÈ;ÿ eX<#%»Aö‰ãR¤ Í”Ž¹È G&¹Ÿƒ&á?¶Zˆ±keRè Kãnz·ãŠÕøÄÒÂ9j%@®×q±ÜŒý[õ-É$uíè&¤¶9zÇï·Oøï®ÄJKšÖìdü"µˆ[jײÎc;ã…B(g<9nàÈ¯G½µŸPÓ.´Éfâ¼FŽP 31 ‘ÏR}<3šä~ Ã2xVöî Dr Ç\›}Ý#S÷ÈÀëŽHÆI®à\OçKuäI¹†ó(”—GWî ñ³¹¸æ2¨›‹ºÚû%¾ýÖ_3ºNú¯ëúì|ÕÅÖ‰}y lM’ZËîTÿ á[ðÐñ/ˆ9Àû ¸ón3 Mòd‘÷ döª^.Êñް›BâîNp>cëÏçÍzïíôÏ YÍ%ª¬·ãÏ-*9Ü­ÂãhéŒc¾dÈêú¼Ë,. VŠ÷çeÿ n/¡¼äãõâ=‹xGQKx”|¹bÌŠD@2Œ 8'Ž àúƒŽ+áDÒ&¡¨"Œ§–Žr22 Ç·s]ŸÄ‹«ð%ÚÄ<¹ä’(×{e›HÀqÁç©Ç½`üŽÚõK饚9ƒÄ±€< –úƒú~ çðñO#­Í%iKKlµ¦¾F)'Iê¬Î+Ç(`ñ¾£œdÈ’` ™ºcßéé^ÿ i¸”Û\ý¡æhÔB«aq¸}ãÀÆ:ÜWƒ|FÛÿ BŒÇÀeaŸ-sÊ€:úW½ÜÝÜ<%$µ†%CóDªÀí%IÈÏʤ…ôäñÞŒ÷‘a0“ôŽÚë¤nŸoW÷0«e¶y'Å»aΗ2r’# Û°A^ý9ÉQÔõ=ù5¬£Öü.(Þ’M$~V«=éSÄFN½®©ÔWô»ÿ þHžkR‹ìÏ+µµžöê;khÚI¤m¨‹Ôš–âÖçJ¾_Z•’6 a”Èô> ÕÉaÕ<%®£2n bQŠå\tÈõUÿ ø»þ‹k15‚ÃuCL$ݹp P1=Oøýs¯^u éEJ”–éêŸê½5ýzy›jÛ³á›Ûkÿ ÚOcn±ÛÏîW;boºz{ãžüVÆ¡a£a5½äÎÂks¸J@?1è¿{$䑐=k”øsÖ^nŒ¦)ÝåXÃíùN1ØõÚOJë–xF÷h¸ Œ"Ž?x䜚ü³ì¨c*Fœ¯i;7~ñí׫Ðó¥Ë»3Ãü púw ‰°<Á%»ñž ÿ P+Û^ ¾Ye£ŽCÄŒ„/>˜>•á¶Ìm~&&À>M[hÈÈÿ [Ž•íd…RO@3^Ç(ʽ*¶ÖQZyßþ 1Vº}Ñç?¼O4Rh6R€ª£í¡ûÙ a‚3ß·Õ ü=mRÍ/µ9¤‚0ÑC¼Iè:cŽsÛ¾™x£ÆÐ¬ªÍöˢ샒W$•€Å{¨ÀPG ÀÀàŸZìÍ1RÉ0´ðxEË9+Éÿ ^rEÕ—±Š„70l¼áË@û.' ¼¹Žz€N3úUÉ<3á×*?²¬‚ä†"Ùc=p íÛ'¡ª1ñ"økJ†HÒ'»Ÿ+ oÏN¬Ã9 dÙãÜדÏâÍ~æc+j·Jzâ7(£ðW]•晍?nê´º6åwéåç÷N•ZŠíž›¬|?Ðõ?Ñ-E…®³ÇV$~X¯/…õ x‘LˆÑÜÚÈ7¦pzãÜüë½ðÄ^õtÝYËÍ7ÉÖÕ8ÏUe# #€r=sU¾/é’E§jRC4mxNÝ´9†íuá»›V‘ ZI€­×cr1Ÿpzsøf»¨åV‹ìû`qËLÊIã?\~¼³áËC©êhªOîO»‘ÃmçÛçút×¢x“Z}?Üê#b-¤X7õ Äò gž zzbº3œm*qvs·M=íúéw}¿&Úª°^Ö×µÏ(ø‡â†Öµƒenñý†×åQáYûœ÷ÇLœôÎNk¡ð‡¼/µ¸n0æÉ0¬ƒ‚üîÉÆvŒw®Sáö”š¯‹-üÕVŠØÙ[$`(9cqƒÔ_@BëqûÙ`Ýæ­0;79È?w<ó |ÙÜkßÌ1±Ëã ¿ìÒ»ðlìï«ÓnªèèrP´NÏš&Žéö Ù¸÷æ°~-_O'‰`°!RÚÚÝ%]Ø%þbß1'¿ÿ X՝áOöÎŒ·‹¬+Åæ*ÛÛ™0¤ƒOÍÔ `u¯¦ÂaèÐÃÓ«‹¨Ô¥µœ¿¯ÉyÅÙ.oÔôŸ Úx&(STðݽ¦õ] ’ÒNóÁäÈùr3í·žÚ[™ƒ¼veÈ÷ÞIõÎGlqÎ=M|«gsªxÅI6 ]Z·Îªä,¨zŒŽÄ~#ØŠúFñiÉqc©éÐD>S딑 GñŽ1éÐ^+ Ëi;Ô„µVÕú»i¯ÈÒ-ZÍ]òܘ®ì` bÛÙ¥_/y(@÷qÐúg Ô÷W0.Ø› 6Ò© r>QƒŒ0+Èîzb¨É+I0TbNñ"$~)ÕÒ6Þ‹{0VÆ27œWWñcÄcX×íôûyKZéðªc'iQ¿¯LaWŠŸS\·Š“źʸ…ôÙÂí|öÀÇåV|!¤ÂGâÛ[[’ï 3OrÙËPY¹=Î1õ5öåTžÑè Ú64/üö?Zëžk}¬¶éào፾á}3“ü]8Éæ¿´n²Žš_6¾pœ)2?úWÓÚ¥¾¨iWúdŽq{*ª1rXŒd…m»‰äcô¯–dâ•ã‘Jº¬§¨#¨® §,df«8ÉÅßN¾hˆ;îÓ=7áùpën®É 6ûJžO2^œÐò JÖø¥²ã›Ò6Ü·‰!wbÍ‚¬O©»õ¬ÿ ƒP=Ä:â¤-&ÙŽ ` È9 r9íϧzë> XÅ7ƒ5X–krÑ¢L 7€ìw}ÑŸNHëŒüþ:2†á¼+u·á÷N/Û'Ðç~ߘô«ëh!ónRéeQ´6QÛÿ èEwëÅÒ|¸Yqó1uêyùzð8 ƒŠù¦Ò;¹ä6öi<'ü³„[íZhu½ ùÍ¡g‚>r¯׊îÌx}bñ2“­k꣧oø~›hTèóËWò4|ki"xßQ˜Ï6øÀLnß‚0 ¹Æ{±–¶Öe#¨27È@^Ìß.1N¾œyç€õ†ñeé·Õã†çQ°€=­Ì©ºB€Ø8<‚ÃSõ®ùcc>×Ú .Fr:žÝGæ=kÁâ,^!Fž ¬,àµ}%¶«îõ¹†"r²ƒGœüYÕd?aÑÍY®49PyU ÷þ!žxÅm|/‚ãNð˜¼PcûTÒ,¹/Ý=FkÏ|u¨¶«â녏{¤m¢]Û¾ïP>®XãÞ½iÓÁ¾ ‰'¬–6ß¼(„ï— í!úÙäzôë^–:œ¨å|,_¿&š×]uÓѵÛô4’j”bž§x‘Æ©ã›á,‚[Ô ÎÞ= ŒËæ ÀùYÁ?ŽïÚ¼?ÁªxºÕÛ,°1¸‘¿ÝäãØ¯v…@¤åq½ºã œàûââ·z8Xýˆþz~—û»™âµj=Ž â~ãáh@'h¼F#·Üp?ŸëQü-løvépx»cŸø…lxâÃûG·‰¶ø”L£©%y?¦úõÆü-Õ¶¥y`Òl7>q’2üA?•F}c‡jB:¸Jÿ +§¹¿¸Q÷°ív=VÑìu[Qml%R7a×IèTõéŽx¬ ?†š7 1†îã-ˆã’L¡lŽ0OÓ=ÅuˆpÇ•¼3ÛùÒ¶W/!|’wŽw^qÔ×Ïaó M8Q¨ãÑ?ëï0IEhÄa¸X•`a ?!ÐñùQ!Rä ÂžqŽžÝO`I0ÿ J“y|ñ!Îã@99>þ8–+éáu…!ù—ä ʰ<÷6’I®z ÅS„¾)Zþ_Öýµ×ËPåOwø÷þ*üïænÖùmØÝûþ¹=>¦½öî×Jh]¼ç&@§nTŒ6IT Àõ^Fxð7Å3!Ö·aÛ$þÿ ¹ã5îIo:ȪmËY[’8ÇӾlj*òû¢¥xõ¾¼ú•åk+\ð¯ HÚoŽl•Ûk,¯ ç²²cõÅ{²Z\ ´ìQ åpzŽ3Ôð}ÿ Jð¯XO¡øÎé€hÙ¥ûLdŒ`““ù6Gá^ÃáÝ^Ë[Ñb¾YåŒÊ»dŽ4 †2§,;ÿ CQÄ´¾°¨c–±”mºV{«ßÕýÄW\ÖŸ‘çŸ,çMRÆí“l-ƒn~ë©ÉÈê Ü?#Ž•¹ðãSÒ¥ÐWNíà½;ãž)™ÎSÈ9cóLj뵿Å«iÍk¨ió­¶X‚7÷ƒ€yãnyÏŽëÞ Öt`×À×V's$È9Ú:ä{wÆEk€«†Çàc—â$éÎ.éí~Ýëk}ÅAÆpörÑ¢‡Šl¡ÑüSs‹¨‰IÝ„óÀ×wñ&eºðf™pŒÆ9gŽTø£lñëÀçŽ NkÊUK0U’p ï^¡ãÈ¥´ø{£ÙHp`’ØåbqÏ©äó^Æ: Ž' ÊóM«õz+ß×ó5Ÿ»('¹­ð¦C„$˜Å¢_ºÈI?»^äã'ñêzž+ë€ñ-½»´}¡Ë*õ?.xÇ^1ŽMyǸ&“—L–îëöâ7…' bqéÎGé]˪â1$o²¸R8Ã`.q€}sÖ¾C9­8cêÆÞíïóòvÓòùœÕfÔÚéýu­èÖ·Ú Å‚_¤³ÜۺƑߝ”àרý:׃xPþÅÕî-/üØmnQìïGΊÙRqê=>¢½õnæ·r!—h`+’;ò3È<“Û©éšóŸx*÷V¹¸×tÈiˆßwiÔÿ |cŒñÏ®3Ö½̰‰Ë Qr©ö½®¼ÛoÑÙZÅÑ«O൯ýw8;k›ÿ x†;ˆJa;‘º9÷÷R+¡ñgŽí|Iáë{ôáo2ʲ9 029ÉÏLí\‰¿¸Ÿb˜ "Bv$£&#ßiê>=ªª©f  ’N ëí>¡N­XW­~5×úíø\‰»½Ï^ø(—wÖú¥¤2íŽÞXæÁ$ °eÈ888^nÝë²ñÝÔ^ ÖÚ9Q~Ëå7ï DC¶ÑµƒsËÇè9®Wáþƒ6‡£´·°2\Ý:ÈÑ?(#¨'$õèGJ¥ñW\ÿ ‰E¶—¸™g˜ÌÀ¹;Pv ú±ÎNs·ëŸ’–"Ž/:té+ûË]öJöÓM»ëø˜*‘•^Uý—êd|‰åñMæÔÝ‹23å™6æHùÛ‚ëüñ^…ñ1¢oêûÑEØ.õ7*ÅHtÎp{g<·Á«+¸c¿¿pÓ¾Æby=8É_ÄsÆk¬ñB\jÞÔì••Ë[9Píb‹Bヅ =9­3§ð§LšÛáÖšÆæXÌÞdÛP.0\ãïÛ0?™úJ¸™Ë ”•œº+=<µI£¦í¯õêt¬d‹T¬P=ËFêT>ÍØØ@Ï9<÷AQÌ×»Õ¡xùk",JÎæù±Éç$œŽŸZWH®¯"·UÌQ ’ÙÈ]ÅXg<ã ߨg3-Üqe€0¢¨*Œ$܃ ’Sû 8㎼_/e'+Ï–-èÓ¶¶Õíß[·ÙÙ½î쏗¼sk%§µxä‰â-pÒeÆCrú ôσžû=”šÅô(QW‚Õd\ƒæ. \àö¹¯F½°³½0M>‘gr÷q+œ¶NïºHO— ¤ ܥݭ”n·J|ÆP6Kµc=Isó}Ò çGš)a=—#vK›åoK§ßóٍ¤¶¿õú…ÄRÚ[Ësöټˏ•Ë ópw®qœŒ·Ø ùÇâ‹ý‡ãKèS&ÞvûD Aù‘É9 ŒîqÅ} $SnIV[]ѐ´Ó}ØÜ¾A Ü|½kÅþÓ|E Mu R¼.I¼¶däò‚ÃkÆ}ðy¹vc iUœZ…­Õõ»z¾÷¿n¦*j-É­/àœHã\y5 Û ß™ó0— äŸnzôã#Ô¯,†¥ÚeÔ÷ÜÅ´„“'c…<íÝ€<·SŠ¥k§Ã¢éÆÆÙna‚8–=«ʪ[Ÿ™°pNî02z“ÔÙ–K8.È’Þî(vƒ2®@ äÈûãçžxäÇf¯ˆu¹yUÕîýWšÙ|›ëÒ%Q^í[æ|éo5ZY•^{96ˆY‚§v*x>âº_|U¹Ö´©tûMÒÂ9PÇ#«£#€ éÉñ‘ƒÍz/‰´-į¹°dd,Б›p03ƒœ{ç9=+ Ûᧇ¬¦[‡‚ê婺¸#±ß=³ý¿•Õµjñ½HÙh›Û[§ÚýÊöô÷{˜?ô÷·Ô.u©–_%còcAÀ˜’ }0x9Î>žñÇáÍ9,ahï¦Ì2òÓ ñÛAäry$V²Nð ]=$Ž ‚#Ù‚1ƒƒødõMax‡ÂÖ^!±KkÛ‘ «“Çó²FN8+ëÎ{Ò¼oí§[«ÕMRoËeç×[_m/¦¦k.kôgŽxsSÓ´ý`êzªÜÜKo‰cPC9ÎY‰#§^üý9¹âïÞx£Ë·Ú`±‰‹¤;³–=ÏaôÕAð‚÷kêÁNBéÎælcõö®£Fð†ô2Ò¬]ßÂK$ÓÜ®•”/ÊHàã$ä ¸÷ëf¹Oµúâ“”’²ø­è´µþöjçNü÷üÌ¿ xNïFÒd»¼·h®îT9ŽAµÖ>qÁçÔœtïÒ»\ȶÎîcÞäîó3¶@#ÉIÎ ÔñW.<´’¥–ÑÑ€ÕšA‚ ;†qÓë‚2q ÒÂó$# Çí‡ !Ë}Õ9ÈÎÑÉã=;ŒÇÎuñ+ÉûÏ¥öíeÙ+$úíÜ娯'+êZH4ƒq¶FV‹gïŒ208ÆÌ)íб>M|÷âÍã¾"iì‹¥£Jd´™OÝç;sÈúr+ÜäˆË)DŒ¥šF°*3Õ”d {zÔwºQ¿·UžÉf†~>I+ŒqÔ`ð3œ“Ü×f]œTÁÔn4“ƒø’Ýßõ_«*5šzGCÊ,þ+ê1ò÷O¶¸cœºb2yÇ;cùÕ£ñh¬›áÑŠr¤ÝäNBk¥—á—†gxšX/쑘hŸ*Tçn =û㦠2|(ð¿e·ºÖ$ ýìŸ!'åΰyîî+×öœ=Y:²¦ÓÞ×iü’—ü -BK™£˜›âÆ¡&véðõ-ûÉY¹=Onj¹ø¯¯yf4·±T Pó`çœ7={×mÃ/ ¢˜ZÚòK…G½¥b„’G AãÜœ*í¯Ã¿ IoæI¦NU8‘RwÈã;·€ Û×ëÒ”1Y •£E»ÿ Oyto¢<£Áö·šï,䉧ûA¼sû»Nò}¹üE{ÜÖªò1’õÞr0â}ÎØ#>à/8ïéÎ~—áÍ#ñÎlí§³2f'h”?C÷YËdð:qëõÓ·‚ïeÄ© ÔÈØÜRL+žAÎ3¼g=åšó³Œt3 ÑQ¦ùRÙßE®¼±w_;þhš’Sirÿ ^ˆã¼iੇ|RòO„m°J/“$·l“ ÇÓ¿ÿ [ÑŠÆ“„†Õø>cFÆ6Ø1ƒ– àz7Ldòxäüwá‹ÝAXùO•Úý’é®ähm­ •NÀ±ÌTÈç ƒ‘I$pGž:‚ÄbêW¢®œ´|­¦­nÍ>¶ÖÏ¢§ÎÜ¢ºö¹•%ÄqL^öÛ KpNA<ã¡ …î==ª¸óffËF‡yÌcÉ ©ç$ð=ñÏ­YþÊ’Ú]—¥‚¬‚eDïÎH>Ÿ_ÌTP™a‰ch['çÆÜò7a‡?w°Ïn§âÎ5”’¨¹uÚÛ|´ÓÓc§{O—ü1•ªxsÃZ…ÊÏy¡Ã3¸Ë2Èé» ‘ƒÎ äžÜðA§cáOéúÛ4ý5-fŒï„ù¬ûô.Ç Üsž•Ò¾•wo<¶Ÿ"¬¡º|£ î2sÇ¡éE²ÉFѱrU°dÜ6œ¨ mc†Îxë׺Þ'0²¡Rr„{j¾í·è›µ÷)º·å–‹î2|I®Y¼ºÍË·–ÃÆà㍣'óÆxƒOÆÞ&>\lóÌxP Xc¸ì Sþ5§qà/ê>#žÞW¸if$\3 ® ûÄ“ùŽÕê¾ð<Ó‹H¶óÏ" å·( á‘€:ã†8Ï=+ꨬUA×ÃËÚT’ÑÞöù¥¢]{»ms¥F0\ÑÕ—ô}&ÛB´ƒOŽÚ+›xíÄÀ1 ,v± žIëíZ0ǧ™3 í2®0ทp9öÝÔž)ÓZËoq/Ú“‘L ²ŒmùŽÓ9§[Û#Ä‘\ÞB¬Çs [;à à«g‚2ôòªœÝV§»·¯/[uó½õÛï¾ /šÍ}öüÿ «=x»HŸÂÞ.™ ÌQùŸh´‘#a$‚'¡u<Š›Æ>2>+ƒLSiöwµFó1!eg`£åœ ÷ëÛö}Á¿ÛVÙêv $¬ƒ|,s÷z€ð΃¨x÷ÅD\ÜŒÞmåÔ„ ˆ o| :{ÇÓ¶–òÁn!´0Ål€, ƒ ( ÛŒŒ c¶rsšæ,4‹MÛOH!@¢ ÇŽ„`å²9ÝÃw;AÍt0®¤¡…¯ØÄ.Àì클ƒ‘ßñ5Í,Óëu-ÈÔc¢KÃÓ£òÖ̺U.õL¯0…%2È—"~x ‚[`có±nHàŽyàö™¥keˆìŒÛFç{(Ø©†`Jã#Žwg<“:ÚÉ;M ^\yhûX‡vB·÷zrF?§BÊÔ/s<ÐÈB)Û± ·ÍÔwç5Âã:så§e{mѤï«Òíh—]Wm4âí¿ùþW4bC3¶ª¾Ùr$ pw`àädzt!yŠI„hÂîàM)!edŒm'æ>Ç?wzºK­ìcŒ´¯Ìq6fp$)ãw¡éUl`µ»ARAˆÝÕgr:äŒgƒéé[Ôö±”iYs5Ýï«ÙG—K=þF’æMG«óÿ `ŠKɦuOQ!ÕåŒ/ÎGÞ`@ËqÕzdõâ«Ê/Ö(ƒK´%ŽbMü åÜŸö—>¤óŒŒV‘°„I¢Yž#™¥ùÏÊ@8 œgqöö5ª4vד[¬(q cò¨À!FGaÁõõ¯?§†¥ÏU½í¿WªZ$úyú½Žz×§Éþ?>Ã×È•6°{™™ŽÙ.$`­ÎUœ…çè ' ¤r$1Ø(y7 ðV<ž:È  ÁÎMw¾Â'Øb§øxb7gãО½óÉÊë²,i„Fȹ£§8ãä½k¹¥¦ê/ç{ïê驪2œ/«ü?¯Ô›ìñÜ$þeýœRIåŒg9Ác’zrrNO bÚi¢ ѺË/$,“ª¯Ýä;Œ× ´<ÛÑn³IvŸb™¥ nm–ÄŸ—nÝÀãŽ3ëÍG,.öó³˜Ù£¹u ÊÌrŠ[<±!@Æ:c9ÅZh ì’M5ÄìÌ-‚¼ëÉùqŽGì9¬á ;¨A-ž—évþÖ–^ON·Ô”ŸEý}ú×PO&e[]ÒG¸˜Ûp ƒÃà/Ë·8ûÀ€1ž@¿ÚB*²­¼ñì8@p™8Q“žÆH'8«I-%¸‚ F»“åó6°Uù|¶Ú¸ã ò^Äw¥ŠÖK–1ÜÝK,Žddlí²0PÀü“×ükG…¯U«·¶–´w¶ŽÍ¾©yÞú[Zös•¯Á[™6° ¨¼ÉVæq·,# ìãï‘×8îry®A››¨,ãc66»Ë´ã'æÉù?t}¢æH--Òá"›|ˆ¬[í  7¶ö#¸9«––‹$,+Ëqœ\Êø c€yê^ݸÄa°«™B-9%«×®‹V´w~vÜTéꢷþ¼ˆ%·¹• ’[xç•÷2gØS?6åÀÚ õ9É#š@÷bT¸º²C*3Bá¤òÎA9 =úU§Ó"2Ãlá0iÝIc‚2Î@%öç94ùô»'»HÄ¥Ô¾@à Tp£šíx:úÊ:5eºßMý×wµ›Ó_+šº3Ýyvÿ "ºÇ<ÂI>Õ 1G·Ë«È«É# àÈÇ øp Jv·šæDûE¿›†Ë’NFr2qŸ½ÇAÜšu•´éí#Ħ8£2”Ú2Ã/€[ÎTr;qŠz*ý’Îþ(≠;¡TÆâ›;ºÿ àçœk‘Þ­8¾Uª¾íé{^×IZéwÓkXÉûÑZo¯_øo×È¡¬ â–ÞR§2„‚Àœü½ùç® SVa†Âüª¼±D‘ŒísŸàä|ä2 æ[‹z”¯s{wn„ÆmáóCO+†GO8Ïeçåº`¯^¼ðG5f{Xžä,k‰<á y™¥voÆ éÛõëI=œ1‹éíÔÀÑ)R#;AÂncäŽ:tÏ#¶TkB.0Œ-ÖÞZÛgumß}fÎJÉ+#2êÔP£žùÈÅi¢%œ3P*Yƒò‚Aì“Ž2r:ƒÐúñi­RUQq‰H9!”={~¼ “JŽV¥»×²m.ÛߺiYl¾òk˜gL³·rT• ’…wHÁ6ä`–Î3ùÌ4Øe³†&òL‘•%clyîAÂäà0 žüç$[3uŘpNOÀÉ=† cï{rYK ååä~FÁ •a»"Lär1Ó¯2Äõæ<™C•.fÕ»è¥~½-¿g½Â4¡{[ør¨¶·Žõäx¥’l®qpwÇ»8ärF \cޏܯÓ-g‚yciÏÀ¾rÎwèØÈ#o°Á9ã5¢šfÔxÞæfGusÏÌJÿ µ×œ/LtãÅT7²¶w,l ɳ;”eúà·¨çîŒsÜgTÃS¦­^ '~‹®›¯+k÷ZÖd©Æ*Ó[Ü«%Œk0ŽXƒ”$k#Ȩ P2bv‘ƒŸáÇ™ÆÕb)m$É*8óLE‘8'–ÜN Úyàúô­+{uº±I'wvš4fÜr íì½=úuú sFlìV$‘ö†Hсù€$§ õ=½¸«Ž] :Ž+•¦ïmRþ½l´îÊT#nkiøÿ _ðÆT¶7Ò½ºÒ£Î¸d\ã8=yãŽÜäR{x]ZâÚé#¸r²#»ÎHÆ6õ ç® ÎFkr;sºÄ.&;só± Ç9êH÷ýSšÕ­tÐU¢-n­ Ì| vqœ„{gŒt§S.P‹’މ_[;m¥Þ­ZýRûÂX{+¥úü¼ú•-àÓ7!„G"“´‹žƒnrYXã¸îp éœ!Ó­oP̏tÑ (‰Þ¹é€sÓ#GLçÕšÑnJý¡!‘Tä#“ß?îýp}xÇ‚I¥Õn#·¸–y'qó@r[ Êô÷<ÔWÃÓ¢áN¥4ԝ’I&ݼ¬¬¼ÞºvéÆ FQV~_ÒüJÖÚt¥¦Xá3BÄP^%ÈÎW-×c¡ú©¤·Iþèk¥š?–UQåIR[’O 5x\ÉhÆI¶K4«2ùªŠŒ<¼óœçØ`u«‚Í.VHä € Ëgfx''9ÆI#±®Z8 sISºku¢ßÞ]úk»Jößl¡B.Ü»ÿ MWe °·Ž%šêɆ¼»Âù³´œ O¿cÐÓÄh©"ÛÜÏ.ÖV ’3nüÄmnq[ŒòznšÖ>J¬òˆæ…qýØP Ž:ä7^0yëWšÍ_79äoaÈ °#q0{ää×mœy”R{vÒÞ¶ÚÏe¥“ÚÆÐ¥Ì®—õýjR •íç›Ìb„+J yÜØÙ•Ç]¿Ôd þËOL²”9-Œ—õÃc'æÝלçÚ²ìejP“½ âù°¨†ðqòädЃÉäÖÜj÷PÇp“ÍšŠå«‘î <iWN­smª»¶vÓz5»ûì:Rs\Ðßôû×uÔÿÙ