07070100000000000041FD000000000000000000000001600AC2BC00000000000000000000000000000000000000000000000B00000000mgr-libmod    07070100000001000081B4000000000000000000000001600AC2BC0000043D000000000000000000000000000000000000001300000000mgr-libmod/LICENSE    MIT License

Copyright (c) 2020 SUSE LLC
Author: Bo Maryniuk

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
   07070100000002000081B4000000000000000000000001600AC2BC0000050E000000000000000000000000000000000000001E00000000mgr-libmod/mgr-libmod.changes -------------------------------------------------------------------
Fri Jan 22 13:08:32 CET 2021 - jgonzalez@suse.com

- version 4.1.6-1
- Improve modular dependency resolution algorithm (bsc#1177267)

-------------------------------------------------------------------
Thu Nov 26 15:59:22 CET 2020 - jgonzalez@suse.com

- version 4.1.5-1
- Fix 'module not found' exception handling (bsc#1179257)

-------------------------------------------------------------------
Thu Jul 23 13:22:35 CEST 2020 - jgonzalez@suse.com

- version 4.1.4-1
- Remove unnecessary array wrap in 'list_modules' response object

-------------------------------------------------------------------
Wed Jun 10 12:13:35 CEST 2020 - jgonzalez@suse.com

- version 4.1.3-1
- Reformat 'list_modules' response JSON object

-------------------------------------------------------------------
Wed Apr 15 17:11:04 CEST 2020 - jgonzalez@suse.com

- version 4.1.2-1
- Add JSON error type responses

-------------------------------------------------------------------
Mon Feb 17 15:06:47 CET 2020 - jgonzalez@suse.com

- version 4.1.1-1
- Align version with the rest of packages

-------------------------------------------------------------------
Fri Feb 07 11:13:09 CET 2020 - bo@suse.de

- version 0.2-1
- Initial package release

  07070100000003000081B4000000000000000000000001600AC2BC000005AC000000000000000000000000000000000000001B00000000mgr-libmod/mgr-libmod.spec    #
# spec file for package mgr-libmod
#
# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.

# Please submit bugfixes or comments via https://bugs.opensuse.org/
#

Name:           mgr-libmod
Version:        4.1.6
Release:        1
Summary:        libmod app
License:        MIT
Group:          Applications/Internet
Source:         %{name}-%{version}.tar.gz
Requires(pre):  coreutils
Requires:       python3-libmodulemd
BuildRequires:  python3-pytest
BuildRequires:  python3-mock
BuildRoot:      %{_tmppath}/%{name}-%{version}-build
BuildArch:      noarch
URL:            https://github.com/uyuni-project/uyuni

%description
mgr-libmod

%prep
%setup -q

%build
%{__python3} setup.py build

%install
%{__python3} setup.py install --skip-build --root $RPM_BUILD_ROOT
mkdir -p %{buildroot}/usr/bin
cp -R scripts/* %{buildroot}/usr/bin

%files
%defattr(-,root,root)
%{python3_sitelib}/*
/usr/bin/mgr-libmod
%license LICENSE
07070100000004000041FD000000000000000000000001600AC2BC00000000000000000000000000000000000000000000001500000000mgr-libmod/mgrlibmod  07070100000005000081B4000000000000000000000001600AC2BC00000000000000000000000000000000000000000000002100000000mgr-libmod/mgrlibmod/__init__.py  07070100000006000081B4000000000000000000000001600AC2BC000009EB000000000000000000000000000000000000001E00000000mgr-libmod/mgrlibmod/mlapp.py """
CLI app
"""
from mgrlibmod import mllib, mltypes, mlerrcode
from typing import List
import argparse
import os
import sys


def get_opts() -> argparse.Namespace:
    """
    get_args parses the CLI arguments.
    """
    ap: argparse.ArgumentParser = argparse.ArgumentParser(
        description="mgr-libmod -- Utility to resolve module dependencies"
    )
    ap.add_argument("-e", "--example", action="store_true", help="Show usage example")
    ap.add_argument("-l", "--list", action="store_true", help="Show list of supported functions")
    ap.add_argument("-v", "--verbose", action="store_true", help="Verbose output (debug mode)")
    ap.add_argument("-p", "--pretty", action="store_true", help="Pretty-print JSON responses")

    return ap.parse_args()


def get_stdin_data() -> str:
    """
    get_stdin_data read JSON data from the STDIN and return as a string.

    :return: input data
    :rtype: str
    """
    out: List[str] = []
    for line in sys.stdin.readlines():
        out.append(line.strip())

    return os.linesep.join(out)


def main():
    """
    main function for the CLI app.
    """
    opts: argparse.Namespace = get_opts()
    if opts.list:
        print("Supported functions:\n")
        for m in dir(mllib.MLLibmodAPI):
            if m.startswith("_function__"):
                print("  -", m[11:])
        print()
    elif opts.example:
        example: str = """
Usage example:

1. Create input JSON file with the following type (values are just as an example)
   and save it e.g. as "input.json":

        {
            "function": "module_packages",
            "paths": [
                "data/some-modules.yaml.gz",
                "data/some-other-modules.yaml.gz"
            ],
            "streams": [
                {
                    "name": "postgresql",
                    "stream": "10"
                },
                {
                    "name": "rhn-tools",
                    "stream": "1.0"
                }
            ]
        }

2. Run it to resolve the modules and packages:

        mgr-libmod < input.json > output.json

To get the full list of supported functions, call "-l" option:

        mgr-libmod -l
"""
        print(example.strip() + "\n")
    else:
        try:
            print(mllib.MLLibmodAPI(opts).set_repodata(get_stdin_data()).run().to_json(pretty=opts.pretty))
        except Exception as exc:
            print(mltypes.MLErrorType(exc).to_json(pretty=opts.pretty))
            if opts.verbose:  # Local debugging
                raise exc
 07070100000007000081B4000000000000000000000001600AC2BC000004E1000000000000000000000000000000000000002200000000mgr-libmod/mgrlibmod/mlerrcode.py """
Error codes
"""

from typing import Dict, Any

MLERR_OK = 0
MLERR_GENERAL_ERROR = 1
MLERR_MODULE_NOT_FOUND = 201
MLERR_DEPENDENCY_RESOLUTION_ERROR = 202
MLERR_CONFLICTING_STREAMS = 203
MLERR_REQUEST_ERROR = 301

class MlException(Exception):
    """
    General exception carrier.
    """
    def __init__(self, *args):
        Exception.__init__(self, *args)
        self.data: Dict = {}

    def set_data(self, key: str, val: Any) -> "MlException":
        """
        Add a data key/value to the final output.
        eturns:
            [type] -- [description]
        """
        self.data[key] = val
        return self

class MlGeneralException(MlException):
    """
    General exception
    """
    code = MLERR_GENERAL_ERROR


class MlModuleNotFound(MlException):
    """
    Module was not found exception
    """
    code = MLERR_MODULE_NOT_FOUND


class MlDependencyResolutionError(MlException):
    """
    Dependency resolution error
    """
    code = MLERR_DEPENDENCY_RESOLUTION_ERROR


class MlConflictingStreams(MlException):
    """
    Conflicting streams exception
    """
    code = MLERR_CONFLICTING_STREAMS


class MlRequestError(MlException):
    """
    Wrong request definition
    """
    code = MLERR_REQUEST_ERROR
   07070100000008000081B4000000000000000000000001600AC2BC00002836000000000000000000000000000000000000001E00000000mgr-libmod/mgrlibmod/mllib.py """
libmod operations
"""
import os
import sys
import gzip
import json
import argparse
import binascii

from typing import Any, Dict, List, Set, Optional
from mgrlibmod import mltypes, mlerrcode, mlresolver

import gi  # type: ignore

gi.require_version("Modulemd", "2.0")
from gi.repository import Modulemd  # type: ignore

class MLLibmodProc:
    """
    Libmod process.
    """
    def __init__(self, metadata: List[str]):
        """
        __init__

        :param metadata: paths of the metadata.
        :type metadata: List[str]
        """
        self.metadata = metadata
        self._mod_index: Modulemd.ModuleIndex = None

        if gi is None or Modulemd is None:
            raise mlerrcode.MlGeneralException("No python libmodulemd was found")

    def _is_meta_compressed(self, path: str) -> bool:
        """
        _is_meta_compressed -- detect if metafile is plain text YAML or compressed.

        :param path: path to the meta file.
        :type path: str
        :return: True, if meta is GNU Zip compressed.
        :rtype: bool
        """
        with open(path, "rb") as metafile:
            return binascii.hexlify(metafile.read(2)) == b"1f8b"  # Almost reliable :-)

    def get_stream_contexts(self, stream: mltypes.MLStreamType) -> List:
        '''
        get_stream_contexts -- get all the alternative contexts for a module stream

        :param stream: the specified module stream
        '''
        if self._mod_index is None:
            self.index_modules()

        if self._mod_index is None:
            raise mlerrcode.MlGeneralException("Module index not found")

        contexts: List = []
        module = self._mod_index.get_module(stream.name)
        if module:
            stream_name = stream.stream if stream.stream \
                    else self.get_default_stream(stream.name)
            for ctx in module.get_all_streams():
                if ctx.get_stream_name() == stream_name:
                    contexts.append(ctx)

        return contexts

    def index_modules(self) -> None:
        """
        index_modules -- loads given metadata and indexes modules from there.
        """
        if self._mod_index is None:
            mgr: Modulemd.ModuleIndex = Modulemd.ModuleIndexMerger.new()
            for path in self.metadata:
                idx = Modulemd.ModuleIndex.new()
                if self._is_meta_compressed(path):
                    with gzip.open(path) as gzmeta:
                        idx.update_from_string(gzmeta.read().decode("utf-8"), True)
                else:
                    idx.update_from_file(path, True)
                mgr.associate_index(idx, 0)
            self._mod_index = mgr.resolve()

    def get_default_stream(self, name: str):
        if self._mod_index is None:
            raise mlerrcode.MlGeneralException("Module index not found")

        module = self._mod_index.get_module(name)

        if not module:
            raise mlerrcode.MlModuleNotFound("Module {} not found".format(name)).set_data("streams", [mltypes.MLStreamType(name, "").to_obj()])

        defaults = module.get_defaults()
        if defaults:
            return defaults.get_default_stream()

        return module.get_all_streams()[0].get_stream_name()

    def get_streams_with_defaults(self, streams):
        streams_with_defaults = []
        for s in streams:
            stream_name = s.stream
            if not stream_name:
                stream_name = self.get_default_stream(s.name)
            streams_with_defaults.append(mltypes.MLStreamType(s.name, stream_name))
        return streams_with_defaults

    def _get_pkg_name(self, pkg_name: str) -> str:
        """
        _get_pkg_name -- get package name

        :param pkg_name: package name
        :type pkg_name: str
        :raises e: General exception if name doesn't comply.
        :return: name of the package
        :rtype: str
        """
        try:
            woarch = pkg_name.rsplit(".", 1)[0]
            worel = woarch.rsplit("-", 1)[0]
            wover = worel.rsplit("-", 1)[0]
        except Exception as e:
            raise mlerrcode.MlGeneralException("{}: {}".format(e, pkg_name))

        return wover

    def _get_artifact_with_name(self, artifacts, name):
        for artifact in artifacts:
            n = self._get_pkg_name(artifact)
            if name == n:
                return artifact
        return None

    def _get_stream_object(self, m_name, stream) -> Dict:
        s_obj: Dict = {
            "name": m_name,
            "stream": stream.get_stream_name(),
            "version": stream.get_version(),
            "context": stream.get_context(),
            "arch": stream.get_arch(),
        }
        return s_obj

    def get_api_provides(self, streams):
        api_provides: Dict[str, mltypes.MLSet] = {
            "apis": mltypes.MLSet(),
            "packages": mltypes.MLSet(),
            "selected": mltypes.MLSet(),
        }

        for stream in streams:
            if not stream:
                continue

            stream_artifacts = stream.get_rpm_artifacts()

            for rpm in stream.get_rpm_artifacts():
                if not rpm.endswith(".src"):
                    api_provides["packages"].add(rpm)

            for rpm in stream.get_rpm_api():
                artifact = self._get_artifact_with_name(stream_artifacts, rpm)
                if artifact:
                    api_provides["apis"].add(rpm)
                    if not artifact.endswith(".src"):
                        api_provides["packages"].add(artifact)
            api_provides["selected"].add(self._get_stream_object(stream.get_module_name(), stream))

        return api_provides


class MLLibmodAPI:
    """
    Libmod API operations.
    """

    def __init__(self, opts: argparse.Namespace):
        """
        __init__

        :param opts: Parsed opts namespace.
        :type opts: argparse.Namespace
        """
        self._opts = opts
        self.repodata: mltypes.MLInputType
        self._result: Dict[str, Dict[str, Dict]] = {}
        self._proc: MLLibmodProc

    def set_repodata(self, repodata: str) -> "MLLibmodAPI":
        """
        set_repodata -- set the repository data from the input JSON.

        :param repodata: JSON string of the input object.
        :type repodata: str
        """
        self.repodata = mltypes.MLInputType(repodata)
        for modulepath in self.repodata.get_paths():
            if not os.path.exists(modulepath):
                raise mlerrcode.MlGeneralException("File {} not found".format(modulepath))

        self._proc = MLLibmodProc(self.repodata.get_paths())

        return self

    def to_json(self, pretty:bool = False) -> str:
        """
        to_json -- render the last set processed result by 'run' method into the JSON string.

        :return: JSON string
        :rtype: str
        """
        out: str
        if pretty:
            out = json.dumps(self._result, indent=2, sort_keys=True)
        else:
            out = json.dumps(self._result)
        return out

    def run(self) -> "MLLibmodAPI":
        """
        run -- process the logic, based on the input.

        :return: MLLibmodAPI
        """
        fname = self.repodata.get_function()
        self._result[fname] = getattr(self, "_function__{}".format(fname))()

        return self

    def _validate_input_streams(self, streams):
        for s1 in streams:
            for s2 in streams:
                if s1.name == s2.name and s1.stream != s2.stream:
                    raise mlerrcode.MlConflictingStreams("Conflicting streams").set_data("streams", [s1.to_obj(), s2.to_obj()])

    def _resolve_stream_dependencies(self) -> List[Modulemd.ModuleStreamV2]:
        """
        _resolve_stream_dependencies -- select all the module dependencies preferring default streams

        :return: List of stream objects
        :rtype: List
        """
        input_streams = self._proc.get_streams_with_defaults(self.repodata.get_streams())
        self._validate_input_streams(input_streams)

        resolver = mlresolver.DependencyResolver(self._proc)
        solutions = resolver.resolve(input_streams)
        if not solutions:
            raise mlerrcode.MlDependencyResolutionError("Dependencies cannot be resolved")

        # Return the solution with highest score (most selections with default streams)
        solutions.sort(key=lambda s: s[1], reverse=True)
        return solutions[0][0]

    # API functions
    def _function__list_modules(self) -> Dict[str, Dict]:
        """
        _function__all_modules -- lists all available modules.

        :return: list of strings
        :rtype: List[str]
        """
        modules: Dict = {
            "modules": {}
        }
        self._proc.index_modules()
        mobj: Dict = {}
        for m_name in self._proc._mod_index.get_module_names():
            mod = self._proc._mod_index.get_module(m_name)
            d_mod = mod.get_defaults()
            mobj[m_name] = {
                "default": d_mod.get_default_stream() if d_mod else None,
                "streams": set([s.get_stream_name() for s in mod.get_all_streams()])
            }

        modules["modules"] = mobj
        return modules

    def _function__list_packages(self) -> Dict[str, List[str]]:
        """
        _function__list_packages -- lists all available packages for the module.

        :return: list of packages within 'packages' element
        :rtype: List[str]
        """
        self._proc.index_modules()
        rpms: Dict[str, List[str]] = {"packages": []}
        for name in self._proc._mod_index.get_module_names():
            module = self._proc._mod_index.get_module(name)
            for stream in module.get_all_streams():
                rpms["packages"].extend(stream.get_rpm_artifacts())
        return rpms

    def _function__module_packages(self) -> Dict[str, List[str]]:
        """
        _function__module_packages -- get all RPMs from selected streams as a map of package names to package strings.

        :return: structure for module packages
        :rtype: Dict[str, List[str]]
        """
        self._proc.index_modules()
        selected_streams = self._resolve_stream_dependencies()
        return self._proc.get_api_provides(selected_streams)

  07070100000009000081B4000000000000000000000001600AC2BC00002504000000000000000000000000000000000000002300000000mgr-libmod/mgrlibmod/mlresolver.py    from mgrlibmod import mltypes, mlerrcode

class DependencyResolver:
    """
    Module dependency resolver

    Resolves dependencies for selected module streams traversing the dependency
    tree using a backtracking algorithm.
    """
    RESERVED_STREAMS = ["platform"]

    def __init__(self, proc):
        """
        __init__ - initialize the resolver with an MLLibmodProc instance

        :param proc: the MLLibmodProc instance to use for module index related operations
        """
        self._proc = proc

    def resolve(self, streams):
        """
        resolve - resolve dependencies for the requested streams

        The algorithm traverses the dependency tree recursively using backtracking to collect multiple solutions.

        :param streams: the requested streams
        :return:
            A list of solution-score pairs that satisfy all the dependency requirements for the requested streams

            Each solution is a list of selected stream contexts for the requested streams and their dependencies.
            The score indicates the number of selected default streams in the solution.
        """
        self._streams = streams

        # Collect all the available contexts for the requested streams
        # to get an initial list of candidates at the root of the tree
        contexts = []
        not_found = []
        for s in streams:
            ctx = self._proc.get_stream_contexts(s)
            if ctx:
                contexts.extend(self._proc.get_stream_contexts(s))
            else:
                not_found.append(s.to_obj())

        # Throw an error if any of the requested streams are not found
        if not_found:
            raise mlerrcode.MlModuleNotFound("Module not found").set_data("streams", not_found)

        self._solutions = []
        self._do_resolve([], contexts)
        return self._solutions

    def _preselect(self, selected, candidates):
        '''
        _preselect - select all the streams that doesn't have multiple contexts

        The method modifies the lists in place, moving elements from 'candidates' into 'selected'.
        The streams that have multiple contexts will remain in 'candidates' for backtracking later.

        :param selected: the list of selected elements
        :param candidates: the remaining candidate pool
        '''
        # Pool of contexts explored so far
        ctx_pool = selected[:]
        ctx_pool.extend(candidates)

        # Process stack: extended as dependencies are explored
        stack = candidates[:]
        candidates.clear()

        while stack:
            s = stack.pop()
            if len(self._get_contexts_for_stream(s, ctx_pool)) == 1:
                # There is only a single context for this stream so we'll pick it
                if s not in selected:
                    selected.append(s)
                deps = s.get_dependencies()[0]
                dep_mods = [m for m in deps.get_runtime_modules() if m not in self.RESERVED_STREAMS]
                for m in dep_mods:
                    try:
                        dep_str = deps.get_runtime_streams(m)[0]
                    except:
                        # No stream specified. Any stream will do
                        if next((c for c in ctx_pool if c.get_module_name() == m), False):
                            # Already has an alternative in the pool
                            continue
                        dep_str = None

                    # Add the dependencies to the stack for further processing
                    dep_ctx = self._proc.get_stream_contexts(mltypes.MLStreamType(m, dep_str))
                    stack.extend(dep_ctx)
                    ctx_pool.extend(dep_ctx)
            else:
                # Multiple contexts available for the stream.
                # Will be later resolved with backtracking
                if s not in candidates:
                    candidates.append(s)


    def _is_selection_valid(self, selection):
        """
        _is_selection_valid - check if a solution is valid

        :param selection: the list of selected contexts in the solution
        """
        for i in range(0, len(selection)):
            # Check if the selected item is unique in the list
            for j in range(i+1, len(selection)):
                if selection[i].get_module_name() == selection[j].get_module_name():
                    return False
            # Check if the selected stream conflicts with the matching requested stream
            for requested in self._streams:
                if selection[i].get_module_name() == requested.name and selection[i].get_stream_name() != requested.stream:
                    return False
        return True

    def _get_solution(self, selection):
        """
        _get_solution - get a solution-score pair where score indicates the number of default streams in the solution
        """
        num_defaults = 0
        for ctx in selection:
            if self._proc.get_default_stream(ctx.get_module_name()) == ctx.get_stream_name():
                num_defaults += 1

        return (selection, num_defaults)

    def _is_selected(self, module_name, stream_name, selection):
        """
        _is_selected - check if a specified module stream is in a selection list
        """
        for ctx in selection:
            if ctx.get_module_name() == module_name and (not stream_name or ctx.get_stream_name() == stream_name):
                return True
        return False

    def _are_deps_selected(self, stream, selection):
        """
        _are_deps_selected - check if all the dependencies of a stream are in a selection list
        """
        deps = stream.get_dependencies()[0]
        dep_mods = [m for m in deps.get_runtime_modules() if m not in self.RESERVED_STREAMS]
        for m in dep_mods:
            try:
                dep_str = deps.get_runtime_streams(m)[0]
            except:
                # No stream specified. Any stream will do
                dep_str = None
            if not self._is_selected(m, dep_str, selection):
                return False
        return True

    def _accept(self, selection):
        """
        _accept - check if the selection list is an acceptable solution

        :return: the solution-score pair if the solution is acceptable, None otherwise
        """
        all_found = True
        for s in self._streams:
            found = False
            for ctx in selection:
                if ctx.get_module_name() == s.name and ctx.get_stream_name() == s.stream and self._are_deps_selected(ctx, selection):
                    # Strem s and all its dependencies are in the list
                    found = True
            all_found = all_found and found
        return self._get_solution(selection) if all_found else None

    def _is_same_stream(self, s1, s2):
        '''
        _is_same_stream - determine if two contexts belong to the same stream
        '''
        return s1.get_module_name() == s2.get_module_name() and s1.get_stream_name() == s2.get_stream_name()

    def _get_contexts_for_stream(self, ctx, contexts):
        '''
        _get_contexts_for_stream - get a list of contexts that belong to the same stream as the specified context
        '''
        return set(c for c in contexts if self._is_same_stream(c, ctx))

    def _get_deps(self, ctx):
        '''
        _get_deps - get the list of contexts of the first-level dependencies for a specified stream context

        :param ctx: a context object
        '''
        all_deps = []
        deps = ctx.get_dependencies()[0]
        dep_mods = [m for m in deps.get_runtime_modules() if m not in self.RESERVED_STREAMS]
        for m in dep_mods:
            try:
                stream = deps.get_runtime_streams(m)[0]
            except:
                # No stream specified. Any stream will do
                stream = None
            all_deps.extend(self._proc.get_stream_contexts(mltypes.MLStreamType(m, stream)))
        return all_deps

    def _do_resolve(self, selected, candidates):
        """
        _do_resolve - calculate valid solutions that satisfy the dependency requirements

        :param selected: the list of already selected stream contexts
        :param candidates: the potential stream candidates to select from
        """
        # Select all the candidates that have no alternative contexts to reduce needed recursions
        self._preselect(selected, candidates)

        # Validate the current selection
        if not self._is_selection_valid(selected):
            return
        solution = self._accept(selected)
        if solution:
            # We've got a valid solution. Save it and keep solving.
            self._solutions.append(solution)

        if not candidates:
            return

        # Get all alternative contexts for the first candidate
        contexts = self._get_contexts_for_stream(candidates[0], candidates)

        # Loop through alternatives
        for c in contexts:
            # Remove the alternative contexts from the candidates
            candidates.remove(c)

        for c in contexts:
            newselected = selected[:]
            if c not in newselected:
                newselected.append(c)
            newcandidates = candidates[:]
            # The dependencies of the currently selected stream are now new candidates
            newcandidates.extend(self._get_deps(c))
            self._do_resolve(newselected, newcandidates)
0707010000000A000081B4000000000000000000000001600AC2BC000015FF000000000000000000000000000000000000002000000000mgr-libmod/mgrlibmod/mltypes.py   """
Input types for the mgr-libmod
"""
from typing import List, Tuple, Any, AnyStr, Union, Optional, Dict, Set, cast
import collections
import json
from abc import ABC, abstractmethod
from mgrlibmod import mlerrcode


class MLSet(list):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def __append(self, obj: Any) -> None:
        super().append(obj)

    def append(self, obj: Any) -> None:
        self.add(obj)

    def add(self, obj: Any) -> None:
        if obj not in self:
            self.__append(obj)


class MLAnyType(ABC):
    """
    Base MLType mix-in.
    """
    def __init__(self, data: str):
        """
        Constructor

        :param data: JSON string
        :type data: str
        """
        self._obj = json.loads(data)

    @abstractmethod
    def to_obj(self) -> Dict:
        """
        to_obj is an object getter.

        :return: Object for JSON serialisation.
        :rtype: Dict
        """

    def to_json(self, pretty: bool = False) -> str:
        """
        to_json serialises type to JSON.

        :return: valid JSON unicode string.
        :rtype: str
        """
        if pretty:
            out = json.dumps(self.to_obj(), indent=2, sort_keys=True)
        else:
            out = json.dumps(self.to_obj())
        return out


class MLPackageType(MLAnyType):
    """
    Package type input.
    """
    def __init__(self):
        """
        Constructor
        """
        self.rpms: Set = set()

    def add_package(self, package: str) -> None:
        """
        add_package adds package name to the type.

        :param package: package name
        :type package: str
        :return: None
        :rtype: None
        """
        self.rpms.add(package)

    def to_obj(self) -> Dict:
        """
        to_obj serialise object to the dictionary.

        :return: object as a dictionary.
        :rtype: Dict
        """
        return {"rpms": list(self.rpms)}


class MLStreamType:
    """
    Stream type
    """
    def __init__(self, name: str, streamname: str):
        self.__name: str = name
        self.__stream: str = streamname
        self.__exc = Exception("This is a read-only property")

    def __repr__(self) -> str:
        return "<{} ({}/{}) at {}>".format(self.__class__.__name__,
                                           self.__name, self.__stream,
                                           hex(id(self)))

    @property
    def name(self) -> str:
        return self.__name

    @name.setter
    def name(self, v: str) -> None:
        raise self.__exc

    @property
    def stream(self) -> str:
        return self.__stream

    @stream.setter
    def stream(self, v: str) -> None:
        raise self.__exc

    def to_obj(self) -> Dict:
        return {"name": self.__name, "stream":self.__stream}


class MLInputType(MLAnyType):
    """
    Input type.
    """
    def to_obj(self) -> Dict:
        return cast(Dict, self._obj)

    def get_function(self) -> str:
        """
        get_function -- return function name.

        :return: function name to process.
        :rtype: str
        """
        obj = self.to_obj()
        if "function" not in obj:
            raise mlerrcode.MlRequestError("Unknown API function. Please define one")

        return obj["function"]

    def get_paths(self) -> List[str]:
        """
        get_paths get paths section from the YAML.

        :return: array of paths
        :rtype: List[str]
        """
        obj = self.to_obj()
        if "paths" not in obj:
            raise mlerrcode.MlRequestError("No paths has been found in the input request")

        paths: List[str] = obj.get("paths", [])
        if not bool(paths):
            raise mlerrcode.MlRequestError("Paths should not be empty. At least one path is required")

        return paths

    def get_streams(self) -> List[MLStreamType]:
        """
        get_streams [summary]

        :return: [description]
        :rtype: List[Tuple[str]]
        """
        obj: Dict = self.to_obj()
        out: List[MLStreamType] = []

        if obj["streams"] is None:
            raise mlerrcode.MlRequestError("Streams should not be null")

        for str_kw in obj["streams"]:
            if "name" not in str_kw:
                raise mlerrcode.MlRequestError("No 'name' attribute in the stream parameter {}".format(str_kw))
            out.append(MLStreamType(name=str_kw["name"], streamname=str_kw.get("stream") or ""))

        return out


class MLErrorType(MLAnyType):
    """
    Error response
    """
    def __init__(self, exc: Exception = None):
        """
        Constructor.
        """
        self._obj: Dict = {
            "error_code": 0,
            "data": {},
            "exception": "",
        }

        if exc is not None:
            self.exc = exc
            self.error_code = getattr(exc, "code", mlerrcode.MLERR_GENERAL_ERROR)
            self.data = getattr(exc, "data", {})

    @property
    def error_code(self) -> int:
        return self._obj["error_code"]

    @error_code.setter
    def error_code(self, value: int) -> None:
        self._obj["error_code"] = value

    @property
    def exc(self) -> Exception:
        return Exception(self._obj["exception"])

    @exc.setter
    def exc(self, ex: Exception) -> None:
        self._obj["exception"] = str(ex)

    @property
    def data(self) -> Dict:
        return self._obj["data"]

    @data.setter
    def data(self, d: Dict) -> None:
        self._obj["data"] = d

    def to_obj(self) -> Dict:
        """
        Return JSON object
        """
        return cast(Dict, self._obj)
 0707010000000B000041FD000000000000000000000001600AC2BC00000000000000000000000000000000000000000000001300000000mgr-libmod/scripts    0707010000000C000081FD000000000000000000000001600AC2BC00000077000000000000000000000000000000000000001E00000000mgr-libmod/scripts/mgr-libmod #!/usr/bin/python3
"""
Main CLI app.
"""
import mgrlibmod.mlapp

if __name__ == "__main__":
    mgrlibmod.mlapp.main()
 0707010000000D000081B4000000000000000000000001600AC2BC00000085000000000000000000000000000000000000001400000000mgr-libmod/setup.py   from distutils.core import setup

setup(
    name="mgrlibmod",
    version="4.1.6",
    packages=["mgrlibmod",],
    license="MIT",
)   0707010000000E000041FD000000000000000000000001600AC2BC00000000000000000000000000000000000000000000001100000000mgr-libmod/tests  0707010000000F000041FD000000000000000000000001600AC2BC00000000000000000000000000000000000000000000001600000000mgr-libmod/tests/data 07070100000010000081B4000000000000000000000001600AC2BC000014EB000000000000000000000000000000000000002700000000mgr-libmod/tests/data/all_modules.json    {
	"function": "module_packages",
	"paths": ["tests/data/sample-modules.yaml.gz"],
	"streams": [
                {
                    "name": "virt",
                    "stream": "rhel"
                },
                {
                    "name": "varnish",
                    "stream": "6"
                },
                {
                    "name": "swig",
                    "stream": "3.0"
                },
                {
                    "name": "subversion",
                    "stream": "1.10"
                },
                {
                    "name": "squid",
                    "stream": "4"
                },
                {
                    "name": "scala",
                    "stream": "2.10"
                },
                {
                    "name": "satellite-5-client",
                    "stream": "1.0"
                },
                {
                    "name": "rust-toolset",
                    "stream": "rhel8"
                },
                {
                    "name": "ruby",
                    "stream": "2.5"
                },
                {
                    "name": "rhn-tools",
                    "stream": "1.0"
                },
                {
                    "name": "redis",
                    "stream": "5"
                },
                {
                    "name": "python36",
                    "stream": "3.6"
                },
                {
                    "name": "python27",
                    "stream": "2.7"
                },
                {
                    "name": "postgresql",
                    "stream": "10"
                },
                {
                    "name": "pki-deps",
                    "stream": "10.6"
                },
                {
                    "name": "pki-core",
                    "stream": "10.6"
                },
                {
                    "name": "php",
                    "stream": "7.2"
                },
                {
                    "name": "perl-YAML",
                    "stream": "1.24"
                },
                {
                    "name": "perl-FCGI",
                    "stream": "0.78"
                },
                {
                    "name": "perl-DBI",
                    "stream": "1.641"
                },
                {
                    "name": "perl-DBD-SQLite",
                    "stream": "1.58"
                },
                {
                    "name": "perl-DBD-Pg",
                    "stream": "3.7"
                },
                {
                    "name": "perl-DBD-MySQL",
                    "stream": "4.046"
                },
                {
                    "name": "perl-App-cpanminus",
                    "stream": "1.7044"
                },
                {
                    "name": "perl",
                    "stream": "5.26"
                },
                {
                    "name": "parfait",
                    "stream": "0.5"
                },
                {
                    "name": "nodejs",
                    "stream": "10"
                },
                {
                    "name": "nginx",
                    "stream": "1.14"
                },
                {
                    "name": "mysql",
                    "stream": "8.0"
                },
                {
                    "name": "mod_auth_openidc",
                    "stream": "2.3"
                },
                {
                    "name": "mercurial",
                    "stream": "4.8"
                },
                {
                    "name": "maven",
                    "stream": "3.5"
                },
                {
                    "name": "mariadb",
                    "stream": "10.3"
                },
                {
                    "name": "mailman",
                    "stream": "2.1"
                },
                {
                    "name": "llvm-toolset",
                    "stream": "rhel8"
                },
                {
                    "name": "libselinux-python",
                    "stream": "2.8"
                },
                {
                    "name": "javapackages-runtime",
                    "stream": "201801"
                },
                {
                    "name": "inkscape",
                    "stream": "0.92.3"
                },
                {
                    "name": "idm",
                    "stream": "client"
                },
                {
                    "name": "httpd",
                    "stream": "2.4"
                },
                {
                    "name": "go-toolset",
                    "stream": "rhel8"
                },
                {
                    "name": "gimp",
                    "stream": "2.8"
                },
                {
                    "name": "freeradius",
                    "stream": "3.0"
                },
                {
                    "name": "container-tools",
                    "stream": "rhel8"
                },
                {
                    "name": "ant",
                    "stream": "1.10"
                },
                {
                    "name": "389-ds",
                    "stream": "1.4"
                }
	]
}
 07070100000011000081B4000000000000000000000001600AC2BC000000FA000000000000000000000000000000000000002F00000000mgr-libmod/tests/data/conflicting_streams.json    {
	"function": "module_packages",
	"paths": ["tests/data/sample-modules.yaml.gz"],
	"streams": [
		{
			"name": "perl-DBI",
			"stream": "1.641"
		},
		{
			"name": "perl",
			"stream": "5.24"
		},
		{
			"name": "perl",
			"stream": "5.26"
		}
	]
}
  07070100000012000081B4000000000000000000000001600AC2BC00000080000000000000000000000000000000000000002A00000000mgr-libmod/tests/data/default_stream.json {
	"function": "module_packages",
	"paths": ["tests/data/sample-modules.yaml.gz"],
	"streams": [
		{
			"name": "perl"
		}
	]
}
07070100000013000081B4000000000000000000000001600AC2BC00000094000000000000000000000000000000000000002800000000mgr-libmod/tests/data/list_modules.json   {
    "function": "list_modules",
    "paths": [
        "tests/data/sample-modules.yaml.gz",
        "tests/data/sample-modules-2.yaml.gz"
    ]
}
07070100000014000081B4000000000000000000000001600AC2BC00000066000000000000000000000000000000000000002900000000mgr-libmod/tests/data/list_packages.json  {
    "function": "list_packages",
    "paths": [
        "tests/data/sample-modules.yaml.gz"
    ]
}
  07070100000015000081B4000000000000000000000001600AC2BC0000009A000000000000000000000000000000000000002D00000000mgr-libmod/tests/data/module_packages-1.json  {
	"function": "module_packages",
	"paths": ["tests/data/sample-modules.yaml.gz"],
	"streams": [
		{
			"name": "perl-DBI",
			"stream": "1.641"
		}
	]
}
  07070100000016000081B4000000000000000000000001600AC2BC000000CA000000000000000000000000000000000000002D00000000mgr-libmod/tests/data/module_packages-2.json  {
	"function": "module_packages",
	"paths": ["tests/data/sample-modules.yaml.gz"],
	"streams": [
		{
			"name": "perl-DBI",
			"stream": "1.641"
		},
		{
			"name": "perl",
			"stream": "5.26"
		}
	]
}
  07070100000017000081B4000000000000000000000001600AC2BC000000CA000000000000000000000000000000000000002D00000000mgr-libmod/tests/data/module_packages-3.json  {
	"function": "module_packages",
	"paths": ["tests/data/sample-modules.yaml.gz"],
	"streams": [
		{
			"name": "perl-DBI",
			"stream": "1.641"
		},
		{
			"name": "perl",
			"stream": "5.24"
		}
	]
}
  07070100000018000081B4000000000000000000000001600AC2BC0000015A000000000000000000000000000000000000002500000000mgr-libmod/tests/data/not_found.json  {
	"function": "module_packages",
	"paths": ["tests/data/sample-modules.yaml.gz"],
	"streams": [
                {
                        "name": "perl",
                        "stream": "5.26"
                },
                {
                        "name": "notfound",
                        "stream": "mystream"
                },
	]
}
  07070100000019000081B4000000000000000000000001600AC2BC000000F4000000000000000000000000000000000000002D00000000mgr-libmod/tests/data/perl_dependencies.json  {
	"function": "module_packages",
	"paths": ["tests/data/sample-modules.yaml.gz"],
	"streams": [
		{
			"name": "perl-App-cpanminus"
		},
		{
			"name": "perl-DBD-MySQL"
		},
		{
			"name": "perl-DBD-Pg"
		},
		{
			"name": "perl-DBI"
		}
	]
}
0707010000001A000081B4000000000000000000000001600AC2BC0000B48B000000000000000000000000000000000000002F00000000mgr-libmod/tests/data/sample-modules-2.yaml.gz          iܸ(]+e ᝣ-]ݞ񛣃Rf2̔T/ .JY<cD[,@ bX<8fa'lIg=[On?NwVg]>E1F("(w^w_[=`,)
Rbnk%̒㪽J;[(-^xo^Ye^/˿tF=xx
[?l=|kq]ܪTܐ!]ɝ!E?lwKre:]U5D^`wu7u,2W,lU,6j9}>-{+=6o+-^HɮVY&(lZܦԗ~	 MљqQox _?`:÷6z/v%3X50ߕ]鋐	A}|@Ie䇱(B)QB.l'a=T=v+`bGIұ}$XQ5&(L#"RCB#-Q|.QO4I3*Z9	ڥ<m/З&(b:R؏)8RI@/$	_|N7av}`"ØŔ	ԇ>qBaP>3"OG.0T~@d	PDQ?X*J1,d,DɄjHT(!Kd ۍȏٴ~9y9\T@LT',p~TQA0:&3^H~pf/ͽ-L{[5(8e	(X5tB0 lPn3gZwۣ=%Q$59B)%e)Lˏu0+I(bIc<4CNV@{oSKB%PE1#ǡ7MjZ\勿٬0\G4(ԑ6ЮUeWFf,hM`%DCI2?D5K|J|"dd4sa.;k)$"Li䢏_F(ԘFP9Raw38
:	RO#P;(dPkAР`S7;Ia"9H(c2C U]nA,(tӅZ%
XKS1cp|'VVȳNYXΘ8`9,]hq-06g>*W%5ύ%dbq^f|)1lh;|`Ȳh.9n%A&3qZbnyQt@S8\b͘³ϲ%Vir[[r$!R̒Ȑp4l[u=@T)PQ),=6PPzgv64&v
"{@,C rFlI0.9suy؊+ T˛ i_Z]2H/<xrTO m@XVQIAp>ŗ]C=g85Wb2V'wy"= eD-K_zwq?l*0?,&l-> 懥~}Xl?Ī7P3Casq'1co15lީ.5G-ra*WfD>9[K*9/Rme0\ܽ~`7O%^gvc9ZGGLXlWfy54`STfft1*p-n~MrAJ>Q8_
v/T}"8Qd%}&hI,5`@SK]iѨ(4Oz-Z!9WO>|_E6ݥ>ϯb3Hia5/#t}|dXnn 
Kd,RA9(|Ŝ@pdASskplK X38E]FsyAT/C.H_i\
E)۩a UFU9EOD;ZE|Ja'hf++kt6͹C-t3E	p|ۣ84힔`By,s0M}sԆ,D=E
|^gZG	̅џrh164	mܬ*:=MG0$>hݻ+O0q;>+ve3BԎݣ)J$,dN5~rv8橹{j!;&>7nEt
΂<Mԣ1JS(b۴	*1n]A;L;-{~37f~8P{vjyl_2DO
$B	JEko;$/PCa>A&"X~8\8x(cIc]C~}%i!^Sc!9(6c,!+Q3
^N=EЦ8$/q~6)&4$ܲq0Rּ6{O^x˳nӛʬ%)ovlz̍byzNvܮ5"*v6ի[W`Тf;śm8y͕E
PlHx-&%g!	L q=6lNCnĻֶN'B^ntcᛸROf%{}j`_xԱF o΁k}޷;J9QP{`jmԐh}(@;vg(/qH0Iw&avU NhuݯW}=j5]r-}c6QBF`2V0]p#QCw`[oU,0fV^Q&Sp{V*՜nn9|ŪVl7qd*9uu2w3J2UL:NB*8.oyQD {Oc
	\5v]S:C-S'ęrkw,?[C6ep[A(b$'D59Zvp0jm%F=@N\[Q2I^e
hL`xǨHRܬɥ.K1?;dQWihNjȺHu*f7{>?Oi)ijF|*'h0-RTkF0/1H9g] 0%ʡq禋yױCI(#>HFRbH@!9c@)J$4#R8!VgN}`'DD>7B0!٘	*c".8'jJI|>CYΛ~meM
5KI7#;!j'#ATz5f`#kql^8.En΍]KΤ9u KSYպo\7n1dyHjp>IVaCW}Ѹk3[47r(T+nc/ݤ*ZpŖ\{hPh}~p8u Vv߫fٚo7FK;8;0UO_&g}V~GWmL@܍RȘ&ZE*K@	A,c
&,REBl$ڱF'<a U!0hQ0_:k9h1H|zRjA\~5MDDP`|cw>AP`+֐.xx8A	̻;o|Zv&.)翾<׆ȭar38қMq9l%ݨm~vsء"aa}q۪Eδ>j,߮k+{Za&Lh^´
.-Wz[N׍~_ʞ/d_=)8%5SoTy\^jed{R(\,#>XA&[yaU[l6w?Ml>͢B_<-|4pD"M?~b+s`V(n]$9sQ}um/Jm&P[o0,MMPr`<r`nvYr~uoa;PnCUvÁ7\fݴN{k^+9+e|wiL[#\_sn(߰=v7-wIֽ%q|{؀FYNŰik$q8!ň+?G*㘗X-Q:cx듂{E:$N1$2Ў~/bDThLbFJJu$;;cIBX=I$%ѰyG,!aX";@.`uJ7zzK&P\Y*GRFIw!(Fa^Ra^?k*	|v4:-{#- }2-9ap/G 6lWZ(P`rQxFV	?m%fv[_>AƝGV+Z{p>R]HmVɁ!fl^Ze찳HK>P`=leaif켳agX,F%O[uȟgPAi]̧LWUȘ
0~t>j6K`4慨9rQR\)G)5ES6X:iRD;dDc))"T$AI©D #%H6Y莬q#tXȝ_#N@#ULh1@SJPgO6g`a8FtSO"0G49eb)..QUYWZͳ?ύ"lV&<$Pqgǂ8(yf/{U2tKGl1Q#8QRdUUb4egBSyCۻr!<sٙ9+Yp>dkri_K?&3_.;h<?ew˕fq.MÅ$T^2\!>yj"TNzAoɔ7#VOj@>9mCuy%&kx#UCUV^R/Zj`GisYVߍ=i%4VoU^Qꛝr*?O7re
m:zaڏI	IIDbA4}6!֭j")6MךhhE֨	5;	 Z͡^.*ߨ=Nh7!:	h<rUE>zHIOJE~N6'/Qۏ{
{vpKd6xH{Mv 젼<=|$.˷,5f*
vW"ٕ0H:PNX-?5#N G<SCgo>l.sZ<0,%K)p?uM 5
D8luq<4>;zڅnAGnmqv.Ro*Wf>n,>ZE۬[zĝX]+gsqг&Ve.!Of9 A,{0g]|[s\w,/l'O>U+5bÚ+y3VsU;P6NSp+ܿDkW^z_^좱ؿ|m;*j;óvJFnLkdDtoVeOvƘM8M{_B-Hw~\m`|F*٪!ERNL~X L<[·}kD]`j.ZmTC/ϻtj6k͢l>v;kE¬NjTLV>1M<
~gOFD!U1%SkJ|łȏcΙ	;hԤ'ZFЭdFڧ{t>-w}|[m[D;*8":$9)i=t6Iv'2|[?[:m)bP*IB_HȗlF4Rq̴z>Ea!Lt_^JwP'Nd W؇nc 2L$D3MP$ak{cj|9	tH%?ZcwE8AĐOfoY{Ժf{cjOϪ3-e"|: 4a`"-OPH`rTXs
7C$HK5(F8/^U8̝O$8yF
)pMqX?wcx2#q()^MaqE΀.cL(`gKq"=cK3JhK?&ooX
S?2e``Nnt0/gu>pLIs5wAeW(+9K_%rx\cbJ {"M~Q%c_g vk_	$7o52qEqE)JNxLN!f)⾶J)$pQY@Ui$Xc\f)*O1
=qg<]L9M[qc}4sX*$8Ȝmo;lС3BLT18\$.]{(bOZ&âFmAxTN]luIû+&䬘8A^5Ga	gh=n)no1}W"{V_GJSѸ
γ?sɤL(2ǀ2[7c0=30ER
3ƕ7~ߏ;4 ǌ_g9:tńˀYjGƶo>xd$1;
voqwo:?.ʼ[\mv;/C#Ց*]\>5:,l(ߩu+χ<Kŷ"fۤ 78<{^{KR}m饐¡H?_p?Fa" H@9bC7So6r?d2Nm^fMK^gx5F|nDĤ TP<:m.襻0Cjooٹ;^~b,TOUOCTcĔ1`BP:;S;^ax["oI=K6nZ{0dBe8@H?q"` Pܭ';L- C1褢HNP~`8#X	N_oUdy|γjLW~hWƌƂHp%pOr١y}:ߎVe/v2%{OXTx̜6;|8TE\cAbIn0XʊKK0y=҃`Pe2/p@A%

H:%J	W }4ݕ"E0h+ḙ>C_L1ڋ]^lW2G<'f+xHp1BI~ SZ(x%! >O|cCDfz<R`\xvL  I0Drc%qayGS	uv/MjBt.[`\uy"bg	T*
XD$<XO>=`Jpg^4,	 
?xR\GaX\cT퉇4qG@G"QsZG-F[/.O2q`?dz+mxhuc7
a
RcVDias7I_Y)/=gtXŬ
mkeK4QlD	-sh
2$#Fc{%#h飳m۱'QLvXVKK9`$l#\1m\6W]h<.b&)\O咓0h՜NZUș 0OT2m
<-dKozsƟ@3ǿY>"[хG'o+8W6F&[S,=}I2`4kߤYeYmxѨܻ_^>3mMw;ɎġגDT$Nh̒i΅SP9^ب/8Xca	4ankv(
υi~58YF'yn"<xq%yR'+Zu1wߊx7'{\|Ջ({e yo),jUt˳jJTVu
̖W$"W&'gg]m}bJ:$-OJblqfep~!}-1{E7̟p+M"^ 1{F0ӛuľs[46bUB+"b+F|[iͧ7{swmQ6bԑSaEGc&Uh{wcƽ[s{׌)]R HwuY·c;>ߪnJ ^.t*Ӭ;;nD6lwkz .b5@mRS;OlYbҸ\
{+ FTϋKȸp`0kK|D4{)o?ޔ{<Qws
@s>)+
L1J_/]V4{L(P1Q*5Vjm`[QvGytlDyU`2ĂS*m!/^Tj[zHgS_k=-ϲW/꒽P/ɶUPfa|^i<X%1ccH ҉s^vvjʰziI*3"!]4NP vךE'P֋lRz}bpPs_*fX#F:,@2aze{J\d&,#Aw5Q+!o{(0a( i.Ud``x<mImn]\NIIdD%HZtrIByc>"p̌!5C$Bq)C8AHTDZHn8#VjR_L3oZ3iX$`	84ITqXc
}a6'۫1D 9;*όH- Kw*m9RW	LQ'4$>P&NϚ5IQH7	0y#cv	1Mpx[dLE	i=3nE	]c\
sbY;eP+zB$/u$)NB!BKZ*0aEy.pP o!sK3ı^[τuFc!_	bUL)ZgmV4H2TB 㨶% p\y^_x[Z$3088($퓇iR xOs9IJ\4.b,W_ lμg8Ee3fՙmc*76ňMIpبq7}@6hd4AT#x&Q߅!*'¹^XCP\xMFpzb	PZWǈW>žOVnPh]$f^W󲬾 
j{s=qչ!El*uyuyIE&#'݆.ۻ$~ڼ+z5p֥9 _4늱2վiW/p5;m_`>.q/Nt_U׷2WfU	wmҩ<x~Uм-yzf{q8ڭڽ:qwK͑iqֻvÎ[7(tPE^byz-Nuya5w~H7Xw/n@z|<l*rrC&>vúwh,׸P-Fpsӫ߉l{gU9G-06s~i#$}5ﯽ;֛Cskds~!κu|*R
3\8q!߄x[gp.Di!=NkFd`=N\;w49ɩM;. M\;hĽy<N"m*DfgD&{2͍ZTaJ퐀+ P6İMȾ
'6@6t*]/Ĳ=vgP^Tc6<w{~U>7՛B6?1Ch@~d٘R,lcHiAjSm2oYa3
pqJMP@6ޡ.z-so,
?=cZW]p.iFplɊݙ_6D*4kYX7&'_fm?)1s4S40ZykDOsq9)Fb YǏ8QptF (揣p:B
G;a/p;)V=
~_=͔X{L!\	3̭Yh8:/c/'5JL9Yh۠aB#䇱q釜iB'Q۹Mg/XỼ<5Qk㾰(4f0?8LibL3b*V3/p]1/%pahU,#HGc)@E:S<t$p_n`{xf"!8\I(+
"	R@Hm徺9H<[SVovË3*Ä:XJXDdrZ<[[-
a(AT&WqHp6,ɷ${r氷ޒy<3P';T`b] 	,#1ЍXqMps>f.iO9tʾZ+Ru*U"j?%AH)('8@XG^t|lW:fNtRˆvtOR}ZiWR*%p$14"vL8cXʙ/8|cl>+l*nnlnzb0(1%~L)1avAs$ek0ID&(	㛧,Bq?6fwkcZzɕa(DYQ5yͺA#`8J0eH?J٫~s%(8#>T>3q|>,|*d19$Q:I}>1UhuCS¢fJPqSf-W$MyU"Kʶ9!FB6K
HńæR(dΞ9:rvU[AS^XAdxֳ"}OϾmv$0
p1ט'~BR8:}%^VY6AJ^U5`~y4R!Cȡ2 vHD8	BMa @8ma:'k;Yn*<guW7N*m8Ư?@z '>Lreؿ5J.XF21[%0sB4	R*$sl'R4'M@Ƃz 7b0:4S`|Gxn3`F\Ԩ^x~WnH,I a8A,X(J`0D*:W,>C1C82`_@1b1NiʠJl>Uם].ۭTGO?LP*lB"Vq`b&>
c<wUGcFFX	P>Qb/S+be8pP-nkws-߲-ޤs~dO<[e7B/u5bP"`T!0R<	f!%hvSb[%\ H^qJDP(T$(P)>/Z}Cװ1z4g?°b$2 7J7;gMdAhYJMsQcni0{mO$F:=RpS1
br ߲UήUl<o'E0i+Pm,XH$
,P@ "I.
. OKZtQe]Dޞ{޸ hfT9A>H+,1%'@X2PI|pc(&4Hp-cAM=1K.8PHMp~#{q*P%:5S0\XWdMy赅[%2ٟyh
1Z*u"5a$	pPJG%G8m<AssQHRHRTg%_0갱>m-緝jUyI(}"3d20y/߰מM6RƱd	鍴#͠@D`_I ѺE}ޡǌ#03+,ɾ"L L;;KBFr-v/p@x
 IBՌsTh]$&
>3!"P$I fGHT,A W'oKgڗ>DmG8¡~ 
!U	eFXR#k04ߞ iILXDB1dV1XJѤ|5if`_za1}sGKqoo @n(;3ucPcc/2V<RA3=`gDC`SOX&GC태<i#,R#_xZ^}.&^ՓrSi#)#}<^ݮFBs=QlssĿl~ݓC"֜hiKҏ0|x\p2zvce^SuClu:j;-z\k\&Ѿ|B¼[n<>a1}Q[xnr,QŐ,aOb̻+AIiH((BA#ǂ>z3dp*mt q+7̧}ɓࣨltlAۙ
)qӿ+G1zs.˹;rn1,]P44Y`~l1M{c*(V❓<Bo$$#,'VǹxuD2Bp9&/afhFrƋ~)[z@/43y9mj$E63s>x_cezz9D]7奐k[l"3`3p1pvȬ3L#,q.|
_C-Cx5pXZj?U2ٍgoFdU}cL5ƣq˔%75g0G2932\L$@19㏻hyuQFl
]Xu9Yݧt˅;S25=&?PPbxVusyzKo`	$r͐efп; 9]*tOϷ-to g<[Z?IC<۵#n1	q:?
'2cH5I7cT?-TzZ`n mkoO4|YpL| 	Wi)	n
>33rZGCi8ݐ'ǥ}X)5BK(oH{́M_XDcȧIS	UGhv)5Eԧ0Q\gVN~4YŃ\(ۋep\]Ʌin.b'f")(.)e!v1>U_D2X"2$6b"uiAq&=<W}F2rcMBWhNNvA,<Ov9eT˳Q\ZUKQUs1\ZET]J5Tg"LwJt\-(Fr+p\wGlsWR$&Shlx2acM{u|m*iY+6iʭ8ŝJSbUuT{kGq	y.=4V:]Ψ7,1:=d16`J*cٯSq@k㤴6dvg7N&u[V1`S4{ZW~J/U"KV|}bǨ'*TGwu
+f$՗N-4Ww`T7+:oauwu> ] cħSYx/Ԃg&v0:=`o׋쭉{(Z&LN}mn:\Ɲ?	r~gweV5]l*>-"c𗩾۪zasvC墺4fn38pX9Vk9jM~ 8/>TزV*	>kOM6ՠ-?5~jA,Vq6͂\jԊ}ܼ,`U~Sb]v߮:0rvnz^vx-T]	_&@4.jf6؍K`U]uazU/>=n&$9YU"yA~39pcѨ<%e/O%Fc~4q'@pR7+"@d:g/*϶oٗ;ؙo{,Wv@u+ɾ8]ṋѻe٧;'*e[0$w~Jm,bחR"o}5t~e޿9G2mv3_ݝ=@/p\2soNz&뫉1,߰=v7-wїA$ݛdXvGսEu^9,؁D$aؿ $P8 n2PP?@1#!O"}PJ|r qǪwڸnbØFL"0)xH$.'sYBN:V$tׁٺ0\	V$;8TqLYL)+MdM)cXk((Nm361pj_ud+~p%Bȗ>:i; 1Y!w-MwkSoN%#fVVD<לcc6˜a˓cb.RUc
xݍBO
uK1tE<0	^s+N'}~j>cb"A("&V(	c$H8דÌvOjM<;؏%Qi@q a(
+qvX';<]ԋ7aVw󛁮( bZD%1c9~!][]Asb)NT ]D@̏825%X'd`ID'$XS+A$5&.FơrBe3"ݍɜydoJ|UUbs4A @X!T{49=I?1✁LDt$2.p }MmdG
;ȥLuQB>80lBEPɆvhÇo]k}QzT)#$0VO*SPRhr\TsX@.?W_ک5V84O,: )&:w}c-5Riιa?oBOX|hL XBEԾW=RExtkW3ۚPʚ3	 C`n'~DQ()%K(f3d%)LJZܟkn7H03u=$D*8x(ĤmBƓRgM~Ɵ40!1>d1 	)XYcɡRĽ(/6LgXMHB/hq(|"$P&+Ց@G}FΓߒc͒f(З53S5_g76`Yb(ŵSa6yE$f&
=w
KKW_&+;ubs.!
%ڰB	ZpYEs"bҪAkq[r6(׊%8Qx)B.aaB`MOuZݥOG^6нRo4Sh"U 4-1k<Ynշ>NٯC;9=r
aX&"4`3X?	ÓO=7K9*u$!z;Xa(	ڧHpX7ɛuu/oˊCʡIgTxPZIJ>CHQOZwi^W5JB?4ѫp&!ZQ|ML:Y1YwNOi*eaj$K=AlFZHa_D`h8	{neBQœٯV7ͷ=XnW$ [ݤJְA ƥ}HMCs	%6;CK1H(~Ўz0ĕy.=g#i|l8
@tptV~AtN\QW΂/_ge$ABә9EJuT/$<./'YҾ+ǸL6MjӛOBqB'3:17|W%l&xD[L\MS"=qfK)7OLiv/<|g#g88=[7iVQw"#Zei#V!Wh٘8gh'GP'e̀K숗<ns,jRjغ nmQk2t#`#a־6ڳ	GhF]o\3XYAB?|2KOpe6'ah`܎l=ýLnO(Əx;h05j-E#g=ly[L{-Xj;+O<R+_~]}v۵sON~^q"J20MPB|hT4)Sxa2q%d;gWޟ_%"؄X*	Q
DHBIl./{L_^IAD"cY%e8~$,'_쳵`g/ a,y,pHJ8JSqˍV6MBؤut.HKgQ'1B`8scme!mL든-978\Mחre}?i*18:ac6[?C߭?3ۖNa4*y4VA7a k
I\
v2ym`T#V
&Q~P+M{@Z0'tȆRQ#a௣:I*H:e!G]gP(S|V(hFZ8SC5ʜXhK4ΥPFퟺO#Ԗ*nJv]Um뷊vmN[kV[KΆyqJv,9ds*բKA:ݤk6йq«rd(ͩ:+y|3Z'2ӐјJ_*AP8;dh4\F3u9+0}5U8CLCPlL>pA]NZ:Dsd#.d6"I C\=mz8_+^84#3	WJj+D10P.=6~(VDHƾF9Juƒ_8,lcaDȑ=$K$dD.Oi6?my(1")M9s,b~0XLf'96t~Vn΄Mlڿ: D\Il#*-Ϧ9ۿ<7dl@gnײM|:[M=	9;8?-QϦ#\̂Oܙ>:}K|2_#a۪jmWĩvBKU>mT2y}ÍM٘V\7EZi[䦛E`o.l:v@	=|3]5)Ȧv6_֓V$ m'z"Lx	6@&ĸu8	pVL\'T`rˎFd.u*b?B:cL.F66QKu*aeqlmtOލڨ]*l*$'e"TuV8иN&5x0Vt
ԯrC^dBR_;
U4`޼eUj*7݈,0ø~ Ff͞}yNPrIgET>xt;5[,ã\ȧ$vZ=[Ivrk-f;256?ۦs_.5*Ljj8nCntJ$PV(&0F#Iqj嫋f׏u^4~'u{dǁ'F+=F`{~e=,4d@g1^U˘3^Qk'	m qXLBμy52fZ0IXożOSr<D=
nZSoĦA/}e<&#%uO{H]^p<tDP`u\5mְGu6j߈ġqLdT$2.a@XJ>ԀYX`"]<MQN32RyvLF^f6BhM&nV1!jгuo }e,ƚ5k*ZӍ2jo1}1x؃Fa6FfŌ>@X~,,n 8|2;˲2aAW9{j Lǌ{8'[)%Occyc}es30V֋0XwznUj|t N/9j-6_޳=9Ϝ2jNX"V`K
#Amf6L
 xLJEoFcQtOח}{:I\4<9C)*Ouoz'_ɿ<
)d<ȓs!OhfȓXeuм6kY)#Rh$e5+KEnqis{oa;\2O3"sb.@H~7~~f"]~~cȟ+Ck[EfEgprXV,MNM̭>_s+R,I\Un@xz\#Jv\iSQm(۔ysf6{X˾ATԊr`Jd|Ea"IlE\-cD?+[q鄈hBŒT3"("RD`$ɤjԋWjXq8&$	1"}4
%QjrQ57Qe*~W"**I"JEXbi"/F_DuQW7DtEB<	̻NAS˽BX5%3{
#t8ȃcw%D[_ĵ(_c42BصzZ*g+wu7*A<JILu1M!<B~'>]';8x8s為9Uml<5w;o8$Yz<s7boJ)&'t&{;쭋i{{sWK?8<l1g<8fW]6Ź=a8ޢ5jNPˠ|QuM,jK aq6Zˆa.jN:tbs;l"gվ9mZg1\[y5T#
tH9c$qhz2
?"I,펀vsA;|T"M_??"AwZ#/Fu m~qG;_&&:8Q'wؘO
`Yl^\=$KkۺꪝvJ7b>)2;K,B,\]تe[p *GFΜ
讃_~,BKAXLVjz< dƆYjm/2!ܳJ|`؈w-GyM`(I$:"`&2Fotf C%LaZ:~{sϦŁM8IbИ4c*BSmb<-<M$U`TZ&p#܏KBGF8.VN#p*EXk
@$B1L2EWh0c!i@-qTrhbbCWB1=Ļ!X\a:8JLXQLIs_$-)u7t^!0DC6p6)UH Sa:"B2$?aN"s0d>)USa1ydH)dާ6V?i<kQ9)LQ{6 b4-92OGbƢX٠	T!~/zAO1O&tF!ǞQ4!͊Hr1+"Z1!N=	jc~l<jc}X]bX_mԯ6Wk#N<2:ADD3lfuX'Șgu(fX'hհ<hSc!|'TviRV&;Xfz(G{ov2'ܷڙЬ&ۋ'^$V?ƕNhox\5Wi@Q*+K;gq6aCj3r((8S0~5!RB:ljkҼyRcXu萢! T&x9gśC{xYw78/ie3K'AQN)eS2`9&Ŭ4Xbmi`ǃ[1t\v[R`<@}Q76pKSbKHîM?Ż2pU/LRѬkͯAᇛLs8{[̻Q>~am7X&d-xkŃ_sGs0ӶkCgUrQn8WWWJ}^8Jo@Y,޼?>k~1)O%<un
vܦ8_EVe{
I8Ts~{fapd7l΀?6 vӑ~P{twjvF(Y\PRl_6}wWwYzw3Q:Zv?o@+.wi2'Pysyzj(^؈l%\߲>*W,MOf;:mΧ"î0PlؑLpr.iT槟`
eyajZúUI設dD{saܯW2{L cJQv;==bxrUjM[)vFrUwj^<Ջlz_^mllf[;C@?v41NOsk2ECtz@=n^UD_6J0&9?dD:;L[E<82R3'5:H6o\J7R})la+ԛ%([SNLzvXW"fZK#-x!DuI0|_W_~;~x~Ŗˉ8BVym+x;#͜ ۊ󨸷c#ZRRQ_I7N0޻w4ɍ{<8b۵}<8bu1kpn}8(3mi/BG+kk%jǄ8(>vԾG"o#%Zupl^CPtF*e(Q3(8N~Ó'4#VKqƖ}.zsN4i}sS&ru.[U{`<cz-NF,LګgS+30<r_Hkȕ(]17}%ѭleܹE>(2ɒd$d1gv3U'O+|eC||	~gsۻ_eY](-iptm5P@rXI.+S
,$t,UcJL|cǚmW3LcdJ;	XqҖ9l+J5=4q0~r>븝f-~Y\Dc@}B1հ{:^Tm#eQ)/tQ(*l`A8\&^DX[MK<y5,r<!:,82dRJŃ2 $Ւ(U$I#@w2:z>
 T<8D`'L1m-0\"ŘiϽ
v]x;i*T`*Ŵ0ˊL1zpfԐ
	L	X[7ȁyW Ibd	ZہmCa1FN<ȨNP8ͦ_PHOl0ʝ!i87iD,e@v	[)`f<1)	\@{-$0D$p	8zU)^ZI";8> WYÄyp&bmbP$I \ؠ	#൱}8,x2^j @Dq`5?"w4#H #!^4r$sѼ|'RK)Id/sЩTB-Ԩ}T~}l^TA#	V9bT&J>ҌĴqIS.:h5+&3JMS HP"4~ϤEOK7\
Q0&0eK*ǉ@-Sb#E8kPM1kטC$ hm=ƈf|v+?!
쭈2ɵQ29iLj=XsgGeF/
9;,Fz\[a ӄ(DTl42
ԁ̍@6*:n(p**YRb%|rA[Xd,c",PfTOf}qP1R6ZH Цj>,1<,̱FPOᆹ\;` -XDm%)J8䮻U
dj\ wv@:liЬ/1GHK`;q5Ig5h+yv"D	["'PBx5Wzs;(O(+ULPn5z	HBjt,8(- `XEba7Pk$:A^t{<ItR@MEfӎH3hr(̃P2F@aY4Uⱓ AօSI0Ǭ0z4aX8XA	V`7$\C=H5zokpaG%%q ACaq(6b+Z	3e0D`
r'%(t[Ae0U4id>U墭d PJ9Aeƚ18U!-`"a,QtISdNeb(rWP$f@s#ʉ6("$ *	+9q"?2)a)tj1eBp6,9x.VE-%u gBAHN:d!PL[1Arp
Kњc14*`fON;FT:qQ8"Kpu T3+&3%!|#F:Ve!rXiPp` X{ZN|@yb 2E9@O)2 `3n;9ǖ&nd2L@7 	H>	97r6
TP@V38"5Rjz7 !dXJd^bq~\GTY4R!2C8~h~r1pc.H{|%@6RYLaO\lbg8V"B#2ݻ`e4$Ȏwb$b/ёkgE@5F2x'Aǎ	BFFe'G{/6hdJ`AZa8E
CǭzTZ$,0nLIh4$wYAnd,u|@QLˈb*@,Qh6s8ޓ+r"H"'$VfȐ	Z"yrB_D9L/¥Kh|t }:79OIM5v+@ZVv1;rq$墐%Pc(f	0| Rv^)¢$?0h4(rk	dKA@*GcMAE+_#7iD6Z/l\cDOA!1Q(2+c28!Oz֤sAfx|,`>(r-hk(j fՈ)VdVF@(ypP4YAbۍ̞lEL09c.)8>BQKBA`@RxSa׈n;U؜Ta)9 Gg*ᴏUE+y ~fRXdaF!8ьt8@#0J%*xANUъ98Zqyз4by,N%/<I@Kha
zzlFl&r,S 5JzA@.BS$"\:c$ב6X"izntHZJvbEL |jlA BUNqPȡD
G3EW)jxXk K
{T('ǣy9`ѵaW 1b85Q{0:Csa<3$v:&4	h4q|=26\̈1*E!p,r ("v4E	!Aȕ$ia(G5f!@Fm@8㗯ʍ;TY0h|L2s! [ߟӈW rMjZaG	d#(I d#,RG,эu?^P~qcZ"C)!XxQ:Be-K &h6Nd(
GzU%QGx!ZA%At(W2C 0Y 6~*uzi&(x,TAEYEPL0A0b$>㽚	^($! );$7Hc2ΉcX'e{8Ы<\K|43NAȰaq6<Ic	L&bKԸrHV2x
3E@H )l)C̱qTJR>Vtpy1`A|6L_<+gʰfr h:`a"q.e1zc)D451	*rl4a'ҔXXjc3)*JmJT[/8RΙSnSD0y6AZ+H^S1la
*ǭ>t)rD|>EA(RPD޺a\}4]JzTnM&^:
$Q6;d>l,jdiDlCt搑 '%Ԟ!Ӓr!p-.'fs0[SL$kW.M>wuӳrc@;vEP"RcP,r)IH]P1Bh(VEMuF@D\߸m+GJ"NMvtUȩm׏<ɀde's jOڄ037jJ}2~殇r:ikbDRU3uLZ#E+Vt&@ӻ|3/޸S kl١2U_
9Y99T[>UByq.*0 PqZw=K/ ;B\մ\[khӉr\8[G2[@LU)j2,aV/Y-iޝCL8/T۟}&S k>9NܠBN_bǩT=1ÀL̪RE\nS1L=#%Z0ė}qs}"*3;x\_ ~# @).JAQ)D0YĪ;0>bt FLO^',۾ B.Fȿs/#4vvNKy eKkTQp0@Ű@sBUDK/J!t8dz͹(5;NT)=_W¤BC V'E7 ҇FζTQ\J}
v'IWGt]#UWN?$8j<MIpFVyF<rI9d^sS
t"EFR§8v)v^@8)_CgRTɝU*NT`^
[;zպ1jB;PgPy8r[}3S2RJfAp(dgQ2fSF.<5 &m~p0TM-u)НF+uƸ]s}JJAL]Y>xm #aDbaFRqjԤ[XU-Pd)tgq(%
K33HS\%BIF6jB#!5x_svwm_R=֓^Յ$s\Bꌨڋ  h$h:rNJ,	!N:4\,cK_B-jN !gDVo@SU&!'j.jbs.KPr=H)ĲpA"H<Re(e˯va$mvQa qPVD
9-XޔBàB_sˌzÀS8Gb=)Ěd1ˆ+}N6 'gT\Ҵu۷f$s HiQIe0׹Ht}[v]غgF `S:8HV)9ǅj 3շpKwJ1.lj/(n߳Gmk! Aә}ζ~ N6l-lL o("HrrH#5[u6@CX3+vH+kyJVgbTt~uΏҪ.p!sHaz8+E΂V,?+0H4U_R]	 pt6Ma._fjHTz)}f3c@tQ `qiܵ-;IVq9g(8i5p4p2`8נԙ	6n:=]5`k+Й*]L:4t-7ʇ]
MypQ0ƑPC^J7~>uB3_eۨFg1;yW\!NwUzu%1^M5BJWrN{uvͧ8·#A9΄YCX@RT+CZؔ;O4z{w_>A`eҥǨ}tǬ>C_2;nGiXCV~oe5 <F[\Cv-XGouŹ)3^a+l}q^Ui_$}73b_qew3 ,v{nl~?@B(r 7*3*$Jf5-wf}]Fu.?y-33bҤĤ$\q@@[ f <\np`~1E=q~=<7Ofe@wvqa{;_ÏͬZ5 p0A0$9ۭS7r}og[F6̒+yx~off߼{o΀)-@|: 	&n5Na笣)Y'x; ~5ǼluEU1`>vSe	<Pym+GfWf)Czэ8<ƕf	׻zs*CGz
 .{n}LzL᬴~aҝ=/Ujb=Wh>W)1c(}¤7Sjw?335on#k8JIi	VQ/o&Rcbڼ)6x&ӭ;XFF@aDjf҈eRȣ ^`#H?h`w|w8~ۭj)"\QpāiՉ^<a6?lΨO@pQfX%=@_lW/n n}"ꙶ]LuYآ2u>K=b]I˝",r_׏K`&f«LPCk6˷9S_V	Cppy2ݻԇn~ 7MbwWw
hX*l/βaul_bT}s|kB
	&2㶚s[#3 18XdTñqc㣷HڻeWx\ߟ͡缅:m^t牵KYMOd6gC(8E;CS-;Oy `r2GN;LHx^Hɟ	f~.Jw*ޙ/aNΧ$Mu;Ksh`X4e
x8L;>2j|gj]DZ8\4]M;XWζWۊ8}L~گAjCJ[&K7{ol79.hvv%UT1ɝHؒTW) AQyĠq]N_K2յH	 /DSmaaۣbo鷼󽸖CnrOҲvD=]+5=ݡ]se]E**'pG{ۊ?Vn.'inBڶ[5=ͩ.7}^TIwi*"yY'jn<Du>lӶaʲ
#$I0qh9F$TV|p{Ӷ2\-PtmbTѽ(l
2Vau<3Z gce/iw}:O5,+ٽ(!W"`F3ǃ&kjYVUa|b[0_>v,?_HÛoZө 5F*ι{ڡ7M5-a ~NUl݂hoIb}
6>Tm_?74mhc=dQY׮ Ѓi%>ЪfA"Ѯ׻?*rWu+w&soVOQFr1cXH,ue$U)j5ҧQ;zoգmlo谪PmLYIUFA8)3KS}szN;j 5-E|Uv4=]~iBDF"'QYҩΗ?SkXxw1bщ̋xG`[]y	pS;NaQ+@Kk	C`ҤA	 J  4ωMA'$?7KK
%k۰gAuFLJkJIŤquxT/g<ՖΛ4=<!596vyzI]77^<+xngفwPey	<'f՜Qɝ6
IcB`,bHoXnzRGc^b04[I6c.Pڴ9Ci񸁘t@(-:b8zR𦘴Τ53ї)@LOEڦ2!ˆn.Y{)}=}׷ƪOq[Aܼoր2Z	G7ͦ냄5;]ϮY&ȳoLo:/blv5vpƹr_Ș\cK·vYʀ|pW.7=o޿B^?ᯗrI?PR\>8cY.ɈִsBk PJ
m\Mwf#5@jV_W;B:"=Mz5-e ?mk[wWIq}QjY<]|>;8K,Kb5eϸ^v^:LǘT:8ePȑCHEllD@)2G諸qE.hjܢ:il(C0vPLҀ2wCoPAz~Q;SB$+usmp|kgW[1%2d^Kj	Hb%);jg')ToI{Kg(&Q(j֒>䢙fF:aPM&*BxO31yt~7{?\Y)TZég-iae(3F8Pmvl)6 9pd)R eW?|(4hwwS»EnhU(
BX])+Zc ]zJ	ZѶe)wB= e2C7Xu{cX>[{Jkq=o?Plv,KMq7X@}ݳ3*(Wxuyq\dpIvgsN/9-G q ̉_,vzlJbKf$`\IEwFS<	T6a4~-yIj_ƞUL_ 4YШEGvmIp08FK[w7DM蝻a/. 5F	kpa7Ӵu&kc)};3r5vlM]f9	zY{d!A]ܮ i4¬YQ*xovw)rF^[^~zsW[GAxS.5>h~~^UoEyno7B!\6poqhʦbT''C/%iE;m6r zDTShVˡ
-6ryO/Y]y<׫Y
>Ghs Y&:g9ا0ofȚO.ԕJnZ
^vm}؁QusWۊJsSAd¡2"3! L=&͏?oUNRm:67|O\~x_?Z@g,VmHMGoQ碧E?ϵgeq}rqo8#^?Nф)kܨ>~yjǬrH(17Y{}۹[. Κb}}|Ȧ|}~ކz_jzvۻvz}sJN~ti29-4^_ʮ[sqǷpw𨪱{.rs\2zl;~7x+ #7{wjՙ$yu[:wi{\2'Sl;v M"F)f>8}1.#T?ʁu6<28Wm30ʷ^lQ?S370#WsB{DΞ&N:Tv:}2@<z>9ɼi2wE:\vwir7K~Aq
|~حAh|y_i'HQ?eoy?}d -+tqk[Ϙqܭg >v:gӋa@?Y}k"Guٗ_d;WvrO e&nM[?[߳Ogtm?.w07 H?g9If^o7Wwg:K_"i_o>H=WÙ{_A;P?~}^̎]}zn]Gەۇ>l_Z}%nu`j&_񘱫ҔA_U|ŋ_!Af<Nۨʰ@~'7EΌb9["Zh`H0htIvKRJF+]hy(.)bKt(mFjVN!u.׫UJ"55:X*B4%8DJKl\!'^˚U	6i4TIaS,*@	DDbV_x4m 'Z"gLZ|) %GMMkd`EuzOőYg*},4 I;n,ހ8GYЈ7h8QE	g?22IPb
GJG/858L&Mπw:IUJFC^c@!d/hdVsO @X&\9X0&(2'CGlʂ6f)i$1EY] R-aE=%6W-SQI'"`l84nU@ԚéH7ҳhgxm4֘MP~qllMi:#$]WIIB.HGv)<AL>E?G%mJFh	 ;N̎"yZ3An8E+8R2A i30ϛ'O2pPNq.h#p^Fd7/aCJcr# o56ݏ*%DƩ.L8xP1D12Eh%.bes;Shp cυ6 DUrg(T`,(ɀ(a'qeBA'>܍]=cWG/aD,V`0
:u2`Xw=S@$9  5oR*xS@)p*ZJEB"$W6Qs?a?d=!a-	 z9w5Qp d	%K&0@&
a*iq`8lRv!Mpރ2+x)&&y[L1t:UDFh
>m		Vm!J1A!T?F!)V3=_NI.őTf S&< ]$lʕ-ڎTF[H'Li㣣lkV.}ZP|@G!;p=Ej(gYT%p$pʇ-쉢Gix8&pٜT6_V$<*C4jw
"rg.hwϋ:
F/1QHB5WCixO׺1ڟ}Gࣂ/ixnI8.ܪN{Ui/`#4FX@\u0.׃9Rtʴia945i
2xZ(c5jTz۱rĀ4leyK5INe]Tbhٜɭ/Rχiep	W7sk7`ʯ6v+ ;J:cm8#dɔ&'=C1~QTۍzjY޼QK=Es'!E)Gkky%W}%ؾݳV0`ʡU_zj8TD$tyfQ#PtC_nnSkW55ZJ,OrIInr>~lGU}}]gxSv^3,?zR^5:]33)^ѾM:m\7oB1Ezs_m|})k]uY]_%u=,\nb.3qGzڜ'ݣj`}x0<k#vbqZo1G(pgUa	5-i\F6a>!ڝrE-QS$3H1"	C\^zhrm8<-tޞMz7o8olt>qw:R8"*ϹHsbbgrnUuƳρ_ho¡\{0$(etU1kA9m茫:\k}E8x.OYfX&#ldIL?|OfR\몠Q˔UcI[aT0)/<=Q법kcb0{"OS})N/li
9||q. ܎1"U'!A4 7zxU1 nd M3Wff^	1S	mjS@,f9h CqfX,A~L/Z-rAВ^K.mB!WvvHR,
9Θ:_~5ɴzX(me<򌎾4<
x͹KRjۜQXܯK\ٽe@WDK\`eU^h&X N>{%b\{QKl,iס=U& aB/U-kO6wO?SJ`i_Y^߾snӫٟm 7o%_#Ys^9	M{W$USh=F}JEN̑/h_M86luT	^*웧ۥAw<5)E"5C$I-G8AN<f1ͧ`pfOcܚĤ{h	&C') a
UP/0ZxC9?Te}a`Z3NH[B
GKq9޽7H=̯r.,8o#RmĒdeFoK/fv0
FkaJ59VLBA|?Ϟ})X9rAh8/%D{:~&cm>nUYpw˺xɬێe	V)F	N5XeS*$)H2Y@PnItfQ쿁pZ8+S"
K"N}BZbDfr;=OœY67	|y"Z: mwZ8Zq}&8@Ţ1\M;v !jD3XژrLJ6RiӳHP.c3،ӾQŨ¡{.ivN%83D?C8Uy㾾ŭJ/w[_ݨϮns)´yQA뛞ےc-he=;v4_ݨu6ls0-l~.Ǡ@^M;?`_^ݪ;ntC4SAH?۞y:҃]ٶem ꖠQ6b GeM;v`I fn].EOx'vq.jhqnڷ"ʔ7s|2̘u8aX=<0xtzlS)qz_ }fs)ˉVOJ~']F,*}si-jawyU@}/ǛGRO8}<>wZўh-ő~ɱKCwCsl/]c`XxrD.q2J%>.5&.EQK,AඡIj55u@+_	l9n<z(r.Y@TBDb0K|6ۭᛇʡdۤg	b[HsY<R>:Ǯ3غ]bKqW%}L6WEO9?2ǉs3pŗrZ/\-'{blRL+רEvHԠ#LˀT{TDKc=RbaQ<:̒aJK=42qFw6u'dhbyC(M.T퐟ȑߘT}u;4*˒3d*VK5ˡ߯q=.K\> Mz?&c23_jT1S= f<.nfud? =e7Oeveʲ`+`0mI̪<Xw@k =Q5V {4ųTF:|5sK8Y>ܙ
5/fan=v0Û;biL_C,}JL)-lƘ2e`9Wj@ݛjMxSv[pWA
u_M2\aSꁜP M_3
p=m4eυ,o(&uc{W{"Ü褵§b("DYԕ'}bzu<l}f6C|:T$2pRi#OrȺ=hP_MR>iJi˖rhLƂ9=vq,	  (I9ջY-h[T!ߐ)g%!̙0ˤ 	~;ɃNF W:gdCAD Ih}^> X\p3@˧:CSx}2mwXpG]J=	^?cLכ귩8hsY/+}0=<^CIBaYګWBe5yI󏀫yܭ@+٥ѼjKNg?yL]e &}qW(nW02n =~#4|B_?~])P>Qi|Ӫ泀qd1U0݈c)_(URB~z7!,LZ.I7fkd<$Jq^CxYllz-_T[,VhZ{#lkXF>/H=[27z c/IQ=&spEԕU`?u 5qkͯ}tj{NOkNC^-ϗy<=캦㇧mӿnRNއyw<=څ[_RewVΗ<?=q@g~aH|pݤ="t.Ѷߜ\'Bn;yp۞3ƪF]dŶΛV)n{u
Y^YK,O1jwb?$VĶ@JRzĞ(5pSFpϐ<PvWTj엦_]3xpr+T&ڭoCGjL)DEЂIQ;b}؄RT41cpMSt!LIIdLw<(h Y71m,e´ZWNySQ_,<p9QLJHX=>v&SfZѨO7Mp_{"ǆH<JS<PgtU8zwU"dg<,zTޔ%_t3LDGXRiꔑK-`w=FpCM}OvWL\J
学2 %5SXF2r6R@mu9?PÆi<W 'ϩXMy-iݑF;7YZd{Ud(lnk+Kjf<%1
-)3RlsuB__˛Ƴߚo?IzWK#-iGx nuLF0t!dzHjr:1HͬjruM~%֍S?QXT!@:l'xYb{v~![5}}/5n?W@(^5[.NCo5Ծ3Hbv \=-Co/設/[)ekv_'`C|Vv_v9Jy_.9e/jZ5F^etծ3q.|*)*0g}v~\i`{qj{<w*x7ߟҿhBT>]T)Vϣ/laȂe\n00,փK8fx){D5)&TD
Xü8{Gc_zp2K̆4jL>hHǙB:*0.b)ԕ9/L߼}7m,?槣X\rðG$HĢV"fCQ%wcM)jpSS*Y#6X":@h$J(i`4i˝/rksZwNE)<)vwvvow8U=.Kk=A^چkPuT%\
el?f~EMvm77dpKmER ݰy^7ɨ_\ؖHFQ-e"^2C 6drz鹎ۅFi*tNttܜˇKm3	5s!];+ QQρ(nk_d=dWd]^7=_erN Q
L!zQYo0eCR`]~]hy̳8I	eEYޅo}řJՇ*Za5l,ĸp0Wא7(ދT%_;0K3pctk\ߚ+>oƯh><z1=''mqw}ӪqX-3z8E^`.GLͭ6HUR"m-'.И(Jsl2<a/錽&-`/0<PD\V͕d
S֮4j+"JR%7IY6H9rA ZҒ*(fhǣ>T Fd$JړN[7=q[	oT Nq n;YUHxGCۆ\r &`#1CuQ?ք𖫠Մd߬ÿYOV?f(-w+e c1>z!*w!׻.Ҭg wY<|~ɛ%1}I!%e0WBZBJ e@
;XZ#6~`vFJQ#Y&`V^KC$:#+S\MѓbJbbi&,oۮKdw[ҮK/b7q\վ%[7}~41ݧD̥ĺ/˛ǬvU~ӻo~?~OY-*cٷmlq_%]%aeR\5rJۥ<ey'U
ayHKyrG>Y_{Yg4VڹgmŻQO?`K<joSfqNۢ2VU/j$VĲ.i*eF(\4Bo:V	-O8<oVytmze2	nSp~Q0\X2kbe60CKtrH
JJ!AZ ZnB\B?#əŦ-}N?ٵt{$,$V(&"GrѠh< KU: $5!dI*Za0)ꔞkUC 故k K18,).svݦ*nzt}V#m0#4lc #`8C  Z״]_#4q(_xW|&>VE↞:]	c`j|%A)pcqhȾ61,m﷋ۻy^8A<L֫}dKSBgύsT>C@9L5:ʸ8&^fu}shŗTlb^j{f3y	&Tg_faɔfknWS~mLk\B3Ks6y:3u(MaDʳܚ:cc8UDy)ݬ®0&'}J@%ۭ>!<il73}sPS8,zy}XQmaf?r>`z/rPOܮhC)U-,?ZL	նjyfΩk8zb>r:V|VaL[u'ɛ~Vslr8;ZVvJ6Xz*
_)luQ~[zu ߐ5=FrKzm-kh}~24ϛ:Biiz[ʾxw>]G8
7=o*Eu}]{q)<7j)?2sV3˦v0ic~%\RFN;
?dq*j,YN Sb4ɔdSa &@>4n,hSS1iLӞiMf2r)`hYWQK[u1qyS$1ꉼxT	)fVW}{tU{Js,RN*XeǚEi? /VB1NwIN9spu3gnBuz9	C؛pyN͢J&}r#xy"qc7gPuH=եykWw֋Ǭ==!?tVg5ض3pOG>2zwC
-nW̎V/'񌶲HDؾ2J[@@!WVR((N99D1vzg'Cqjd=$`&#xJMCq>|`/(C =z¹@цHطkF1ly4*l	RZYҖ	;sa;AX	:J*Wv Y\ 9TheQ(	Z:!wzt3@D+lC"iSHg'a1Rdn(Q MU\L	,H|=2I>TTNFTD5U\kVހ2xKÉoԾCѾƛX#e t p:b	Z;IXhyDsȵ1 U0r5?=A\9p
4^[ȸp*o{*ԘP]Y].qu3eԚ1I'p<Jʄ®pГX 9Eg"B9N۱k:7@kʹJ+#O|LP}h4q<jq$p~qƇ/yqpZˠ?[弨<e >4q
p-z8QbϬ	gܱ;ٱg&k(Y@xioGI(?q_}?čw/<FTZM1)K'[փm}Srn-D4mH),/`brRR<D_a B(hGmM~_PBxk,yF'/HAȘZfF[52v<Ǔ8ȥI1(,appU ?HbE<-R]aX<x=D0\`Q虊HvApQcφ9}PY*p,yb7+hp]i8L#肢"ǌ	O4K1&C@Va̅v_h?*`7߀6}A／P]<I}9x6S;q	 0ܸ`$֕Av<ִwe..o1P&3dɝY-?h2*@ L cy_p=>tt]plwBpEg'kZv]p
vuY5m*	f2.c..b*i?U[U)8 sC4zކ"gKMvOS9E5Yug
lN!;ݗ'ۧEXwGg0$P)5e}^f۔R4z)ᘇeɟ|!S}jrpfy[;缍 md,C U5]CmNC|ʁպȫ|".ߤ 7/_v.žW˧W}E
O!<ge|sۅ6+e3wB	ntR6#l,92:+ۇnwMwFbn!ҺtO.׷f}pn}ϷЃfiV񼚉mmϛU5e=FnSGOC=HIgZ*{ktStY{1/ڪGuٗ_h@+һ{rf[\U7qk߄'&vypöp2}w]<y?fn7Wwg:umEbӽo>۞YOwWtx+80}rgXjpztnz?߻p$v;ڮ5/asڶ KQs6W2OLo^Y°H,cϬVZ,טYG~fUi://y_#6U市To{IX)V=4*9Iš=#u2_hh˜j鐙)ɽ	!'b喏؛@5dY[~;|J30i)gSڪxs[NnQ.Qu$u0V[%^{N1xE2.bz*KWeg켪n5GGs7yK{nBUt}bqprb<rrЉLvu0x\ 쫁<}q>ζdhC/cOm2?tCO:Mӊ'NٵRݜMa%3KXh&'=³:|>Iwfw~jͻȡ]LV'X&_LIy߽mM4a=Lش6zLOzG>!#S\?i{t:a
TǶ$bt8Tz@7p	vظG͝z&M>?Ӈ}CN8 -}'\Ֆil?tXlm+J,zi>%TgSio[Ypf94#O2iwMB-oIwljktyJ4&$J!}ߏoqWNx|.қ	f]S"9!L[UOCS'mVg/#;o)'Rf9&mǕ=Jl~ќSyB	9~ڇn){I'춙9aq6byCh]sJxBt9z/C'
>  0707010000001B000081B4000000000000000000000001600AC2BC0000B4BE000000000000000000000000000000000000002D00000000mgr-libmod/tests/data/sample-modules.yaml.gz        i("dLaxt!kXZ31Ϊ RF&@"+(X;pcX<[q\ᙷJj3?=[gtaU+YU}Q⇘GgW ^>ᇐyl*H};fxsK*jgZ^޾~oDAo<_/_g챍zl|r7~x۽|HC*oƏ_vq6RmD2Ct%tV젷{U/:Vخ0En]A.`QeՋh/*aK FU7:|?y獞/lWWl+h+zM? Ǜto'yy|
'P 2ֻ-kwc7|+zq4l3&QHCc(QQev/a=T=n'BRS|$.Qa
D*IhTǔhu)Q'^I3JZO9	ڧ<MCľ%QBHFeKD/m}uHQKkʀ8$Y4>ҁW%HHTh'>f\jHŰ}*4J1,d cJGHJNxH`vZ`c.dqY"*	U %#TT/$?wcfގV{[+kD"w$"XJ$	cH'~(v/);ܞ)Ab$Pbb!AI0I@0S:~dQc!+>c&a)?vl-6%#$pY(('t]CD\"JQIx$dMQds
@z@ A8N)x,6^x@p	]'HK  (Qq!fq\sH#)c-1I	)avG:uss*P+ŔQM%42ď(uQb!LtE.ghI(X|~(Lǔ>N@'2ۋPMz(q/$`c)@K@]6zc,]shfk!̷>ȫc;Mds*V̊Fgx,[Q|fY,Ah6GM'bq
|%bPfc7ʠtl{zmUvaqhfG̹DOG/ Vla(:EC CJ@@wMhv4O p<Ʀc:.ۀ$jN@gM'a<FTtK HgL4hN@V'!]8{_hMԬ(Yp;prJ g0H9'aJb!P>؞͍A(͔ثԉa=l`<J?ffufmJi{<}I[=$cۇC|(JC-X&ti~̍h<He lMv*;L fd
Ȧa0'3`ilW[iw>L3Q&A0-yLR-&:k a1vG%^0\DST,v+3$zjh<s¹PH$1(p9>mD3Ojq[|4!+	|,yG@1p>HƗPOAQ1Hr3P@O*O$tT1݈43wIZZ@\jГbJ:Yh@4yP6|1tAڂ
%26mxv{Ԇit}3~J'38ƣ8n|#-67q=·in20Z4u19ګyG̘qG~7^sAOR,:CTޒ/.zlGR fGOqtv~Q?K f%l^D,m2OnƐ)}*0?Ɵkh8|$wf\>ZM43a:S|(6~zL(+4u/{l["!̄P+gјyOWZY
wp={v8؞ZÞO.AeKGͥ`M$O,hHڏ7~/4.ɫ;W5mߞ>|mkWob?ˬQPR=z<}Xȗ\&~bbK.	J T۸/I_afkYF?J# '"$R`a<#]AM|Ff!Yw#Pc!y57RȌ]cywϒ<Y@btcM%Ib30ea:Pּn6
Ǐb/[/ۮw.Vf-Nygk`nͮpvATI=%^ޟ&Nw׿&+.Όg5Y 9LņO< ^PyNTL"w_,?Kco[;fJWO+amx,A7VY+aVa@>'@MGZ܀hdA 0X6|WTh1=`L훜{>hwUe3w/&4?n]Ie3FU>/oUWπZ~KW++yFM{;+{?cnHާ{T-0fkJ*ۨJch+spwkW*Ԝvv9jhĪRl?~0qd*9uuw2w48(`$ tC*PHQ8>AͣoyX"2~B!a1WurEkTMNPԑ8BD;Jy&|")DHu5gvv=FW׼Ĩ=ȉk+JFIfȿlRMX\(ϕ5]GJ;
=.Ds^cgOAFu%{zןl@.SJql~Lzn2dӀ.Z3"(=t"*#O_@S~CEr({axڐw-@12{Z9*CL$BLeOZѪAp0"TIIcY`$&\8cFXg(!"9ӡ3%UEQ"f3Dr:xTW;#m['5KIEDxeu@о@'LU8fګ\Ajbv")lx('O3IUo.dM	be) k=g}4@ڠ:̩ܯ{\JK7!e2%z*wSgs߽ {uЌjf~ei|=Y_)tRܤlbۊJ]_ѽI,Q|A5DPg(1bϐe TGq jh=$ڱF$$WB	QEyL$vf-tlX@gMbBj~<5I<N.i5;GRG3^FV&K=y4bAǜRΈǍ7"vo2L(=W֛cdƟG\sOۍqf38қMR_w7vg;v8Ƹ ;QlIR7lsOZdL+[z^nI2O+v8U~b_4u LsTXX[_)Hn9J~6O3_]MY[җ/L\4́oLL=@EKa-VB٢K`-nٗMU@-J?M.0)nZvٚ}VE>hQϛvD~V[
weX
"U>I3O;pt+Jw@gf/x7ۯor}p=wn?9?\4tcsNv3S׷{>zʍ3<p~Zmo8Pf2~7mkyYNbHJ[?sBW&Vp7mnlŖG<_zսq*|w܀jFYNWk$q8!F+?UL^"&z޹}m[伾ۋ0ԡO`DC&)Nk&&(T%Aq~߃LE1gۋ)&Q5B8"#L%*`iPR=@!L$$hXE<CD b,Н$NxJ;%	Qc%&2f1Aَ1FAs;JJ݅]*ƏcBAq%>`˔DoCw2"xȆIeT.}^ YVP>@ vN<]Ae򂉶ZNO]Yz|#;M}JO]zZ\uOsKHc|N:,?Cؼl~ǽEZh0a2ѦUq'su]gn&[*2B>,ިJHɲZFŧ`kTkP{,cvA2KՇvS>Д2u8%p?\To9/QtNMuͯ~+!vlt(0G.HBJ$`IAX"!
_k{da
wfB
"@58@:/8}4w<M0~}:^"0G18i:+%w+.a`ڤgnFw}lkE!'Q$}XD|,8DQ}[tY`vb1!Q-T# %*EV[%J,FS\nqior;2d2?xОV<3qVfIp9dc2ioKt1ќ!Peu~<ڍ1^ǬXYnoR.$%>ZL"bQ]v|p>&SRTlֻ܌X>ad~S}pPCl]CݗEt+c"Ts@^3iU\k{<H/h(S">ܣ;T~ޟ.nZ_+mtD)´qMHP"a÷'nPkF I~ɴn2DT#DD2X'$S¦PW-ioՁ'v-SGHaNcsU>z)K̪dRl4Z#:X!q>jFmBa.nϯd/#~n#S1oe LEP$".f2YG]ujqG#Qzbg;aߙ-܅oa뽑0ᓤ|!NA(m A۫yH>ŘRڸ5{Ua
;+4Zx\L	ūgj" [ZXgL5Ur΄қ =`bUB< hwm<OQ{&9~>3	<ga~a{G<_qk@X6;)q:Pqj%<[}/F^#̈́v?U}k38V5,P_~|W#U2v{y2GXggdEp~ڴ=swbZ64j{m zs͂UDfb\K[2k <mWc QY>ppBVưen/je.	ͼl>;y¬VjkUnMV6K{"r~z`=;OtFH!U1%S_1Q9(LD0󺍶aCjOۦio{{xBJwFE41Xr־	&AO!L>Wڨ+&u^9 HҊ7^\wuScI":}gD#Ec8"Ճ)gVgP3﹧i+d)39UT242H$PfPJ%(kd
|ufCuK$6ˀ/?5VQdC~C>LeSreﭩY]4+"|Z##iJ ?A!2ΝypWfJݫo6I&jPR(b_R¨}s_J
K]qD M^-`݄KcHڭt$S7!Ў֋K[;0ダiH4zJƞgN1~Don
6_
c?2E:t0GbqeO;!TsS|׫roMET{rk
*/@^Y»^Icb
 {$u~Q<6 6#V,Iiz52YDqE)h'FOpLN!f1⾲
)\[|NCTq$XcXf)*1=93P&.@ӁbFV\qX~<fEI{?Nh82'm7tG]p	8O#hLsOs`ҵߋ<e2{<,v	G8 b+}>慊Tl_2&wGT%]Opߞ2{/ErǇJalO?rֵ?sɤL,22[7y`0=30:9g5;~ߏMz{P}XρiNՏ*tuŤˀYjwaFy+7۽6;Կ}`vQfmQ|k/V\Pί9o3vZoaQ|ү^rz_29l*J0ϞgҜM7p 'aGH1LdDiHhTH:yoz6r_d2NmQfP^exFnH<AցR\:mnmm7:̪Tf:Xov~3;oc>ꨀ{U{xpE $U'Q0L	C(
ͻ,9$et{̜)/-ƤX}K6oZs0dqL*	Q(QI``z` sfWhŎZtRHNP>UpB|L5V}6q2Y/Vi}%ᇖDEhH	d3)WګjU<ex~]<^ɷǃ',*[fdiu>@zBbIn.0XʊKK@bqG#p`9%UٟPP}	#,RAP 4B)!7
䒳/4RS7OM^7eH؛i2r0F=U4V<*߷ofcX$le-,깘4/ yB,	ᾢ~c	M94S\*"P0I:go~Fw[`B(%	M"9[1(F:z S9!.c\_bF*Eg	T*,$`BFzWMWOypo^aaȷYb4OC-$`9a*Rb$AI掘)T|{/Mq,R=;qby59 F["OwS_C34-F]F/ƬXӅas7Iσɳ:ib1kBct@T?)xbh
*-Ô>Z(L!02?ŀj^x -P43}e;,;Ҏ
t1o'Lak	21\͗,2nP
,ztA?q3ߍAj~,E@n(tԪEH^?i~gPɴ칢[Ihp2P(A9]ǿβ00.<:륫\pj֚//kqU$ ]]ۦ'Bte5rG.^syY|{π$Z5W$;	$O$Xb_#mXk=g3E{?|8 ᓺq1L3Âu2xB5E0F:!лg#,oÍ|aAB89ۊ#<O'V]-'MYe13^ވg[&ءh{&"~EV̎yv%e<A76eMX)N3;0殲mwuD>te>9! IpI|75!_7p^˻a4H;/\X}9f1Wٻ7+y(^HgneLm#6jW ˽)+Nw+ƨ||#wei-G@9[t
8ojn̸kY Z}*u$i*:py×[~=l%Hr{k:*Uw8v%%v%vYTvLj x?S4̖E+&MEšOjX qzqAfm	1&SݧBO<zaFbT]/#o@ܲʊxץiuO
xLlJM_xVIZ"a!hԱ@#eh=-6?)YzZ&?T3੯BULksWgZTJR?
}JuފV(ėdC`( O߲}^N%<$1ƸƘD 	s?Sʰ[wV]KxM@qlFPR_&$4h(A,3n<݁yf(EbUKXJcp@s_*bX#F:	,*02=%i&YF&V kVBľ		$	CA(LDLsv]*ID$|nAy^Lܘ0/ =ٹ01@"0
ą$9:#2Csfᾬ2 !2.T85X%"B(p]MInUjy{ȝsLKN(K'QyUD|jNJG_5lkDre XnNi&0Us0	E2WVt?Ț5; J70y##	1M+x[ͧd/MEb-{nts)"+cZ$) }IC`T#ŐA(H&FvPPcY0gPg"H 	ƀ0ǑTihnb=55({M(^<k<6Ϲ_u#Ab)˨{>/]aF"F-H]O00JK7<HFAG`puvp#Y*'!qR; A~sAǥh\X@ڜ}adrSy8.Uk+<c](lr'MڃcFucYgDVU7X݋cPdDN$Ùsmx<r5IKH=e6.3#QekD.\fd#٪;NLOOTW/*`?evzUM0{IVoט}\/?ͬneezjmRee]}2Axфߙϫ|%p!n]hnެ<3Sfl+8xG37-^7y;mQqlͭnݢ|ekvL`m!^[F]jMd5oX7(۴x)ӕ{]nX޴Sa]XG֞Z! ̞\ZE8mYww e\+Yon:ղ;ݴY;h%t99uKki雅ݱ&^6>dbh\vɪR
3i8ql?'.^pu_߶83ŝ;=t8qqҷIw9C){qҷǉkG&v49I{GĵI&Mܛ'+V<MdBMFc2lO	ZQ*LB_xi/ԃkPǼļqsHrbC,Qs>{R04c
wJI:fÃ~,wPsOi]fU'fn~1T[)JRj#i{g6[oYe(a=5
pi
Ovo@ݾYWPͽ+xy]B~H-<e˼/ibT?06Ak`r+|)A2ib#7G0VsC8k/n;'HY`3QF@
N):@yPrGHdHºqk{YV=r?"ͤX{oL.^f2}Ԋq
aG![Z5+b+t
˳ҶA űBE#qk'aHOl.oK>+NM1{}u&Lc-$(8D1*bO|1T%\FI,~KC\S!U4d(~-OUpC>n;=O^ؗ<:]7~@3D}.9eRQ}WhH8aR1Oj$r;pK$Ͱ+cdDASb,da%Dr!$8HY*-0JJ4#"҄*!FoÂ|˼0g3iǷds4z#W$$HxcVF&8%3z]4WNfkeOSuOq*Ç-ҙOCh?%4EM1'9@X*tјȎllV*sN~Tޫv
RB}Zϭ XJIb2>iDpư_qhƄ(@6Oy<A]Zz:`6Q#KRSLcbĸKMTaHP%*>>T$GQ$B0	&BOS,q?}6'kSZZzɔa\D[QEyک81aǘ
1(ɈJ?LoXK?T,c-dCQ`'fS01 qq(ҡO$yaPb-9rT+z<^BUƦ?nmڹaXP
b`h))JBg]T A.+z^S^.6V!F.z"}y'D+WMeybe
xpWJثJ6o{"/F*``r(9BI1Q(Jhc4S{[ή63{m"ϛvX!ؗQ"Mt(tHz"$ol:q"ʸM#l@
H&&}}N&(L25tv,僖	~{ZP߿r#}s՚8G@p6=fTB2Q̏7(oTbIUã@p0DbAC0ʄkN}Ȋ4h<?)*\vvnfzR>y>Sr0J	
IZEdM|,x*߇X'k)jG&&BL'P&	)_VT˰\6'Yac[@I=>Lo):Hy(Ƙ$F #% 4+); Wi<&F%Z!DOUf3#0 G(J,Br@ QhF'Sj=?//Zܼo}Cװ1z"q!paYEHNe5T7J7/{gMlŵNаUcni0zum$B:=P_k)8@cQ,bt:ߢeήUl<n'y#0i+PmE,XPIX +A|E/0\T,]hz}ZtURS;Pxvs{AP[A%"-|sGIO>H+s91%k)G@Orh$5y~\=ݲCtXW	SE F@7GʵAd="@alRD?܃%@2N=.X׹Qo!nra_lC,R4Aqu£X 6H0B%,R0!%AXE\O֘
9C}($st3|O%_0긱|]o7Á*
Z 1lBfʄ&"8~Uo&8<}	2Ё`I`LbapFLh>Qs"j_bko)	>f "R 6yE\DT;;MPBqSrݍf/0%<45#R 39&*hIa
EA8`vDE@ zrsGI`XWI)ZoQtSPcLHT)X*`c`M $@Z>h(IbȬbqF-3wJ0{Q~죈cP?j`r6urT/vԀwMˣyw/+43ֽLVs Jx:`ͥ}'k9Iy!xi#H:p<ҡ}*eNֳr©#}ݣ<^zWUWqO>/ZFq7Y!zM֜hiK3|tМs2⺐vc`z/}btv<\*"8_C)ڸxJ^"a >l]rY<}C۳-K<9$bH\g1]{JYaH'A#M}K"8-T0a{[P4>I)<h\س]5s׏5Lr<Lrbߞ(pqEsw>Ž]>DJgW)n*J.EVTLReគH	7sF@CRc< p"`8ǗƮ-~>hFr~ȹj@g߅XܼD.5$+gr&7t7>twqt>Dm6\5х{Ɔ=8=]<S֥͔u?y8>rof!c
'=줾g,-C5ٟfҪar{_7
݋:1]Iƚv8ea[l*gcbFcrg[N4η.\XnN3/:u]Z]- 8S]F#wfdj{L~faN
?u[r׿ݫo6غ E>z"п?9m*stO/H7ḷ_OM<jFTh,}"ĳ];ӊp*&()buKנ`_ڶjL:|`ݙۺm2BO.oE 	B7i+	n^|Ifg'[}zWXijtC}ꤪ?>A	JĀr?X
a.1SSQ0wH{)MGdqqRCAbm>3a+WS͊:X)?ٜbV;:iz|28(g ҋ03OLDRXQ)a6l_>SD2XSw$6_)*4	|Z8Dn-\>#:XfX&}q4N%GcK4OSWNC0O*uy2T9EU&O05<ŬLfTǣ(NW)HNce%yzw6u%51n	)vYÀ8s'x	Oj+.{y#񯷠%j?QR~|ļHRW8Ǘ_Kw`NU}8UyŅӐ]RS(ksAVgQqQ{4ʼ!S :_mlsNo݆Yc,92>*?Mh_&ڛ`=evEcYxm7c{#NY2jnȚr5\,_يmMz.kZ7V_3PLI_$PV ~Jd2?vķǍ0[ų
"$Θ>;׻Ճ 
]&P
h[m{(w=wn?9?=݂)I']_>¶zf]q]Oa6l.s7mkyUi]+s3ܬw}5d۹3{e7*g;3>]$=lue^WeI͎D$A$ )*su:7)/.!ܤ8U"<
>	5A)M#ا,	Lk\1c>w}xڸ(7jaLC&}A}x ".G[oy~{]ɑ劆4y
Q j'Q(D)cEI&eDT!FY,iv02fJ֓tƦ|߃7xա: W&~Ͷvd!<%&b:1v [Ӱz}]EudL[6};pYYaLT,e)b޻Z2sT_p®JVf۳&1CN7#b 959j!	^W9K3|FD0"&YV(	c&ܣi#/D\hOz(#DsbcJz*c縏s ;·qe^+z3L*~y#NC
ALC2QDZFWԮޝKC8!%QhI,N"	+ɤ>D=TnF%TZZi`A#0ql'b(9%bh\v07#,GE '5$A!q#"aϐX{4:j٣p`NEݻC!HDP$Id<E=q
َ\zO}÷Kj
-$%'\1AY69@ɚv'Rj4=nuVgeVS}C7LbXi?N
j_0Y<k1Fvj3F'rā cu΃ּ6WWJyJ\Պ}Nv۩[- T|ǉd%$b0QXSKel_ɻqaQY5̶&,fhAR`cD%d	2Flr*rӽ f5<(	'rP	3"`J*
bG49`k&~x쀘G݂Ĥ	ba9
8O0yAGaô	I%M>Q("B/Hأ,V8b;߻ F!'%!ǚ%!0Qѡ/=k4'N{9EN+Obә^l:HL,{1/-_cB|lrؓcT/dUUh@IqPB0$TaȨG>V_->qKZ8
OtFKXeXuߴ+WFǓS-^7RkcD*
QMY_KLm:[_qv~	وEe"Pc|6ѾH}aR-iTnU$)X`+	?&h2/wE>мdTxIcZy0}?24gۭ;{!wVL^(0y	J,fļ(FI:M%,LdG>R>PEQy܌'asύֺYh?r76],DE?BPn԰A*
j群Rǁ|wؙQ uB}ڼ:)¹;3Ťllfm|7tHّpZG~\J\oy2SpxD!qcio$Y'K	u< Wj8+vI2\!fF#^	6G:Y.r,g	4v=4`́<ӵ6x^d`U?oa<8j<݃3#iaonYze9Q/bã8Oc92:3GPۍjkr𞦧]ޛܟѺ
?dlw;Rm48&ᄱ!٩nf؝>tGhc+(s.·+q]Df9qcP<Sp.!5_gGyFKώX1vZ=X|F0hPv3Fm *#]]c"e8Z˹F}?甙E]-|wW$ZoID3zgc`kv$)"aE5C?  6,')pM?l.6{M%v<q0`-+)`TO HA5zpA<\Y=FGa(`"#?\a,M<L<p1aSZ:ā r'HjP_ɩ)ʈ]TFcqPJP "v7eyCbe.N0VmvZ8z0" 04ƭ^@B2{BkiΏ!k0'G169}4 2qUvE"Yb*(H:θ"ySbJ։"A3f8KQ\QqnǞ?__)$SicI(f
klz7_y~}Q>ab$G)Oa;$&NNPAvZg4)a$%c2f<fQP!v_M{خ;M{F)HH0Pp
BPP<v(T11/io|lp<Cme!s7gAriK:]ˤJxܙ{	l< ?GH8nI]<E<AS43xŉA7b +
ђ2;]MGu5IѫFt3G"=J%b(8>C֔fCRj@/Q9颿BiTgǭDiWC6uڅQ$DCSvW.Q:BauxV>P[֪R><ηX߶~H֍&Q氚a5
ym"Hwc@N}@m`4Mrg&]Ν;[vՕs&C>hN__{M1:q8/ (
PI2Xp2odnnlcci`  }bg$I	dڵ`-hLqȅL\$	Nu |vQWGw:ӭ&(NH(
cQJuv;׵=ֻ~{(VDPF	r8674YLb+#ؠhrc]7tjZ9`ӻ<)X$Eqz:|XEl<kv](< ǦNo͉ГM)۟A@F(`JJ%'O	Po>P7Nnf\07|ـNn?Fe;?v2rd
Jp2tJ6D	>bt
v6)Tt$]@&_]}1Vv4hGKUzLFbύ4P$rƛ&dL5pq[849Tt앹<z2fjdaSXx	sߍH*F[ty?ZwZ{qE4℞VLFLm$T`ӹeWj.w2t*-WG7͖)W5t>q*>ej력eR
{X[oAXFm>TpfVoy?
@:0lXIUzQ>xʹYVۛRQy3Q&)VC2owWu_M7bu-0.Ѿns`_x0bW2*dTYfT<<=?"|=<1OՁg\b5k񖷩ΥZ1O 0C}<jtr%`DDIR02aeBfZ?6vvq	3A3X83~cE6|H;>'%"$`KIǗz]c2,#OZ:5o	A9-2w-8aKm;|٧,Ēg2 &cYq,㗂ݏV~JV1 SBPE{77`r|s!K_CysHD:ʏQI۴zfRz?NDC66
dNRQ/b"QEa~-!oLDX"f"$&rHh&EeHy&Bj"ϭc1	s|m_J}77rۭ
[żPYH=}ؿK.c1VƮYP0~ni6Sc&14
12Kf>`"'@piE!тeFǔ+ Lǌ{8'[)%OC˘cyc}e5f`+`{Uv~L{eT~ՋUr7`e.3'|LyoJQ)%ҡ^CS6za>ZXc$2
H+h{:Iqz)<@)&O}ɿD&Oɓ+yRPyRM' @L'C#/2?@mְRG0gJD) v%#_wvҍ*s5i =]Kqt	kii T{bI
׮|TMmKsRvb]V̯c|f[OUWӤAVR"ILUn@xzZJ	v\sVH9oyuj&y+o)B`pV1ħ}řSARDjsH|ABIdEs1N-q$R#?$fDPHD!0HQ/Qo9RG㈐$t hDMFUBxJD o"w%"j o"ꛈ+zOQ*+Qt5 "l'zSX.灎H6;v8u߹ܫgϮnraU$VT<3e+0+?oOcAڷK97%kam|ɻצ}Y>WC qbyQb\ĳnk#5Q8@!cDXݕ"
s?HEO]
LWͻTrL*D'co,x0{jۿ+*ЉB<6I]KG>=R>vܳco6p{4^''/j~`QQvJLyemjdquT-uY @3o^͸k-=jl8iw鼤-?=RMOՖ<-k]pm<7!>Pc03F$,D3gK,01db3G̫=U-o߉㿿#AwZgwY8٣-idÄ}`ZG':<,ƓXFn[W.>wZnqŲr{Pӛc|V4hLt./=1
mXR㺰U坻fTڏz՝97n]%kտHnrcw~ʫ翽^X?Km׼J)|,oa>USgg75I$WP8~?|ɦW0i&$qsMK	(I"F8X8Q7ĚyZyI>LИrCb܏K懊	R]٭I;G>&JaX&*#5( Rc3H:ʷ6,a$0B4NL|P9EEq]	+cqtZB02aSD1%Mw}- y6??̏a
FG(&!C"A(%wVD0d>XQX92Ʉ'cȼOom0a6V>A
(t$SwX+mBĎ<-#91OGtybiXؠT"Č~/:'c1uftF"ÞQy<!#MH2~?6,WXlo6Vo67"ocP#c9ƪL2>bgcb()62icc0I6BF"bcլ*=T\mA _ ի=pTyMXmMvPTbeޞp{!7YM&OLI0|ʍ+3l22HTaP>Ѡ4pgLV0 \C+l܎:p[ 5Y|-25BW[BCښ*Ƥ47gA:$o6H	VN@KZXԬԆcrϖ;ִΠ ۫CXzSbV,.4y^-[v[ȜR`<@}Ux06UKsbCHîM?5jY__jÏ7mqn.w+]%|o$M;et{*͏eam"H"O(o\]]s+[zVp伅*e[x*p^^<y-]n7FWÎlҪ}aOɂ~0:՜޾]?'e&-ۤ5;h5]wt9]CZZK6U|ßa;,l7}W^j:,^_˵l]e_~5_/ziQn3C/Xq>oc/қכCOfte+u̸FZoߚ*vޤ͕`)6HmSE`4\0Wisf,75mr-ONa|Nª
t@\meDs2va:W2;L ݅cJI;=bxrFCR(WpWׯ_nW}Kk5ד=77l˻~o6G&h=_-bnK0l%]kΡ-Sz*Mj	(xO?W"VǎLE<8v2R3W'5:H3oSnk%/UKH^5;eG4rաԜ7ĺ-4X:)l3t8!Fͺ?Ѻ]!ׯZl_^L/d˸P/k<_KߙiOoޕ^FŽ|Nm%].7qka.rШ0Ao扆]uKDQiC{7:8\?0ſmk]ȭDٸ+gѭiٚsw6xVQbe%u92IfHm3y=8&Əw
c`(85\o@s]724@ms?N^Y:F3ߤvêsUgv_@0IY|M'wo :,a))b~jmL?tuYbeq<]1mj'|~FT"ݻނv+2vS/#p%0~xn&PZVkJ\>ԤpYӱ{XKST3I(353,nvu\O43)&CEJ[(m"wʍq;^xkFFH=u$#+ZKEY?R-3Za*/l$g11"p=@FsxNu+JY9T`qő'sR)QȻ^3T	"H+	=+OD@(DP,
kb1AVpN_)cК)("9.L9Pil0
CqF:$=T)YRdу3+4HL0f2nH7q 81@,8tp|&^	dv`PXV8H˹U6.0;2HpTa;b;GɟK*Q8rCaiAZ987֎]`Z=CPh.D"-A̭N3rWsx^A;U	`i!H
8(q:<|SRŝ02D4p̝.13:	Şa1M( ?2R@<pm`Lhoub`qB
*G$VaX#rG1Tr*(1색i2Fd"OtD(9%L``ZKҍ+*ubBXc#E!`"hGbں)q%j)T(?"AhE?Im nXF^W0)3XP1No1Wst`=V%TQ5F{5fD H4jJ1"00A')ohv
"29iL(¸=XsgKaZ/,kҜnACrmLム"b<QPEFgYgnb	\̖r@FrWF2̢(k.r* cid5n7)k	jz4=41`Հ^@@6Vaqk`z,7xa@ZDr580>lAؖ(X)AV^W-li@}%0Db4rqI6؆Nlܚ:Ƅqj4
>G.NOawԁ)Ѐr }+.8)wPnW*@ڲcFw$^	U%';= K9V6:$H1?y'NW! D:X3)KcT7ыEqQ(e̂,2"Pi0G?\a+@Gq+7aGa.i¸ͱ7MN{p5u( (q4SI9I8H	jǡ&*7Vy"`0q'N&zeSw=<5?!@s܈ jҠ-aI#SiGHqSU.VU=	2
@RZ@eƊ1qcۻC`iA<l(PEX,h'Qb8aZ11\
@.xR1c3VN1^"V
\Aaȸp\$܌9HV6$U"LHh2Kr@q+K騁AyZO@h֎c$m'b-2qsw  9Xrh͉c14*`(͎Rvu&Hmp+?.Rr
ׂP`4P̠eM	\ <8>,((0*|J"*W
qx}Oˉ(O$UƤD5@=Emǜsl*Y@&t}Z*R$hr-`-A5!yl 1h:_y8ՂJT^Í @TZXp2,
X0'0cp8}\GT5R!"
Qp4h$8Oˍ\(#A(@0[W*WY$x+v|eRR Mw[]Ԋqw&d$`'V+cc!TFsȸtq>;[VP"p4(͜W<z4<ݣ|Ah$\$ZzxܪOA]1y"ICb,F`hP~S"K|=&Kg9u\?;9\H ȉ	22dZ Tyr|.fOFƜjcs(<$\ZҚ36X}#)LC1t@YQpHcJ&	AAC([ R94hʥ R/RNV*5r˞P	ƁKS~D@Pz@e16+;X>n{-*Ӡ:^`Jy|`>(r-hK8 FAUF!XbkY
 j@afgtU칂(Fg,E #gG[#1TUPPfvX>~C@qص߆`6'$rpLqN)b4
81t~sA߀20J
8At8@!0q;Aö",t,p4ro;C=9h4;V}7YΣ^xzE,1SOnA8؎,WYuVB0q V2RK	3g<
MpUY- V\8&Lq`+u' ǵQ+`]mZs >_& +BNȢHV
G3FWIjx X+ 
{ OGs<k r'AbkXira@u<ø=	gD
(ȪRԲJoFN};q-<z[ZqCV<kZ2T^P%V&h !D0B( ^!Lٺ RLYdд52krFz*HMDH8-O?0Ƶb9D5F0 A2b(I UHkgGO{,Xf.6P14BDӢbyoG<
n2EHm5hY{ 0@q$CP=қP.qFT.UrSy$cgFAsKӌR@iAыQ]Z5Xo<D,(g,(0@H*}L1{5R^J"a	H!'%(:)HG:ypN,:,+؃ڂ^ Zpq
B5D+pM#G`2["CSȭX-/ڀ*@@flծO)Xe^Lh 
;2EڠH1aK!aLX""v3rzL npz\xI4!`!FMQVE6%p8R͙SnSD0y6AJIH^!ma*ƭ>t)rD@\>FA
H' /Z&h웘ͩ58zi)nJD]вK`2ن9ķCF @n(P{B=CW%CZ%Mzn]1i$,_u]|\.M{3vVc"RcP$)(!4"@M}F@҉idi*Iu^oZdmQ
v~,C	Vv2
M5sc'gz(נ3AV*DT(e[0NfIHdhŊڞ߼:dcz/"yew
`-;\\C!'+&oLcj^(/sJ+17:/;e̒A4e8?r5-Z tb8V0/W6v֑薵HО)@|:EMRՒszޓBqG]=ooTZ_85Ӏj&f	Y840PCA|W/>׷=]Xefʍ% 70B8E4bCd:-7֋X]{'Y(IDe4^Toore!PﰚOipBE)4XZ;MYt2cNڔpC)SRs^
o9kpϗ!#j]SR9;a|RtS@rhlK5ťԧyxu$Kwѵ-Y'?R}D9(Q%QiK 2m3Z8C楚=gZ=ǠI?Ur:9 α?]Jç&BsGEkh5Z:S,^֧o75q' cAun;;fmt2MF4P9-p};S2RJfAQ8L(yfe)H+TKu|H6?u~CF&8V+uƸ]s}JZAL],S^?9=H?5TX*[ Ask=smNr9J3| ٨A
EDlR$WPRn*i+9rxz|H\d6N
]NYBBUs\B:Q;eWl@hDh:bNJ,!N:4\,c-46@WԜ VK-O!NMDCNpӋY,@AadhR%9p(A"H<R%(e˯vad[tp02HTizC-A!KR0(pY9~eFa@I9#bCːd͕v3	*I.in	\3R7mZm*AaRjothpI-.l=3`yRq! t~ך[E8;)lj/(nY#k
`-pdn ݠs2mnumD;[/٘ Do("HrrH+5[}6@%!;uӪռίn,{7NCR]1V&Z8E߬88E,@	ϰ#1l
`-c`pR7QC"K!7cϚzP8qG O?PҀk[LIC@9^kxHw()3sJ'6!ۤKQlm NfN@=SN4O疛7a.p&N<8m(p(u>F/hOmTd1;yW\!-xJc*j(p2:^-;4vk8vOͧ8·#A9	v3ڟ⥨s~X)i}2?A&BbHֆ(UzڟtOug_RpPҴ1{$%{8:YaV]3 ³ht%idrMP[W)e]t+9l849-vssb>pkofu{brF^8f2~oẁïCR"\%ͩ

YK0<}3{Ww1{7ofKyGL~?8)!*I+a40g6 vӻ|뭇&+(-{,6~fwOuwlnY^ F1'v=F]쬃ClجoSkի&?guy f=Xw޽yq=5Ysѽ~۷zLnIO0!w/>/t
>e9F:Q~'3үWwOd^3`7uC؏xݶv$f$VR?-`?T,fo.y\|Oarݮ[R1=o<ts_؇% M"~^^Č@a׷#&LS\\״>NKQLJK{􌺊9fULLL6z&d52AՋՁ`4]y(X1,PŚ4`@Y;#%rDpi1b*>_5nѐp{z_O3ZѯOZ`!"x)Z+ `J`cQ/H1ɨ@qQzX'=@_lW/n n}$-]LMuYآ2v>=c]Q˝"-r_֏K`&zL«D[PCk7K)S"^oaaӔ%2w;!n6~ 7bwՓv
hX*lf9Kq֡3}mS|,SN)X'+׏zϿMna[H L[;˔P
'kcD^q}ߛCOiӒƳ8\Zدl|'5~89STaie(PN*	Ɏ`g6SVxr>Fi(5#0,KJGހE1ʎ_O?ށHSǻkv~7.j~]u?Ry\VDprWEyij}灍w1uήſ4<4G>3^pD,ƌb06$Յc
*rW5h\7L}-b2P(LW;,l{TY;wRM.$-[8㸋!
`E:bMswhyY{NU{u[ǺMR{-f;nluclNոvyQ]چguۚ}Oa]
Dۖ*ɊF+F+ȟVQT{=p{6\-PtmbTѽ(l
V~e4F gcmqw}󳚛:	/kٽ(>W"`B3ŃFk^֥ڈatbq0>v,?LR鯄kcJMTuhrbfHav߼~]Л@_o%(D?w|=iynyppb-rv8XOЖ,J:NZ 2ֲCΆV߀~3fEa_\6fs.`ud
9-gTKl,b~aa>:]j뽡~֌.+~jê!b@ANhmcZ4Ȁh+eXߜcGZ[sm ibWmǋw{݁!1|P^YqBXkgְo0Hc3K{A[]p7iGOL3$`׶HoCZ{_țǴD @/i>笙kf	ܖ>^TL=̾x #|_ޏ6(-G2Y֯yke'oФ휼9H?>~K+&y7׋\z/JD!gxh,;.JZ;/WLs@DKn՚0

i@&bi`)'g$T./	ԶItѥ	FQqܘăC?Y4	jiMc#LKM 1!/˖l#o.$UۧeodR\sP"7kDf񛈻ѠbMi} A͎b̓B4>4s]:lj]pGfg*rm/,lUìg @;7~L^?ᯗv4?[P[b-Z[m7-ʀݤJ6>K5}(EA\ƄFpX.ƻ;wr"a5KC5k؅䎐ξhIZkmcLk#e.峣!9?.vY3ZBǡOqfmT%Dx-B2`#S4Ors>0_L-3N2$4(]E1$#n5*Psj(dCnNjg\
S,<k)*J"Cϸ5>K}U^-6;8a	,NX-A%gY=nKgY0j6ՍjiE:Ǟ\J2J}R,I5BqLҏίwƁK}?e>MALwdx+ב'lۧq'EMG ]hLXҕ~}g[j&	Bmo1Y\ ]zZWiW 4]dy3ݺq)n`uO~z)A÷K}0ݘݣu9WX_A}*U ^Y|Z+'׷?8\uqTA8C)q`b8Zcs@$ϋE֓^>1k,<j<ğʱ^9+$	jEtS	SO޽d@.iIL*/XШCFv]o07FK[n$qEa/-5V)kp~c7ݶ/;f.NfLw\޿yÎvk5,'"Y/{R"Dt$?<8@Ac.zs;#$ʙYmn""F@ވkZ˗/7M1tz[>=|^x%]>~zB|<[|!G6fM(b-Ɣ&st4뢆'm6r zDTcU!6A5H@P @	_T.zWGhS@X"&us7X,EWZZ7]M/(o~tlA㨻9~mM%_i2p#3!=&JlQ/On;(|\~x_=@g^/V]HmGoݏN<ύfqOrqohz7OOh5n<'j^]^.1>b&io;3Y?Y/QOַə#8 =O{]-ڡN[Y^Q?"On~j?:z]9%gz?	y-N˅9<c2kmF?|^EA7W>uEw|M$fN}\-N(sGi^ߏm%\~Qf`g|>ܬ̲(7G'N=.r̷>6R| 32NUp(z݇[ԶϘNf$yJ,ww}s|d:o׫'p~ZZ]N槛!q]un.NΗfNP{q=<vsZ_7E.|	np{vz#'[ΰӓ[V v9ĭ;Gv0<i;@|݆Mz~2Eo׏zkޗd+~\'6)WNοOC}yӭk=muhyL63&']ϼnOWw=E/}WG)=k.|_ُ=ϣg_1AK{0)6lwAc˾|GەC~޾iaRKDϚ~1V-͋:B&"2ϴ*CFjI%*bɼ[psݢdd=cpΜM0F2:P'L#l>YtcjPhBkýRZrAN0BYc2VkoE>qA.Ӆz^dPY[ȺI')żmQ9إlܪ^֤NIRd^
Uȡ)/ikѿ6sDIM*KRHUCMMd`Eu8GcR*8x@YhtS'ԻAxJti3=QqhH4xܞy?<V2
PbRWq-)p0xM|x#Y<CȞWĊvS`5< @0E*RaL	FQ`rSoڂ6bIi 2I] i'k*MċzJlT:Q	[i*9QPwiĨrLd Qkr 1Nǂ&iVXa>HB+f7#$]WI
DK])Rx}+#B>%Mm!K#,r"J୨j24L{vT2a9'HzWVfS7EOH*c*GL4k8 %<0bEy1}jfk'E';Í6~$*x NAOeE{A)b:P䵒 QyZ6<Gs>?[x`:S㡒#X*cq̆W0<h)1[8$."ćsfRA,E*@=ETKX,cb!PvP+{אr%@A0LG9SZ=LTPH.*!>y0~DwLcT?=צU7S/	hw$!C(qX
dB9LfAIӌF2[9PTcFr	/+'y[D1tv^@y&[#X4FR>m	Vm$&R2$^J ~ 2B@U"ujNp!)r!cuo2iaSW׶T4he<!2׬Tr0z@RLūJ/"T[5 "PŲ(kqH?\J7?1)BfxD҅yg
\jjRv]Y΋>
F/1݈HB=WCyO׺5Ɵ}Cࣂ/ixnHWu\vUdq/`#Fq X:Qzi:E.io%OkCccq^y u}?XkLv^G_kGZȕVa+(ɛH\-rVvC;<xͦmPK=ZǕ
%l̍.x1x()vtJGj`(?ȎIbד`NP=zYʛF'gF ġH{TF^s|=,oުt#9P~U@)s4N5$(G_	67{
LQ9!x:;^#z.]޼]\k4PW4UMOʀA@%PoEWc٣i+g6iVI=.U"yo-s&ټ?2I]K蚀^ꄮ	lORz]M욂k_ǩPLQ0ܗ*&m[lGLڔ}ipuEi\p6Ky!XOLp=NWPև3b'S~>%FQ˧hhI2"&Qÿ!>&>))PU^0)
Dc?J{j/ K==>It0zt^:̱xۡrw0i-T\p8![rUoxY`?ԋFa**\.^j8q9,C|#V[c#<ǉR6azW[$צ>3YT몠QǔՐcI[aԻ0*/<B3ǫ̞X-+s#EvƐǇ)@r& ^qpb1iL3;-pWv&F4sKh3%i`&X=1iF|0afT", 륷xoSo1͞}ܦ,d|l~:ؠ)Ţ`Ӭj =5&k7JF@n'=:R?^?1ʛKRj(}zp=V:wR$7B+2:Z3p2`aWXjB$hɇsxCTX^"ƕuƒv'n&;$0Cre)00Eܗ61"5J"-֟'ңm_O"{mk=r|!Vm犯B
hOtH]9-w~֟NXZù=⒥BMʾy]Z4;Q(X1,A,Ml9	ha/l|i:+68~VG&޳%pYWVCie0*8g0*owP̫V1O$ZE>[u'D{q9޽7@̯r^ıR		6NXˌ o/fܞJKLJUj*	A1!.(ɄΟ}:<{Tci%"zKȿdU1J^a=w]qŬH]6Kf5ܞ]Pe*"*f
s,If$YY@{(b7K$pW@([UY#b"	}
[X#,5R7"yP'/)2Tjo"V-ouDtxu pma&8@bQWm3=7密t|}Ӿ~. \Z@D!<؉Q ,Ǥm*6EzDrf׉U0 jٻfT*M4@/Py<pƹ҄ŭJ^*g+`|u>~;OF9E 28wGa7=#u[2eshw^4_ݨs6ls0-l.Ǡ@/'?`_^ݪ;ntC4}é 9,¶}=_!P2جm;Զe(pP~Tִ߱8K0x}2PQwV { Z.h7>!Em;x-X26xunpԾQqfMb0cnbEANA]]ꛅ
/
s<]~o+Ǧxw}p3 KN?\y:z{^2PexhO/T3K#:N۲TYg{^zj;=4f5xFGGlQNGZV;AqZây(%]C_w^t[9J`Cq8@SLH9(; `yJmzKfGr\Z%iX=1֩=v6̾l].<ca.zY&8N\}(%H=p|oM֓=1l7)&k"D$35hsbi1S*G,(CJ,%YSG,)ɠi124m$_>m~hEtȅ AyW@,X	,~,v~#3mo_,ߋr7_~KojP7pON=o|(򬾼5 6<Erɕ)_1gH:3`)nNCw0D5~['sLς׻Gb=.\ÿzpkH0$oB]ԘiV]'N:H)2t;c"3KB<o_𢫽jwꩺw7Nw?OUwoȕ
S^or	zZtzFjeυ,ϓPLzdkAEHE#YC=r
c*p1d
RBt,fK;pͫ͌|He\
:
+9ENqLFȇr6K9n)*-;*ʡq[3p0nA_&0nb[6<r*Y-hT!wߒ)欢'a 	yA鷿qk%,o6)uj,{dCAD Ih}^> X\p3@˧&ASx}3mwXpG]Z=	^?"cכ_L[hMsY/k}0=<^CBaIګBe=yQ~ܭ@k٥ռnNgy]m!&h}q(nW02n =~#4|B_6?~<RFR]S3%b>-a!~TIQ
MxxIh$ԛ$Qh̏Sƻb?$3knw|~zhN`|xXÊ=}}@4r oa,֯^lI;$Eu3KiahҩAX&Smzumss|p(u"`z\t=/?07Ofahٝ3gs}ߙtf5]d[+pt  B"mk:vكfaV32&X-z=y4m﻿!.O.'+տ,>72v-}dEIl]WJ1-.pbcH@*jPvWTj&fDۍz9^n#t@G׷O!xO*K+2Ue*&%:kp&lg.Ţ1,+W"	@#	%VL
	~sJQ&{o-.8i*uP=טIVǪߓ~77ƞ7Fyiӆ9L(0Fp͍)5rT5Ȏ_wu"hg<,zUޘ#_gJY,a	Z`.T1#x0r5}k7;|?5f]2#HQIgIB;ׂȳww88@v\VAA;N]PjcmI3<0P$kO GWiv\R3(aH/R"ݵbCAX9V<g[{X,424z_޼0Vo\zM۽^ha0L;p;Kcr#*MKjW3ӈ/WȮ(g_״k9ޯҹqʉEG5$cݜCӵ!)#eԸ^Yl k\l5Ծ3Hb zm;z"EGc{{oVf>XO)v9I#c<KN?/N%Q֬y8|?\s&΅6>f^p,gJPW覹˪o|IJѰ˿w|NɶZ<J0a`,P<ј͍4WL
z(G$p)iJ2Z
Xü8;Cc/	=8?̆%fCDGL*fTTbmBԕ9O/o;7v>zoQn/Ya!KbAɊ"f|QcMIp=ʠb*YX":@h R *`4iFLkíc`ι6JͭATPN*?X;;X;Oo78V=.KcANkP󎽱}*X.2]Uf~EMv6ϛYd{n"2)q;N~:hg&~ip.7pb;'#QGt$&q{rIEPo0ݳi_W#_B';'vjSE\lå\h|9 Ћ@lA7Yϵ/LoR+n~֭/ӲC92iqj<c;^+j]?Ʊ`(u
M78/yV"PATRɷ@SƾRaBV}X|5!,l$5$"&MIC=7Yintt^E q6hE/39<nVjq'DtR_L5HgB+THɳJu#$(fэg5G5ZqHAGH@/8IS.;2h,-Dǂ<XXUY.H9rA :ґj(z#aa@j #pXl-i&#zMT]/eO]ms9 Pc~8gǁpԦ$5C 	`1mSC`vUv|oei]"<% f#f=Yef츢])rUJr߅_;˲ >}4T7Kbk~sBY%%0K2Fsryזq`z#1WC8{[ïr*%)&w OZM/Y,9_: ! v+Xݖui%M&w侦bkǴS9tXu9s1㘕Վ{7?}77xqY{N}ݵu\ SbzVWtۘlJR/I"A1V]s}cw7R?⫵v"<zժ{?`Kj?ehmQe+}}f|2Vs.7',Ϡda_Q7~^,'Q6 ,,Ue%j{\Zk]lOkU^yX2p`̅3MtrݧHWAq"Á"jv0VGOV/6ywMn&}'zݑP
LDkWKu@0i=^|, `9oc~ziLEI[)huRvS	mƌ2H$#֭IL0/Ƹ8d Fui_֯FB`Fiٓ@ڛGHuq@ :VL7ׯiA\d%G i/P05`7xV|F>VE=w9|zJi 0PvmKۣZ2\ow&ṕԝ;xWaqIoOЗ)76nFPNAaU}x}a\_Y/V:v>@),Xhb^j{d3y	YgfєfknWS~mti\"B3S&y2M(a{Ḏܙ&ck8u4y'ݬ$na洿@kUi J[}7 |9~73"+>ꠌo^._ݗ:W̬ۯkp}Hq}aCX>orޣן"#?b<TTW @js4%,VzZ)9o6{Tpؙ!Ø!PWN'XPv_??f%l0=l'|Ud4StѤ o	!0kz~p!6K͚ :_ttk{Ӧ<mFl=%7NRz̵ǻbϟ?Q߽ɼi*]2h?(<7	UWXRGzrM\Қc+20J%7Hv~F9Ȕ 2(I!)@L5hS($0()@Lρ|Nh*6uI §f 
=Ӛ
dx}S+1$M7J;8oξj[_7oT)o"2Ur9^rSia-;p~[i]n)ksŅ-LףI	j^Mu˞;·7:ٍwǍ.yhlC5G dV)b^O߭ן:/Nwxv~ֲO>\.6Y*%vg3ܳv%O,w~:!E+?$Gg+5أ,":?]}Es&Pȥb>[!lDŉ dbbR g5rqȐ81y7E|M}ED+a#;/utP0>X"~(0Q(=&wI%RO(g*l+¼mWApy6qiƠ\)
5lc5L1<3Ժ_$c Q,4V )yb,JʸAAER'@\'@p)b!]QSK8Yv*ӚRDv(5QMkD*\*pZI԰)M2|^Q@o"H&@ڰt_d]pe._*N|;͠15Z-䈠bNRKк	jB;&­E镫9%<f w.Z;ًs%5<'*t54p˄`0PkK@*2K@,E~zúZ;&iz]QP	AzC5Ė`VOڑ`(=#u5@.CZ#bPEo689umv]u>S=Yq`kQC NC<
#aج͌[汱g.=5
N/J];%vڋ\k\G\8g2@&<w٥	XN5b>nDŒ4f~6mHJ4,&``ጴBP%<FB_a B+kM~M@t@$PUiC1o`8
i+56cjA(`PSN)L+k
ZI	<f\\*M!ܚ,#é	bV
-cQ]*19B빉	p\QDOdLd	۠cCќ욠
ǈY*|UrDJʡ &1[J3V9X-41c^a	v5Aa		>ڠC	wQrMl'}~W蝨bn4KIvCx-񰦽b(\tp	t@<2õK`dk 	Vr+>f:j ;Lw<AW}`.7W׀+bX~5Qpbh9!Wz	^!w5tboWMzjUg|kA	zgX5ڭg.VX kSiݝckD:FWv_ŴIkh1y!=.9a}eQ狊ѯ1je5{km6cuo,G?<,M, _ېq4c<VO:.:x<w|oEkLWCw1[6.OC)<'tWWf]L# o^<&_a\.^:1Z?FҜ5+vRuo7ۤз-ߨXG&i趾j2g//W g>y;.7	m8\߲כÍ??o>zWmmZOOl#'~3^w`Z<1翾vՇfTnŢg{e@xOVowKU>s[㷟vO@Mv.aGi`B7pxW럳Ba~Ѯgn7;X˞Y:}l:#mJ}?_CxxMd߁E}Wޮ7Oُf}пw7>8vkmW˹}Bg?H=78zxbw~ůE@Y\QS?
3de_4^5?K 1MOovb\AwCl*u=xXKzA҆ZtP__Hug62ee:$qrozHXk(ƶ|Q-}d+3̤:L+uY*GO~kaVɭ?JU[	R;㜠)ǉi0=z3Bv^D7Ϫ.	4yG{nC8:Vj8hxU5{&7La*0cAFWỵr=!|`Cm-K/y*!ІZ_vy39f~膞uB5Oikߥ9&<ì%dOgzYzgu|ޒG8Hn:R3L'L~j>j)u{%߿}cg	3av1-<w{lM8G!燌LyRuΖ<9ۇ}+P
@,pop	G2&~CN8 -卹ujT߄wv2ڟox:,y] =vs|OID.Tg,RtՑrI&M9MgY-w.ωƄc[]٦G|'<_ݍt~n̈́vE|9B:2		EUO %adr"epw~2paƼ$~\&\Y='7i}Fpn(>PIhc-VV?ɘS攣gI?3(I   0707010000001C000081B4000000000000000000000001600AC2BC000000A5000000000000000000000000000000000000002D00000000mgr-libmod/tests/data/soft_dependencies.json  {
	"function": "module_packages",
	"paths": ["tests/data/sample-modules.yaml.gz"],
	"streams": [
		{
			"name": "perl-App-cpanminus",
			"stream": "1.7044"
		}
	]
}
   0707010000001D000081B4000000000000000000000001600AC2BC00001D8C000000000000000000000000000000000000002300000000mgr-libmod/tests/test_libmodapi.py    """
Unit test for LibmodProc class.
"""
from mgrlibmod.mllib import MLLibmodProc, MLLibmodAPI
from mgrlibmod.mlerrcode import MlConflictingStreams, MlModuleNotFound
import pytest
from unittest import mock
from unittest.mock import mock_open

try:
    import gi
    from gi.repository import Modulemd
except ImportError:
    gi = None

@pytest.mark.skipif(gi is None, reason="libmodulemd Python bindings is missing")
class TestLibmodProc:
    """

    """
    def setup_method(self):
        self.libmodproc = MLLibmodProc([])
        self.libmodapi = MLLibmodAPI(None)

    def teardown_method(self):
        del self.libmodproc

    def test_meta_compressed(self):
        """
        test_meta_compressed -- test if a file is compressed by Gzip.
        """
        data = b'\x1f\x8b'
        with mock.patch("mgrlibmod.mllib.open", mock_open(read_data=data), create=True):
            assert self.libmodproc._is_meta_compressed("dummy.gz")

    def test_module_packages(self):
        self.libmodapi.set_repodata(open("tests/data/module_packages-1.json", "r").read()).run()
        result = self.libmodapi._result['module_packages']

        # 'apis' and 'packages' fields should be filled
        assert ['perl-DBI'] == result['apis']
        assert result['packages']

        # Assert that the correct context is selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl-DBI')
        assert '1.641' == selected['stream']
        assert '75ec4169' == selected['context']

        # Assert that the correct dependency for perl selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl')
        assert '5.26' == selected['stream']

        # Explicitly specify the dependency for perl:5.26 (default)
        self.libmodapi.set_repodata(open("tests/data/module_packages-2.json", "r").read()).run()
        result = self.libmodapi._result['module_packages']

        # Assert that the correct context is selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl-DBI')
        assert '1.641' == selected['stream']
        assert '75ec4169' == selected['context']

        # Assert that the correct dependency for perl selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl')
        assert '5.26' == selected['stream']

        # Explicitly specify the dependency for perl:5.24
        self.libmodapi.set_repodata(open("tests/data/module_packages-3.json", "r").read()).run()
        result = self.libmodapi._result['module_packages']

        # Assert that the correct context is selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl-DBI')
        assert '1.641' == selected['stream']
        assert 'a7fbf8fd' == selected['context']

        # Assert that the correct dependency for perl selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl')
        assert '5.24' == selected['stream']

    def test_conflicting_streams(self):
        try:
            self.libmodapi.set_repodata(open("tests/data/conflicting_streams.json", "r").read()).run()
            pytest.fail("Must throw MlConflictingStreams exception")
        except MlConflictingStreams as e:
            expected = [
                {'name': 'perl', 'stream': '5.24'},
                {'name': 'perl', 'stream': '5.26'}
            ]

            assert expected == e.data['streams']

    def test_all_modules(self):
        self.libmodapi.set_repodata(open("tests/data/all_modules.json", "r").read()).run()
        result = self.libmodapi._result['module_packages']

        # Assert that all the modules are selected successfully
        assert 46 == len(result['selected'])

    def test_default_stream(self):
        self.libmodapi.set_repodata(open("tests/data/default_stream.json", "r").read()).run()
        result = self.libmodapi._result['module_packages']

        # Assert that the default stream is selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl')
        assert '5.26' == selected['stream']

    def test_perl_dependencies(self):
        self.libmodapi.set_repodata(open("tests/data/perl_dependencies.json", "r").read()).run()
        result = self.libmodapi._result['module_packages']

        selected = next(s for s in result['selected'] if s['name'] == 'perl')
        assert '5.26' == selected['stream']

        # Assert that the correct contexts are selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl-DBI')
        assert '75ec4169' == selected['context']
        selected = next(s for s in result['selected'] if s['name'] == 'perl-DBD-Pg')
        assert '6ce0b5f7' == selected['context']
        selected = next(s for s in result['selected'] if s['name'] == 'perl-DBD-MySQL')
        assert 'a50016cf' == selected['context']
        selected = next(s for s in result['selected'] if s['name'] == 'perl-App-cpanminus')
        assert '63feaccd' == selected['context']

    def test_not_found(self):
        try:
            self.libmodapi.set_repodata(open("tests/data/not_found.json", "r").read()).run()
            pytest.fail("Must throw MlModuleNotFound exception")
        except MlModuleNotFound as e:
            expected = [{'name': 'notfound', 'stream': 'mystream'}]
            assert expected == e.data['streams']

    def test_soft_dependencies(self):
        # Some modules have dependencies to other modules without specifying any stream name
        # For example, 'perl-App-cpanminus' depends on any stream of 'perl-YAML'
        self.libmodapi.set_repodata(open("tests/data/soft_dependencies.json", "r").read()).run()
        result = self.libmodapi._result['module_packages']

        # Assert that 3 modules are selected (perl, perl-YAML, perl-App-cpanminus)
        assert 3 == len(result['selected'])

        # Assert that the correct context is selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl-App-cpanminus')
        assert '1.7044' == selected['stream']
        assert '63feaccd' == selected['context']

        # Assert that the correct context for the soft dependency is selected
        selected = next(s for s in result['selected'] if s['name'] == 'perl-YAML')
        assert '1.24' == selected['stream']
        assert 'b9186a2a' == selected['context']

    def test_list_modules(self):
        self.libmodapi.set_repodata(open("tests/data/list_modules.json", "r").read()).run()
        result = self.libmodapi._result['list_modules']

        # Assert total number of modules
        assert 46 == len(result['modules'])

        # Assert that every entry has 'default' and 'streams' fields
        for key, value in result['modules'].items():
            assert 'default' in value
            assert 'streams' in value
            # Assert that there are no duplicates in stream names
            assert len(value['streams']) == len(set(value['streams']))

        # Assert that the streams are correctly returned for a module
        perl_module = result['modules']['perl']
        assert '5.26' == perl_module['default']
        assert not set(['5.24', '5.26']) ^ set(perl_module['streams'])

    def test_list_packages(self):
        self.libmodapi.set_repodata(open("tests/data/list_packages.json", "r").read()).run()
        result = self.libmodapi._result['list_packages']['packages']

        # Assert total number of packages
        assert 1742 == len(result)
        # Assert that no duplicates are reported
        assert len(result) == len(set(result))
07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!                                                                                                                                                                                                                                                                                        