From e55f05cd0af53a1937339545053959050280116e Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Fri, 9 Jun 2023 18:53:04 +0200
Subject: [PATCH] update project

---
 agent_based/inv_cisco_eox.py           |   2 +-
 agent_based/inv_cisco_psirt.py         |  52 +-
 agent_based/utils/inv_cisco_support.py |   4 +-
 bin/ciscoapi/cisco-bug.py              | 188 +++-----
 bin/ciscoapi/cisco-eox.py              | 208 +++-----
 bin/ciscoapi/cisco-psirt.py            | 150 ++----
 bin/ciscoapi/cisco-sn2info.py          | 157 +++---
 bin/ciscoapi/cisco_live_cycle_utils.py | 270 +++++++++++
 bin/ciscoapi/ciscoapi.py               | 638 +++++++++++--------------
 gui/views/inv_cisco_livecycle.py       | 307 ++++++++++++
 gui/wato/inv_cisco_bug.py              |  70 +++
 gui/wato/inv_cisco_contract.py         |  73 +++
 gui/wato/inv_cisco_eox.py              |  94 ++++
 gui/wato/inv_cisco_psirt.py            | 122 +++++
 inv_cisco_support-0.2.0-20230609.mkp   | Bin 0 -> 26029 bytes
 inv_cisco_support.mkp                  | Bin 26335 -> 26029 bytes
 packages/inv_cisco_support             |  30 +-
 17 files changed, 1516 insertions(+), 849 deletions(-)
 create mode 100755 bin/ciscoapi/cisco_live_cycle_utils.py
 create mode 100644 gui/views/inv_cisco_livecycle.py
 create mode 100644 gui/wato/inv_cisco_bug.py
 create mode 100644 gui/wato/inv_cisco_contract.py
 create mode 100644 gui/wato/inv_cisco_eox.py
 create mode 100644 gui/wato/inv_cisco_psirt.py
 create mode 100644 inv_cisco_support-0.2.0-20230609.mkp

diff --git a/agent_based/inv_cisco_eox.py b/agent_based/inv_cisco_eox.py
index 58bcccf..23ce74f 100644
--- a/agent_based/inv_cisco_eox.py
+++ b/agent_based/inv_cisco_eox.py
@@ -58,7 +58,7 @@ def _create_eox_record(eoxfile, optional_columns):
         with open(eoxfile) as f:
             try:
                 eoxrecord = json.load(f)
-            except ValueError as e:
+            except ValueError:
                 return {}
 
         modifytime = os.path.getmtime(eoxfile)
diff --git a/agent_based/inv_cisco_psirt.py b/agent_based/inv_cisco_psirt.py
index 6348315..f72a108 100644
--- a/agent_based/inv_cisco_psirt.py
+++ b/agent_based/inv_cisco_psirt.py
@@ -63,8 +63,8 @@ def _create_psirt_record(filepath, filename, not_updated, dont_show_older_then,
         with open(psirtfile) as f:
             try:
                 psirtrecord = json.load(f)
-            except ValueError as e:
-                    exit()
+            except ValueError:
+                exit()
 
         advisories = psirtrecord.get('advisories')
         remove_advisories = []
@@ -132,31 +132,31 @@ def _get_profuct_family(sysdescription: str) -> str:
 
 
 def _get_os_version(cw_version, sysdescription, pids):
-        version = None
+    version = None
 
-        if str(cw_version).find('CW_VERSION$') == 0:
-            version = cw_version.split('$')[1]  # .upper()
-        else:
-            sysdescription = sysdescription.split(',')
-            for entry in sysdescription:
-                # if entry.strip().lower().startswith('version'):
-                if 'version' in entry.lower():
-                    version = entry[entry.lower().find('version') + 7:].strip()
-                    if version.startswith(':'):  # AsyncOS
-                        version = version[1:].strip()
-                    version = version.split(' ')[0].strip()
-                    version = version  # .upper()
-            if not version:
-                for pid in pids:
-                    physoftwarerev, phymodelname, physicalclass = pid
-                    if physicalclass == '3':  # chassies
-                        version = physoftwarerev
-        # remove leading '0' in IOSXE version numbers
-        if version and version[0] == '0':
-            version = version.replace('.0', '.')
-            version = version.lstrip('0')
-
-        return version
+    if str(cw_version).find('CW_VERSION$') == 0:
+        version = cw_version.split('$')[1]  # .upper()
+    else:
+        sysdescription = sysdescription.split(',')
+        for entry in sysdescription:
+            # if entry.strip().lower().startswith('version'):
+            if 'version' in entry.lower():
+                version = entry[entry.lower().find('version') + 7:].strip()
+                if version.startswith(':'):  # AsyncOS
+                    version = version[1:].strip()
+                version = version.split(' ')[0].strip()
+                version = version  # .upper()
+        if not version:
+            for pid in pids:
+                physoftwarerev, phymodelname, physicalclass = pid
+                if physicalclass == '3':  # chassies
+                    version = physoftwarerev
+    # remove leading '0' in IOSXE version numbers
+    if version and version[0] == '0':
+        version = version.replace('.0', '.')
+        version = version.lstrip('0')
+
+    return version
 
 
 def parse_inv_cisco_psirt(string_table: List[StringTable]) -> SnmpPsirt:
diff --git a/agent_based/utils/inv_cisco_support.py b/agent_based/utils/inv_cisco_support.py
index 958bf73..90dc6a7 100644
--- a/agent_based/utils/inv_cisco_support.py
+++ b/agent_based/utils/inv_cisco_support.py
@@ -31,9 +31,7 @@ class SnmpContractEntry:
     phydescr: str
     pid: str
 
-#
-# global variables
-#
+
 # list of PIDs to drop
 g_PID_black_list = ['BUILT-IN', 'MICRON', 'C400-MTFDD']
 # list of PIDs to try by serial number
diff --git a/bin/ciscoapi/cisco-bug.py b/bin/ciscoapi/cisco-bug.py
index 9ddbb7f..e766bef 100755
--- a/bin/ciscoapi/cisco-bug.py
+++ b/bin/ciscoapi/cisco-bug.py
@@ -10,88 +10,55 @@
 #
 # 2021-07-24: rewrite for python3.8
 #
-import logging
-import ciscosupport
-import ciscoapi
 import os
 import json
-import time
-import sys
+
+from cisco_live_cycle_utils import (
+    configure_logger,
+    log_message,
+    expand_path,
+    get_ids_from_dir,
+    get_subdirs_from_dir,
+    remove_empty_sub_dirs,
+    sleep_random,
+    move_dir,
+)
+from ciscoapi import (
+    AccessToken,
+    Settings,
+    get_bug_by_pid_and_release,
+)
 
 
 def main():
+    settings = Settings()
+    access_token = AccessToken(settings.client_id, settings.client_secret)
+    configure_logger(log_level=settings.log_level)
 
-    def get_new_token():
-        response = ciscoapi.get_access_token()
-        access_token = response.get('access_token', '')
-        lifetime = int(time.time()) - int(response.get('lifetime', 3600)) - 30
-        return access_token, lifetime
-
-    ciscosupport.set_logging('debug')
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-    base_path = '~/var/ciscoapi'
-    conf_file = '~/etc/ciscoapi/ciscoapi.json'
-    conf_file = os.path.expanduser(conf_file)
-
-    access_token = ''
-    lifetime = 0
-    config = {}
-
-    refresh_found = 2
-    refresh_notfound = 1
-
-    wait_after_start = True
-    max_wait_time = 15
-
-    loglevel = 'warning'
-
-    if os.path.isfile(conf_file):
-        with open(conf_file) as f:
-            try:
-                config = json.load(f)
-            except ValueError as e:
-                logging.warning(f'snmp_cisco_eox:status:JSON load error: {e}')
-                exit()
-        # global options
-        base_path = config['global'].get('base_path', base_path)
-        wait_after_start = config['global'].get('wait_after_start', wait_after_start)
-        max_wait_time = config['global'].get('max_wait_time', max_wait_time)
-        loglevel = config['global'].get('loglevel', loglevel)
-        # bug api specific options
-        refresh_found = config['bug'].get('refresh_found', refresh_found)
-        refresh_notfound = config['bug'].get('refresh_notfound', refresh_notfound)
-    else:
-        logger.critical(f'Config file not found ({conf_file}).')
-        exit()
-
-    # loglevel = 'debug'
-    ciscosupport.set_logging(loglevel)
-
-    bug_path = base_path + '/bug'
-    path_found = ciscosupport.expand_path(bug_path + '/found')
-    path_not_found = ciscosupport.expand_path(bug_path + '/not_found')
-    path_request = ciscosupport.expand_path(bug_path + '/request')
-    path_missing = ciscosupport.expand_path(bug_path + '/missing')
+    bug_path = settings.base_path + '/bug'
+    path_found = expand_path(bug_path + '/found')
+    path_not_found = expand_path(bug_path + '/not_found')
+    path_request = expand_path(bug_path + '/request')
+    path_missing = expand_path(bug_path + '/missing')
 
     pids_requested = {}
     pids_refresh = {}
-    pids = []
 
     # get list of bug reports to refresh
-    pids = ciscosupport.get_subdirs_from_dir(path_found)
+    pids = get_subdirs_from_dir(path_found)
     for pid in pids:
-        pids_refresh[pid.replace('_', '/')] = ','.join(ciscosupport.get_ids_from_dir(path_found+pid, refresh_time=refresh_found))
+        pids_refresh[pid.replace('_', '/')] = ','.join(get_ids_from_dir(path_found+pid,
+                                                                        refresh_time=settings.bug_refresh_found))
 
     # move not_found bug reports older then 'refresh_notfound' days to request (for refresh)
-    ciscosupport.move_dir(path_not_found, path_request, refresh_time=refresh_notfound)
+    move_dir(path_not_found, path_request, refresh_time=settings.bug_refresh_not_found)
 
     # get list of PIDs requests
-    pids = ciscosupport.get_subdirs_from_dir(path_request)
-    logger.debug('bug requests (PIDs): %s' % pids)
+    pids = get_subdirs_from_dir(path_request)
+    log_message(f'bug requests (PIDs): {pids}')
     for pid in pids:
-        pids_requested[pid.replace('_', '/')] = ','.join(ciscosupport.get_ids_from_dir(path_request+pid))
-    logger.debug('bug requests (PIDs and releases): %s' % pids_requested)
+        pids_requested[pid.replace('_', '/')] = ','.join(get_ids_from_dir(path_request+pid))
+    log_message(f'bug requests (PIDs and releases): {pids_requested}')
 
     if len(pids_refresh.keys()) > 0 or len(pids_requested.keys()) > 0:
 
@@ -137,29 +104,26 @@ def main():
             reqoptions = ''
 
         # wait random time after startup (load spread)
-        if wait_after_start:
-            ciscosupport.sleep_random(max_wait_time)
-
-        # request access_token if no token available or if is expired
-        if access_token == '':
-            access_token, lifetime = get_new_token()
-
-        if access_token == '':
-            logger.critical('failed to get access_token')
-            return
+        if settings.wait_after_start:
+            sleep_random(settings.max_wait_time)
 
         # first refresh bug reports
         for pid in pids_refresh.keys():
-            if lifetime > int(time.time()):
-                access_token, lifetime = get_new_token()
+
             # get bug records for time frame
-            bug_records = ciscoapi.get_bug_by_pid_and_release(pid, pids_refresh.get(pid), access_token, reqoptions)
+            bug_records = get_bug_by_pid_and_release(
+                pid,
+                pids_refresh.get(pid),
+                access_token,
+                reqoptions,
+                settings=settings
+            )
             for entry in bug_records:
                 pid = entry.get('pid')
                 software_releases = entry.get('software_releases')
                 status_code = int(entry.get('status_code', 200))
-                logger.debug('bug return:PID: %s, Status: %s, Version: %s' % (pid, status_code, software_releases))
-                path = ciscosupport.expand_path(path_found + pid.replace('/', '_'))
+                log_message(f'bug return:PID: {pid}, Status: {status_code}, Version: {software_releases}')
+                path = expand_path(path_found + pid.replace('/', '_'))
                 # check if there where was an error, if so go to next pid
                 if status_code == 200:
                     bugs = entry.get('bugs', None)
@@ -168,8 +132,7 @@ def main():
                             bug.pop('description')  # remove description
                         for release in software_releases.keys():  # create one bug list per software release
                             bug_release = software_releases.get(release)
-                            logger.debug('bug found:PID: %s, Releases: %s' % (pid, release))
-                            missing = entry.get('missing', {})
+                            log_message(f'bug found:PID: {pid}, Releases: {release}')
                             new_bugs = []
                             for bug in bugs:
                                 if bug_release in bug.get('known_affected_releases'):
@@ -180,7 +143,8 @@ def main():
                                 try:
                                     bug_record = json.load(f)
                                 except ValueError as e:
-                                    logging.warning(f'{pid}:{release}:snmp_cisco_bug:bug_found:JSON load error: {e}')
+                                    log_message(f'{pid}:{release}:snmp_cisco_bug:bug_found:JSON load error: {e}',
+                                                level='WARNING')
 
                             found_bugs = bug_record.get('bugs')
                             for found_bug in found_bugs:
@@ -193,16 +157,9 @@ def main():
                             bug_record['bugs'] = found_bugs  # replace bug list with new list
                             bug_record['total_records'] = len(found_bugs)  # change number of records
 
-                            # bug_record['missing'] = missing  # replace missing state with new missing state
-
                             with open(path + release, 'w') as f:
                                 json.dump(bug_record, f)  # write updated bug report
 
-                            # if len(missing.keys()) != 0:
-                            #     path = ciscosupport.expand_path(path_missing + pid.replace('/', '_'))
-                            #     with open(path + release, 'w') as f:
-                            #         json.dump(missing, f)  # write update missing state
-
                     else:
                         for release in software_releases.keys():
                             if os.path.exists(path + release):
@@ -242,7 +199,7 @@ def main():
         #  modified_date_earliest (earliest first)
         # reqoptions.append('sort_by=severity')
 
-        #reqoptions.append('page_index=2')
+        # reqoptions.append('page_index=2')
 
         if len(reqoptions) > 0:
             reqoptions = '?' + '&'.join(reqoptions)
@@ -250,14 +207,18 @@ def main():
             reqoptions = ''
 
         for pid in pids_requested.keys():
-            if lifetime > int(time.time()):
-                access_token, lifetime = get_new_token()
-            bug_records = ciscoapi.get_bug_by_pid_and_release(pid, pids_requested.get(pid), access_token, reqoptions)
+            bug_records = get_bug_by_pid_and_release(
+                pid,
+                pids_requested.get(pid),
+                access_token,
+                reqoptions,
+                settings=settings
+            )
             for entry in bug_records:
                 pid = entry.get('pid')
                 software_releases = entry.get('software_releases')
                 status_code = int(entry.get('status_code', 200))
-                logger.debug('bug return:PID: %s, Status: %s, Version: %s' % (pid, status_code, software_releases))
+                log_message(f'bug return:PID: {pid}, Status: {status_code}, Version: {software_releases}')
                 # check if there where was an error, if so go to next pid
                 if status_code == 200:
                     bugs = entry.get('bugs', None)
@@ -267,49 +228,48 @@ def main():
                     for release in software_releases.keys():  # create one bug list per software release
                         bug_release = software_releases.get(release)
                         if bugs:
-                            logger.debug('bug found:PID: %s, Releases: %s' % (pid, release))
+                            log_message(f'bug found:PID: %s{pid}, Releases: {release}')
                             missing = entry.get('missing', {})
                             # split bugs by release
-                            release_bugs = {'pid': pid,
-                                            'software_release': release,
-                                            'bugs': [],
-                                            'missing': missing}
+                            release_bugs = {
+                                'pid': pid,
+                                'software_release': release,
+                                'bugs': [],
+                                'missing': missing
+                            }
                             for bug in bugs:
                                 if bug_release in bug.get('known_affected_releases'):
                                     release_bugs['bugs'].append(bug)
-                            # changed from entry.get('total_records') --> total records for all requested software releases
                             release_bugs['total_records'] = len(release_bugs['bugs'])
 
-                            path = ciscosupport.expand_path(path_found + pid.replace('/', '_'))
+                            path = expand_path(path_found + pid.replace('/', '_'))
                             with open(path + release, 'w') as f:
                                 json.dump(release_bugs, f)
 
                             if len(missing.keys()) != 0:
-                                path = ciscosupport.expand_path(path_missing + pid.replace('/', '_'))
+                                path = expand_path(path_missing + pid.replace('/', '_'))
                                 with open(path + release, 'w') as f:
                                     json.dump(missing, f)
                         else:
-                            logger.debug('bug not found:PID: %s, Version: %s' % (pid, release))
-                            path = ciscosupport.expand_path(path_not_found + pid.replace('/', '_'))
-                            logger.debug('not found: %s' % entry)
+                            log_message(f'bug not found:PID: {pid}, Version: {release}')
+                            path = expand_path(path_not_found + pid.replace('/', '_'))
+                            log_message(f'not found: {entry}')
                             with open(path + release, 'w') as f:
                                 json.dump(entry, f)
                                 pass
 
                         # remove request file
                         try:
-                            logger.debug('bug delete request:PID: %s, Version: %s' % (pid, release))
+                            log_message(f'bug delete request:PID: {pid}, Version: {release}')
                             os.remove(path_request + pid.replace('/', '_') + '/' + release)
                         except OSError:
                             pass
 
         # clean up (remove empty directories)
-        ciscosupport.remove_empty_sub_dirs(path_request)
-        ciscosupport.remove_empty_sub_dirs(path_found)
-        ciscosupport.remove_empty_sub_dirs(path_not_found)
-        ciscosupport.remove_empty_sub_dirs(path_missing)
-
-main()
-
+        remove_empty_sub_dirs(path_request)
+        remove_empty_sub_dirs(path_found)
+        remove_empty_sub_dirs(path_not_found)
+        remove_empty_sub_dirs(path_missing)
 
 
+main()
diff --git a/bin/ciscoapi/cisco-eox.py b/bin/ciscoapi/cisco-eox.py
index 85ed776..630ca3c 100755
--- a/bin/ciscoapi/cisco-eox.py
+++ b/bin/ciscoapi/cisco-eox.py
@@ -11,20 +11,27 @@
 #
 # 2021-07-23: rewrite for python 3.8
 #
-import logging
-import os
 import json
-import time
-import ciscosupport
-import ciscoapi
-import sys
+from cisco_live_cycle_utils import (
+    configure_logger,
+    log_message,
+    expand_path,
+    get_ids_from_dir,
+    remove_ids_from_list,
+    refresh_ids_from_dir,
+    remove_ids_from_dir,
+    sleep_random,
+)
+from ciscoapi import (
+    AccessToken,
+    Settings,
+    get_eox_by_pid,
+    get_eox_by_serials,
+)
 
 
 # split pids in known and unknown eox state
 def split_pids(eoxr):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
     eox_known = []
     eox_unkown = []
 
@@ -39,30 +46,27 @@ def split_pids(eoxr):
             for PID in EOXRecord:
                 if PID.get('EOLProductID') != '':
                     eox_known.append(PID)
-                    logger.debug('EOLProductID  : %s' % PID.get('EOLProductID'))
+                    log_message(message=f'EOLProductID  : {PID.get("EOLProductID")}')
                 else:
                     eox_unkown.append(PID)
-                    logger.debug('EOXInputValue : %s' % PID.get('EOXInputValue'))
+                    log_message(f'EOXInputValue : {PID.get("EOXInputValue")}')
     return {'eox_known': eox_known, 'eox_unknown': eox_unkown}
 
 
 # split serials, expects a list of EoX Records from get EoX by serial
 def split_serials(eoxr):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
     serials = []
 
     for PID in eoxr:
         EOLProductID = PID.get('EOLProductID')
-        logger.debug('serial split Eox: found PID: %s' % EOLProductID)
+        log_message(f'serial split Eox: found PID: {EOLProductID}')
         EOXInputValue = PID.get('EOXInputValue').split(',')
         for serial in EOXInputValue:
-            logger.debug('found Serial: %s' % serial)
+            log_message(f'found Serial: {serial}')
             eox_serial = PID.copy()
             eox_serial.update({'EOXInputValue': serial})
             serials.append(eox_serial)
-            logger.debug('Serial EoX: %s' % eox_serial)
+            log_message(f'Serial EoX: {eox_serial}')
 
     return serials
 
@@ -71,9 +75,6 @@ def split_serials(eoxr):
 # expects a list of EoX Records from Cisco EoX API 5.0,
 # returns a list of saved PIDs
 def save_eox(eox, path):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
     saved = []
 
     for PID in eox:
@@ -82,147 +83,96 @@ def save_eox(eox, path):
         if EOLProductID == '':
             EOLProductID = PID.get('EOXInputValue')
 
-        with open(path + (EOLProductID.replace('/','_')), 'w') as f:
+        with open(path + (EOLProductID.replace('/', '_')), 'w') as f:
             json.dump(PID, f)
             saved.append(EOLProductID)
 
     return saved
 
 
-# save EoX records to file by serial number,
-# expects a list of EoX Records from Cisco EoX API 5.0,
-# returns a list of saved Serials
 def save_serials(eox, path):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
+    """
+    Saves EoX records to file by serial number.
+    Args:
+        eox: List of EoX Records from Cisco EoX API 5.0
+        path: file path where to save the EoX records
+
+    Returns: List of serial numbers of saved EoX records
+
+    """
 
     saved = []
 
-    for SERIAL in eox:
-        EOXInputValue = SERIAL.get('EOXInputValue')
+    for serial in eox:
+        EOXInputValue = serial.get('EOXInputValue')
         if EOXInputValue != '':
             with open(path + EOXInputValue, 'w') as f:
-                json.dump(SERIAL, f)
+                json.dump(serial, f)
             saved.append(EOXInputValue)
 
     return saved
 
 
 def main():
+    settings = Settings()
+    access_token = AccessToken(settings.client_id, settings.client_secret)
+    configure_logger(log_level=settings.log_level)
 
-    ciscosupport.set_logging('debug')
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-    base_path = '~/var/ciscoapi'
-    conf_file = '~/etc/ciscoapi/ciscoapi.json'
-    conf_file = os.path.expanduser(conf_file)
-
-    access_token = ''
-    lifetime = 0
-    pids = []
-    serials = []
-    config = {}
-
-    # refresh time in days
-    eox_refresh_known = 31
-    eox_refresh_unknown = 7
-
-    wait_after_start = True
-    max_wait_time = 15
-
-    loglevel = 'warning'
-
-    if os.path.isfile(conf_file):
-        with open(conf_file) as f:
-            try:
-                config = json.load(f)
-            except ValueError as e:
-                logging.warning(f'snmp_cisco_eox:status:JSON load error: {e}')
-                exit()
-
-            base_path = config['global'].get('base_path', base_path)
-            wait_after_start = config['global'].get('wait_after_start', wait_after_start)
-            max_wait_time = config['global'].get('max_wait_time', max_wait_time)
-            loglevel = config['global'].get('loglevel', loglevel)
-
-            eox_refresh_known = config['eox'].get('eox_refresh_known', eox_refresh_known)
-            eox_refresh_unknown = config['eox'].get('eox_refresh_unknown', eox_refresh_unknown)
-    else:
-        logger.critical('Config file not found (%s).' % conf_file)
-        return False
-
-    ciscosupport.set_logging(loglevel)
-
-    eox_path = base_path + '/EoX'
+    eox_path = settings.base_path + '/EoX'
     path_found = eox_path + '/found'
     path_not_found = eox_path + '/not_found'
     path_request = eox_path + '/request'
 
-    path_request_pid = ciscosupport.expand_path(path_request + '/pid')
-    path_found_pid = ciscosupport.expand_path(path_found + '/pid')
-    path_not_found_pid = ciscosupport.expand_path(path_not_found + '/pid')
+    path_request_pid = expand_path(path_request + '/pid')
+    path_found_pid = expand_path(path_found + '/pid')
+    path_not_found_pid = expand_path(path_not_found + '/pid')
 
-    path_request_ser = ciscosupport.expand_path(path_request + '/ser')
-    path_found_ser = ciscosupport.expand_path(path_found + '/ser')
-    path_not_found_ser = ciscosupport.expand_path(path_not_found + '/ser')
+    path_request_ser = expand_path(path_request + '/ser')
+    path_found_ser = expand_path(path_found + '/ser')
+    path_not_found_ser = expand_path(path_not_found + '/ser')
 
     # create list of PIDs to request EoX status for
-    pids = ciscosupport.get_ids_from_dir(path_request_pid)
-    logger.debug('pid requests : %s' % pids)
+    pids = get_ids_from_dir(path_request_pid)
+    log_message(f'pid requests : {pids}')
     # remove already known PIDs from list
-    pids = ciscosupport.remove_ids_from_list(pids, path_found_pid)
-    logger.debug('pid requests : %s' % pids)
+    pids = remove_ids_from_list(pids, path_found_pid)
+    log_message(f'pid requests : {pids}')
     # remove PIDs already requested with unknown EoX status from list
-    pids = ciscosupport.remove_ids_from_list(pids, path_not_found_pid)
-    logger.debug('pid requests : %s' % pids)
+    pids = remove_ids_from_list(pids, path_not_found_pid)
+    log_message(f'pid requests : {pids}')
 
     # refresh PIDs after 30 days by default
-    pids = ciscosupport.refresh_ids_from_dir(path_not_found_pid, eox_refresh_unknown, pids, True)
-    logger.debug('pid requests : %s' % pids)
-    pids = ciscosupport.refresh_ids_from_dir(path_found_pid, eox_refresh_known, pids, False)
-    logger.debug('pid requests : %s' % pids)
+    pids = refresh_ids_from_dir(path_not_found_pid, settings.eox_refresh_unknown, pids, True)
+    log_message(f'pid requests : {pids}')
+    pids = refresh_ids_from_dir(path_found_pid, settings.eox_refresh_known, pids, False)
+    log_message(f'pid requests : {pids}')
 
     # create list of serial numbers to request EoX status for
-    serials = ciscosupport.get_ids_from_dir(path_request_ser)
-    logger.debug('ser requests : %s' % serials)
+    serials = get_ids_from_dir(path_request_ser)
+    log_message(f'ser requests : {serials}')
     # remove already known serials from list
-    serials = ciscosupport.remove_ids_from_list(serials, path_found_ser)
-    logger.debug('ser requests : %s' % serials)
+    serials = remove_ids_from_list(serials, path_found_ser)
+    log_message(f'ser requests : {serials}')
     # remove serials already requested with unknown EoX status from list
-    serials = ciscosupport.remove_ids_from_list(serials, path_not_found_ser)
-    logger.debug('ser requests : %s' % serials)
+    serials = remove_ids_from_list(serials, path_not_found_ser)
+    log_message(f'ser requests : {serials}')
 
     # refresh serials after 30 days by default
-    serials = ciscosupport.refresh_ids_from_dir(path_not_found_ser, eox_refresh_unknown, serials, True)
-    logger.debug('ser requests : %s' % serials)
-    serials = ciscosupport.refresh_ids_from_dir(path_found_ser, eox_refresh_known, serials, False)
-    logger.debug('ser requests : %s' % serials)
+    serials = refresh_ids_from_dir(path_not_found_ser, settings.eox_refresh_unknown, serials, True)
+    log_message(f'ser requests : {serials}')
+    serials = refresh_ids_from_dir(path_found_ser, settings.eox_refresh_known, serials, False)
+    log_message(f'ser requests : {serials}')
 
     if pids == [] and serials == []:
-        logger.debug('all list are empty. Do nothing.')
+        log_message('all list are empty. Do nothing.')
         return
 
     # wait random time after startup (load spread)
-    if wait_after_start:
-        ciscosupport.sleep_random(max_wait_time)
-
-    # get time since epoch in seconds
-    starttime = int(time.time())
-
-    # request access_token if no token available or if is expired
-    if (access_token == '') or lifetime < starttime:
-        response = ciscoapi.get_access_token()
-        access_token = response.get('access_token', '')
-        lifetime = int(response.get('lifetime', 3600))
-
-    lifetime = starttime + lifetime - 30
-
-    if access_token == '':
-        logger.critical('failed to get access_token')
-        return
+    if settings.wait_after_start:
+        sleep_random(settings.max_wait_time)
 
-    if pids != []:
-        eox = ciscoapi.get_eox_by_pid(pids, access_token)
+    if pids is not []:
+        eox = get_eox_by_pid(pids=pids, access_token=access_token, settings=settings)
 
         # split eox records in a list of known and unknown pid records
         eox = split_pids(eox)
@@ -230,18 +180,18 @@ def main():
         # save known pid reports
         pids = save_eox(eox.get('eox_known'), path_found_pid)
         # delete requests for known pids
-        ciscosupport.remove_ids_from_dir(pids, path_request_pid)
+        remove_ids_from_dir(pids, path_request_pid)
 
         # save unknown pid reports
         pids = save_eox(eox.get('eox_unknown'), path_not_found_pid)
         # delete requests for unknown pids
-        ciscosupport.remove_ids_from_dir(pids, path_request_pid)
+        remove_ids_from_dir(pids, path_request_pid)
         # delete pids from known were the status changed to unknown
-        ciscosupport.remove_ids_from_dir(pids, path_found_pid)
+        remove_ids_from_dir(pids, path_found_pid)
 
-    if serials != []:
-        eox = ciscoapi.get_eox_by_serials(serials, access_token)
-        logger.debug('eox by ser: %s' % eox)
+    if serials is not []:
+        eox = get_eox_by_serials(serials=serials, access_token=access_token, settings=settings)
+        log_message(f'eox by ser: {eox}')
 
         # split eox records in a list of known and unknown pid records
         eox = split_pids(eox)
@@ -250,18 +200,18 @@ def main():
         serials = split_serials(eox.get('eox_known'))
         # save EoX records for serials with known EoX state
         serials = save_serials(serials, path_found_ser)
-        logger.debug('EoX Serials: known: %s' % serials)
+        log_message(f'EoX Serials: known: {serials}')
         # delete requests for known serials
-        ciscosupport.remove_ids_from_dir(serials, path_request_ser)
+        remove_ids_from_dir(serials, path_request_ser)
 
         # split EoX records for unknown PIDs in one entry per serial
         serials = split_serials(eox.get('eox_unknown'))
         # save EoX records for serials with known EoX state
         serials = save_serials(serials, path_not_found_ser)
         # delete requests for unknown serials
-        ciscosupport.remove_ids_from_dir(serials, path_request_ser)
+        remove_ids_from_dir(serials, path_request_ser)
         # delete serials from known were the status changed to unknown
-        ciscosupport.remove_ids_from_dir(serials, path_found_ser)
+        remove_ids_from_dir(serials, path_found_ser)
 
 
 main()
diff --git a/bin/ciscoapi/cisco-psirt.py b/bin/ciscoapi/cisco-psirt.py
index cc1caa6..3b0db9b 100755
--- a/bin/ciscoapi/cisco-psirt.py
+++ b/bin/ciscoapi/cisco-psirt.py
@@ -7,21 +7,33 @@
 #
 #  https://developer.cisco.com/docs/support-apis/
 #
-# 2018-06-06: fixed handling if state changes form found to notfound (delete old psirt found file)
+# 2018-06-06: fixed handling if state changes form found to not_found (delete old psirt found file)
 # 2021-07-24: rewritten for python 3.8
 #
 #
-import logging
 import ntpath
 import os
 import json
-import time
-import ciscosupport
-import ciscoapi
-import sys
 from typing import List
 from dataclasses import dataclass
 
+from cisco_live_cycle_utils import (
+    configure_logger,
+    log_message,
+    get_ids_from_dir,
+    remove_ids_from_list,
+    refresh_ids_from_dir,
+    sleep_random,
+    expand_path,
+)
+from ciscoapi import (
+    AccessToken,
+    Settings,
+    get_psirt_by_product_family,
+    get_psirt_by_iosxe_version,
+    get_psirt_by_ios_version,
+)
+
 
 @dataclass
 class Paths:
@@ -40,21 +52,15 @@ g_logger = None
 
 
 def _psirt_remove_id_file(psirt_path: str, psirt_id: str):
-    # set logg module name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
     # delete psirt file
     try:
-        logger.debug(f'delete psirt id file : {psirt_path + psirt_id}')
+        log_message(f'delete psirt id file : {psirt_path + psirt_id}')
         os.remove(psirt_path + psirt_id)
     except OSError:
         pass
 
 
 def _psirt_dump_record(psirt_record, psirt_id: str, psirt_path: str, psirt_path_request: str):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
     with open(psirt_path + psirt_id, 'w') as f:
         json.dump(psirt_record, f)
     # delete request file
@@ -72,8 +78,6 @@ def _check_psirt_record(psirt_record, psirt_id, psirt_path_found, psirt_path_req
     :param psirt_path_request:
     :returns:
     """
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
 
     for advisory in psirt_record.get('advisories'):
         # remove unwanted information from advisories
@@ -102,22 +106,20 @@ def _get_psirt_id_list(product_family: str, paths: Paths, refresh: Refresh) -> L
     @return: list of PIDs
     """
     # create list of ID's to request PSIRT status for
-    psirt_id_list = ciscosupport.get_ids_from_dir(paths.request + product_family)
-    g_logger.debug(f'psirt requests : {psirt_id_list}')
+    psirt_id_list = get_ids_from_dir(paths.request + product_family)
+    log_message(f'psirt requests : {psirt_id_list}')
     # remove already found ID's from list
-    psirt_id_list = ciscosupport.remove_ids_from_list(psirt_id_list, paths.found + product_family)
-    g_logger.debug(f'psirt requests : {psirt_id_list}')
+    psirt_id_list = remove_ids_from_list(psirt_id_list, paths.found + product_family)
+    log_message(f'psirt requests : {psirt_id_list}')
     # remove not found ID's from list
-    psirt_id_list = ciscosupport.remove_ids_from_list(psirt_id_list, paths.not_found + product_family)
-    g_logger.debug(f'psirt requests : {psirt_id_list}')
+    psirt_id_list = remove_ids_from_list(psirt_id_list, paths.not_found + product_family)
+    log_message(f'psirt requests : {psirt_id_list}')
 
     # refresh psirt after 1 day by default
-    psirt_id_list = ciscosupport.refresh_ids_from_dir(paths.not_found + product_family, refresh.not_found,
-                                                      psirt_id_list, True)
-    g_logger.debug(f'psirt requests : {psirt_id_list}')
-    psirt_id_list = ciscosupport.refresh_ids_from_dir(paths.found + product_family, refresh.found,
-                                                      psirt_id_list, False)
-    g_logger.debug(f'psirt requests : {psirt_id_list}')
+    psirt_id_list = refresh_ids_from_dir(paths.not_found + product_family, refresh.not_found, psirt_id_list, True)
+    log_message(f'psirt requests : {psirt_id_list}')
+    psirt_id_list = refresh_ids_from_dir(paths.found + product_family, refresh.found, psirt_id_list, False)
+    log_message(f'psirt requests : {psirt_id_list}')
 
     return psirt_id_list
 
@@ -141,58 +143,19 @@ def _update_psirt_id(psirt_records: list, family_name: str, paths: Paths):
 
 
 def main():
-    global g_logger
-
-    ciscosupport.set_logging('debug')
-    # set logg modul name <file>:<module>.<function>
-    g_logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
-    conf_file = '~/etc/ciscoapi/ciscoapi.json'
-    conf_file = os.path.expanduser(conf_file)
-
-    # default paths
-    base_path = '~/var/ciscoapi'
-
-    access_token = ''
-    lifetime = 0
-    config = {}
-
-    # refresh time in days
-    psirt_refresh_found = 1
-    psirt_refresh_notfound = 1
-
-    wait_after_start = True
-    max_wait_time = 15
-    loglevel = 'warning'
-    # loglevel = 'debug'
-
-    if os.path.isfile(conf_file):
-        with open(conf_file) as f:
-            try:
-                config = json.load(f)
-            except ValueError as e:
-                logging.warning(f'snmp_cisco_eox:status:JSON load error: {e}')
-                exit()
-
-        base_path = config['global'].get('base_path', base_path)
-        wait_after_start = config['global'].get('wait_after_start', wait_after_start)
-        max_wait_time = config['global'].get('max_wait_time', max_wait_time)
-        loglevel = config['global'].get('loglevel', loglevel)
-        refresh = Refresh(
-            found=config['psirt'].get('psirt_refresh_found', psirt_refresh_found),
-            not_found=config['psirt'].get('psirt_refresh_notfound', psirt_refresh_notfound)
-        )
-    else:
-        g_logger.critical(f'Config file not found ({conf_file}).')
-        return False
-
-    ciscosupport.set_logging(loglevel)
-
-    base_path = ciscosupport.expand_path(base_path)
-    psirt_dir = base_path + 'psirt'
+    settings = Settings()
+    access_token = AccessToken(settings.client_id, settings.client_secret)
+    configure_logger(log_level=settings.log_level)
+
+    refresh = Refresh(
+        found=settings.psirt_refresh_found,
+        not_found=settings.psirt_refresh_not_found
+    )
+
+    psirt_dir = expand_path(settings.base_path + '/psirt')
     paths = Paths(
         found=psirt_dir + '/found/',
-        not_found= psirt_dir + '/not_found/',
+        not_found=psirt_dir + '/not_found/',
         request=psirt_dir + '/request/'
     )
 
@@ -201,38 +164,23 @@ def main():
     psirt_family = _get_psirt_id_list('family', paths, refresh)
 
     if (psirt_ios == []) and psirt_ios_xe == [] and psirt_family == []:
-        g_logger.debug('all list are empty. Do nothing.')
+        log_message('all list are empty. Do nothing.')
         return
 
     # wait random time after startup
-    if wait_after_start:
-        ciscosupport.sleep_random(max_wait_time)
-
-    # get time since epoch in seconds
-    starttime = int(time.time())
-
-    # request access_token if no token available or if is expired
-    if (access_token == '') or lifetime < starttime:
-        response = ciscoapi.get_access_token()
-        access_token = response.get('access_token', '')
-        lifetime = int(response.get('lifetime', 3600))
-
-    lifetime = starttime + lifetime - 30
-
-    if access_token == '':
-        g_logger.critical('failed to get access_token')
-        return
+    if settings.wait_after_start:
+        sleep_random(settings.max_wait_time)
 
-    if psirt_family != []:
-        psirt_records = ciscoapi.get_psirt_by_product_family(psirt_family, access_token)
+    if psirt_family is not []:
+        psirt_records = get_psirt_by_product_family(psirt_family, access_token, settings=settings)
         _update_psirt_id(psirt_records, 'family', paths)
 
-    if psirt_ios_xe != []:
-        psirt_records = ciscoapi.get_psirt_by_iosxe_version(psirt_ios_xe, access_token)
+    if psirt_ios_xe is not []:
+        psirt_records = get_psirt_by_iosxe_version(psirt_ios_xe, access_token, settings=settings)
         _update_psirt_id(psirt_records, 'IOS-XE', paths)
 
-    if psirt_ios != []:
-        psirt_records = ciscoapi.get_psirt_by_ios_version(psirt_ios, access_token)
+    if psirt_ios is not []:
+        psirt_records = get_psirt_by_ios_version(psirt_ios, access_token, settings=settings)
         _update_psirt_id(psirt_records, 'IOS', paths)
 
 
diff --git a/bin/ciscoapi/cisco-sn2info.py b/bin/ciscoapi/cisco-sn2info.py
index 3a9b2e6..1a45b2b 100755
--- a/bin/ciscoapi/cisco-sn2info.py
+++ b/bin/ciscoapi/cisco-sn2info.py
@@ -13,23 +13,30 @@
 #
 # 2021-07-23: rewrite for python 3.8
 #
-import logging
-import os
 import json
-import time
-import ciscosupport
-import ciscoapi
-import sys
-
-
-def sn2info_split_covered(sn2inforecords):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
 
+from cisco_live_cycle_utils import (
+    configure_logger,
+    log_message,
+    expand_path,
+    get_ids_from_dir,
+    remove_ids_from_list,
+    refresh_ids_from_dir,
+    remove_ids_from_dir,
+    sleep_random,
+)
+from ciscoapi import (
+    AccessToken,
+    Settings,
+    get_coverage_summary_by_serials,
+)
+
+
+def sn2info_split_covered(sn2info_records):
     sn2info_covered = []
     sn2info_notcovered = []
 
-    for response in sn2inforecords:
+    for response in sn2info_records:
         sn2inforecord = response.get('serial_numbers')
 #        PaginationResponseRecord = response.get('PaginationResponseRecord')
 #        PageIndex = PaginationResponseRecord.get('PageIndex')
@@ -40,17 +47,14 @@ def sn2info_split_covered(sn2inforecords):
             for serial in sn2inforecord:
                 if serial.get('is_covered') == 'YES':
                     sn2info_covered.append(serial)
-                    logger.debug('SN2INFO covered  : %s' % serial.get('sr_no'))
+                    log_message(f'SN2INFO covered  : {serial.get("sr_no")}')
                 else:
                     sn2info_notcovered.append(serial)
-                    logger.debug('SN2INFO not covered : %s' % serial.get('sr_no'))
+                    log_message(f'SN2INFO not covered : {serial.get("sr_no")}')
     return {'sn2info_covered': sn2info_covered, 'sn2info_notcovered': sn2info_notcovered}
 
 
 def sn2info_save_serials(sn2infos, path):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
     saved = []
 
     for sn2info in sn2infos:
@@ -64,106 +68,53 @@ def sn2info_save_serials(sn2infos, path):
 
 
 def main():
+    settings = Settings()
+    access_token = AccessToken(settings.client_id, settings.client_secret)
+    configure_logger(log_level=settings.log_level)
 
-    ciscosupport.set_logging('debug')
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
-    conf_file = '~/etc/ciscoapi/ciscoapi.json'
-    conf_file = os.path.expanduser(conf_file)
-
-    # default paths
-    base_path = '~/var/ciscoapi'
-    
-    access_token = ''
-    lifetime = 0
-    sn2info = []
-    config = {}
-
-    # refresh time in days
-    sn2info_refresh_covered = 31
-    sn2info_refresh_notcovered = 7
-
-    wait_after_start = True
-    max_wait_time = 15
-    loglevel = 'warning'
-
-    if os.path.isfile(conf_file):
-        with open(conf_file) as f:
-            try:
-                config = json.load(f)
-            except ValueError as e:
-                logging.warning(f'snmp_cisco_eox:status:JSON load error: {e}')
-                exit()
-
-        wait_after_start = config['global'].get('base_path', base_path)
-        sn2info_refresh_covered = config['sn2info'].get('sn2info_refresh_covered', sn2info_refresh_covered)
-        sn2info_refresh_notcovered = config['sn2info'].get('sn2info_refresh_notcovered', sn2info_refresh_notcovered)
-
-        wait_after_start = config['global'].get('wait_after_start', wait_after_start)
-        max_wait_time = config['global'].get('max_wait_time', max_wait_time)
-        loglevel = config['global'].get('loglevel', loglevel)
-    else:
-        logger.critical(f'Config file not found ({conf_file}).')
-        exit()
-
-    ciscosupport.set_logging(loglevel)
-
-    sn2info_dir = base_path + '/sn2info'
-    path_found = ciscosupport.expand_path(sn2info_dir + '/found/')
-    path_not_found = ciscosupport.expand_path(sn2info_dir + '/not_found/')
-    path_request = ciscosupport.expand_path(sn2info_dir + '/request/')
+    sn2info_dir = settings.base_path + '/sn2info'
+    path_found = expand_path(sn2info_dir + '/found/')
+    path_not_found = expand_path(sn2info_dir + '/not_found/')
+    path_request = expand_path(sn2info_dir + '/request/')
 
     # create list of serial numbers to request SN2INFO status for
-    sn2info = ciscosupport.get_ids_from_dir(path_request)
-    logger.debug('sn2info requests : %s' % sn2info)
+    sn2info = get_ids_from_dir(path_request)
+    log_message(f'sn2info requests : {sn2info}')
     # remove covered serials from list
-    sn2info = ciscosupport.remove_ids_from_list(sn2info, path_found)
-    logger.debug('sn2info requests : %s' % sn2info)
+    sn2info = remove_ids_from_list(sn2info, path_found)
+    log_message(f'sn2info requests : {sn2info}')
     # remove not covered serials from list
-    sn2info = ciscosupport.remove_ids_from_list(sn2info, path_not_found)
-    logger.debug('sn2info requests : %s' % sn2info)
+    sn2info = remove_ids_from_list(sn2info, path_not_found)
+    log_message(f'sn2info requests : {sn2info}')
 
     # refresh sn2info serials after 31 days by default
-    sn2info = ciscosupport.refresh_ids_from_dir(path_not_found, sn2info_refresh_notcovered, sn2info, True)
-    logger.debug('sn2info requests : %s' % sn2info)
-    sn2info = ciscosupport.refresh_ids_from_dir(path_found, sn2info_refresh_covered, sn2info, False)
-    logger.debug('sn2info requests : %s' % sn2info)
+    sn2info = refresh_ids_from_dir(path_not_found, settings.sn2info_refresh_not_covered, sn2info, True)
+    log_message(f'sn2info requests : {sn2info}')
+    sn2info = refresh_ids_from_dir(path_found, settings.sn2info_refresh_covered, sn2info, False)
+    log_message(f'sn2info requests : {sn2info}')
 
-    if sn2info == [] :
-        logger.debug('all list are empty. Do nothing.')
+    if sn2info is []:
+        log_message('all list are empty. Do nothing.')
         return
 
     # wait random time after startup
-    if wait_after_start:
-        ciscosupport.sleep_random(max_wait_time)
-
-    # get time since epoch in seconds
-    starttime = int(time.time())
-
-    # request access_token if no token available or if is expired
-    if (access_token == '') or lifetime < starttime:
-        response = ciscoapi.get_access_token()
-        access_token = response.get('access_token', '')
-        lifetime = int(response.get('lifetime', 3600))
-
-    lifetime = starttime + lifetime - 30
-
-    if access_token == '':
-        logger.critical('failed to get access_token')
-        return
-
-    if sn2info != []:
-        sn2inforecords = ciscoapi.get_coverage_summary_by_serials(sn2info, access_token)
-        logger.debug('sn2info response: %s' % sn2inforecords)
-        sn2info = sn2info_split_covered(sn2inforecords)
+    if settings.wait_after_start:
+        sleep_random(settings.max_wait_time)
+
+    if sn2info is not []:
+        sn2info_records = get_coverage_summary_by_serials(
+            serials=sn2info,
+            access_token=access_token,
+            settings=settings
+        )
+        log_message(f'sn2info response: {sn2info_records}')
+        sn2info = sn2info_split_covered(sn2info_records)
         serials = sn2info_save_serials(sn2info.get('sn2info_covered'), path_found)
-        ciscosupport.remove_ids_from_dir(serials, path_request)
+        remove_ids_from_dir(serials, path_request)
         serials = sn2info_save_serials(sn2info.get('sn2info_notcovered'), path_not_found)
-        ciscosupport.remove_ids_from_dir(serials, path_request)
+        remove_ids_from_dir(serials, path_request)
         # delete serials from covered were the status changed to uncovered
-        ciscosupport.remove_ids_from_dir(serials, path_found)
+        remove_ids_from_dir(serials, path_found)
 
 
 main()
-
diff --git a/bin/ciscoapi/cisco_live_cycle_utils.py b/bin/ciscoapi/cisco_live_cycle_utils.py
new file mode 100755
index 0000000..a32ddf9
--- /dev/null
+++ b/bin/ciscoapi/cisco_live_cycle_utils.py
@@ -0,0 +1,270 @@
+#!/usr/bin/env python
+# -*- encoding: utf-8; py-indent-offset: 4 -*-
+
+#
+# 15.04.2017 : Th.L. : Support for Cisco API
+#
+#  https://developer.cisco.com/docs/support-apis/
+#
+
+import logging
+import os
+import time
+import random
+import sys
+# import json
+# import copy
+# from ciscoapi import (
+#     Settings,
+#     get_product_mdf_information_by_pid,
+# )
+
+
+def configure_logger(_path: str = '', _log_to_console: bool = True, log_level: str = 'INFO'):
+    log_formatter = logging.Formatter('%(asctime)s :: %(levelname)s :: %(name)s :: %(module)s ::%(message)s')
+    log = logging.getLogger('root')
+
+    numeric_level = getattr(logging, log_level.upper(), None)
+    if isinstance(numeric_level, int):
+        logging.getLogger().setLevel(numeric_level)
+    else:
+        logging.getLogger().setLevel(logging.WARNING)
+
+    # log_file = path
+    # # create a new file > 5 mb size
+    # log_handler_file = logging.handlers.RotatingFileHandler(
+    #     log_file,
+    #     mode='a',
+    #     maxBytes=5 * 1024 * 1024,
+    #     backupCount=10,
+    #     # encoding=None,
+    #     # delay=0
+    # )
+
+    # log_handler_file.setFormatter(log_formatter)
+    # log_handler_file.setLevel(logging.INFO)
+    # log.addHandler(log_handler_file)
+
+    log_handler_console = logging.StreamHandler(sys.stdout)
+    log_handler_console.setFormatter(log_formatter)
+    log_handler_console.setLevel(logging.INFO)
+    log.addHandler(log_handler_console)
+
+
+def log_message(message: str, level: str = 'DEBUG'):
+    log = logging.getLogger()
+    if level.upper() == 'CRITICAL':
+        log.critical(message)
+    elif level.upper() == 'ERROR':
+        log.error(message)
+    elif level.upper() == 'WARNING':
+        log.warning(message)
+    elif level.upper() == 'INFO':
+        log.info(message)
+    elif level.upper() == 'DEBUG':
+        log.debug(message)
+    else:
+        log.warning(f'unknown log_level: {level}')
+
+
+def sleep_random(max_minutes):
+    sleep_time = random.randint(1, 60 * max_minutes)
+    log_message(message=f'{sleep_time} seconds', level='INFO')
+    time.sleep(sleep_time)
+    return
+
+
+# read list of files from dir (eq. (P)IDs or SERIALs) (don't change to uppercase)
+def get_ids_from_dir(directory, refresh_time: int = 0):
+    refresh_time = refresh_time * 86400
+    start_time = int(time.time())
+    ids = []
+    for (dir_path, dir_names, file_names) in os.walk(directory):
+        for entry in file_names:
+            modify_time = int(os.path.getmtime(dir_path + '/' + entry))
+            if (start_time - modify_time) > refresh_time:
+                ids.append(str(entry).replace('_', '/'))
+        # do not read subdirs
+        break
+    # insert cleanup here (filter unwanted names, chars, etc...)
+    return ids
+
+
+# read list of sub directories from directory (PIDs) (don't anything)
+def get_subdirs_from_dir(base_dir):
+    sub_dirs = []
+    for (dir_path, sub_dirs, filenames) in os.walk(base_dir):
+        break
+    # insert cleanup here (filter unwanted names, chars, etc...)
+    return sub_dirs
+
+
+# read list of IOS/IOSXE Versions from directory (don't change to uppercase)
+def get_version_from_dir(directory):
+    versions = []
+    for (dir_path, dir_names, file_names) in os.walk(directory):
+        for entry in file_names:
+            versions.append(str(entry))
+        # do not read subdirs
+        break
+    # insert cleanup here (filter unwanted names, chars, etc...)
+    return versions
+
+
+# delete (P)IDs or SERIALs files from directory (requests)
+def remove_ids_from_dir(ids, directory):
+    for entry in ids:
+        try:
+            os.remove(directory + entry.replace('/', '_'))
+        except OSError:
+            pass
+
+
+# remove (P)IDs or SERIALs from list of (P)ID or serials
+def remove_ids_from_list(ids, directory):
+    known_ids = []
+    for (dir_path, dir_names, file_names) in os.walk(directory):
+        known_ids.extend(file_names)
+        # do not read subdirs
+        break
+
+    for known_id in known_ids:
+        known_id = known_id.replace('_', '/')
+        for entry in ids:
+            if known_id == entry:
+                ids.remove(entry)
+    return ids
+
+
+# returns al list of ids to refresh,
+# expects a directory with ids to check, the time interval, a list of IDs to add
+# if remove True it will delete the ID files from refresh_dir
+def refresh_ids_from_dir(refresh_dir, refresh_time, ids, remove):
+    refresh_dir = expand_path(refresh_dir)
+    # get seconds from # of days (days * 24 * 60 * 60 --> days * 86400)
+    refresh_time = int(refresh_time) * 86400
+    start_time = int(time.time())
+    refresh_ids = get_ids_from_dir(refresh_dir)
+    if refresh_ids is not []:
+        for entry in refresh_ids:
+            modify_time = int(os.path.getmtime(refresh_dir + entry.replace('/', '_')))
+            if (start_time - modify_time) > refresh_time:
+                ids.append(entry)
+                if remove:
+                    try:
+                        os.remove(refresh_dir + entry.replace('/', '_'))
+                    except OSError:
+                        pass
+    return ids
+
+
+# check if dir exists, if not try to create it.
+# return True if dir exists or creation was ok.
+# return False if dir not exists and creation was not ok
+def check_dir_and_create(directory):
+    directory = os.path.dirname(directory)
+    if not os.path.exists(directory):
+        try:
+            os.makedirs(directory)
+        except:
+            return False
+    return True
+
+
+# expand homedir and add '/' if necessary and create directory if it not exists
+def expand_path(path):
+    homedir = os.path.expanduser('~')
+
+    if path.startswith('~'):
+        path = homedir + path[1:]
+
+    if not path.endswith('/'):
+        path += '/'
+
+    if not check_dir_and_create(path):
+        return ''
+
+    return path
+
+# needs to be moved out of cisco_live_cycle_utils
+#  get cisco product series by pid
+# def get_cisco_product_series_by_pid(pids, access_token, settings: Settings):
+#
+#     conf_file = '~/etc/ciscoapi/ciscoapi.json'
+#     conf_file = os.path.expanduser(conf_file)
+#
+#     productseriesfile = '~/var/ciscoapi/productinfo'
+#     product_series = {}
+#
+#     if os.path.isfile(conf_file):
+#         with open(conf_file) as f:
+#             try:
+#                 config = json.load(f)
+#                 productseriesfile = config['productinfo'].get('productseriesfile', productseriesfile)
+#             except ValueError as e:
+#                 log_message(f'snmp_cisco_eox:status:JSON load error: {e}', level='WARNING')
+#
+#     productseriesfile = expand_path(productseriesfile) + 'productseries.json'
+#
+#     if os.path.isfile(productseriesfile):
+#         with open(productseriesfile) as f:
+#             product_series = json.load(f)
+#
+#     requestpids = copy.deepcopy(pids)
+#     if product_series != {}:
+#         keys = product_series.keys()
+#         for pid in requestpids:
+#             if pid in keys:
+#                 requestpids.remove(pid)
+#
+#     if requestpids is not []:
+#         product_infos = get_product_mdf_information_by_pid(pids, access_token, settings=settings)
+#
+#         for entry in product_infos:
+#             product_series.update({entry.get('product_id'): entry.get('product_series')})
+#
+#     with open(productseriesfile, 'w') as f:
+#         json.dump(product_series, f)
+#
+#     return_product_series = {}
+#     for pid in pids:
+#         return_product_series.update({pid: product_series.get(pid, 'not found')})
+#
+#     return return_product_series
+
+
+# remove empty directories
+def remove_empty_sub_dirs(base_dir):
+    subdirs = get_subdirs_from_dir(base_dir)
+    for subdir in subdirs:
+        try:
+            os.rmdir(base_dir + subdir)
+        except OSError as e:
+            log_message(f'can not delete: {base_dir}, Error:{e}')
+            pass
+
+
+# move contents of source_dir to destination_dir
+# only one level deep, lave source_dir
+def move_dir(source_dir, destination_dir, **kwargs):
+    refresh_time = int(kwargs.get('refresh_time', 0)) * 86400
+    starttime = int(time.time())
+
+    sub_dirs = get_subdirs_from_dir(source_dir)
+    for sub_dir in sub_dirs:
+        files = get_ids_from_dir(source_dir + sub_dir)
+        if len(files) > 0:
+            source_path = expand_path(source_dir + sub_dir)
+            destination_path = expand_path(destination_dir + sub_dir)
+            for file in files:
+                source_file = source_path + file
+                destination_file = destination_path + file
+                modify_time = int(os.path.getmtime(source_file))
+                if (starttime - modify_time) > refresh_time:
+                    try:
+                        os.rename(source_file, destination_file)  # rename (move) contents of not_found to request
+                    except OSError as e:
+                        log_message(message=f'error:{e}, source: {source_file}, destionation: {destination_file}',
+                                    level='ERROR')
+
+    remove_empty_sub_dirs(source_dir)
diff --git a/bin/ciscoapi/ciscoapi.py b/bin/ciscoapi/ciscoapi.py
index 4232b96..133c77e 100755
--- a/bin/ciscoapi/ciscoapi.py
+++ b/bin/ciscoapi/ciscoapi.py
@@ -11,157 +11,208 @@
 # 2018-09-25: performance improvement "psirt_response.encoding = 'UTF-8'", drops json.loads
 #             from about 4 min to some seconds
 # 2021-07-23: rewritten for python 3.8
+# 2023-06-09: changed for new rest api endpoint (apix.cisco.com)
+#             refactoring get_token and settings
+#             some cleanup
+#
+# supportapis[dash]help[at]cisco[dot]com
 #
 import requests
 import json
 import time
-import logging
-from os.path import isfile
-from os.path import expanduser
-import urllib
-import sys
-
-# global variables
-g_client_id = ''
-g_client_secret = ''
-g_proxies = {}
-g_use_system_proxies = True
-g_useauthproxy = False
-g_client_fqdn = ''
-g_root_cert = True
-g_authproxyurl = 'https://cmk.bech-noc.de/api/cauthproxy.py'
-
-
-def read_config():
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
-    # define global variables
-    global g_client_id
-    global g_client_secret
-    global g_proxies
-    global g_use_system_proxies
-    global g_useauthproxy
-    global g_client_fqdn
-    global g_root_cert
-    global g_authproxyurl
-
-    # read parameters from config file
-    conf_file = '~/etc/ciscoapi/ciscoapi.json'
-    conf_file = expanduser(conf_file)
-
-    if isfile(conf_file):
+from os.path import (
+    expanduser,
+)
+from typing import Dict, List
+from cisco_live_cycle_utils import (
+    log_message,
+)
+
+
+class Settings:
+    def __init__(self):
+        conf_file = '~/etc/ciscoapi/ciscoapi.json'
+        conf_file = expanduser(conf_file)
+
         with open(conf_file) as f:
             try:
-                config = json.load(f)
+                self.__settings = json.load(f)
             except ValueError as e:
-                logging.warning(f'snmp_cisco_eox:status:JSON load error: {e}')
+                log_message(f'snmp_cisco_eox:status:JSON load error: {e}', level='WARNING')
+                exit()
+            except FileNotFoundError as e:
+                log_message(f'Config file not found {e}.', level='CRITICAL')
                 exit()
 
-        g_client_id = config['cisco_api']['client_id']
-        g_client_secret = config['cisco_api']['client_secret']
-        if config['global'].get('http_proxy'):
-            g_proxies.update({'http': config['global'].get('http_proxy')})
-        if config['global'].get('https_proxy'):
-            g_proxies.update({'https': config['global'].get('https_proxy')})
-        g_use_system_proxies = (config['global'].get('use_system_proxies', False))
-        # parameters for authproxy
-        g_useauthproxy = config['cisco_api']['useauthproxy']
-        if g_useauthproxy:
-            g_client_fqdn = config['cisco_api'].get('client_fqdn')
-            g_root_cert = config['cisco_api'].get('root_cert')
-            g_authproxyurl = config['cisco_api'].get('authproxyurl')
-    else:
-        logger.critical('Config file not found (%s).' % conf_file)
-        return False
-
-    #if g_proxies == {}:
-    #    if g_use_system_proxies:
-    #        g_proxies = urllib.getproxies()
-
-    return True
-
-
-# Request Cisco API access token, token is valid for 1 hour (by default)
-def get_access_token():
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
-    # define global variables
-    global g_client_id
-    global g_client_secret
-    global g_proxies
-    global g_useauthproxy
-    global g_client_fqdn
-    global g_root_cert
-    global g_authproxyurl
-
-    # define local variables
-    access_token = ''
-    lifetime = 0
-    grant_type = 'client_credentials'
-    authheaders = {'content-Type': 'application/x-www-form-urlencoded', 'accept': 'application/json'}
-    authurl = 'https://cloudsso.cisco.com/as/token.oauth2'
-    param_missing = False
-    verify = True
-
-    if read_config():
-        if g_client_id == '':
-            logging.critical('Option client_id missing.')
-            param_missing = True
-        if g_client_secret == '':
-            logging.critical('Option client_secret missing.')
-            param_missing = True
-        # parameters for authproxy
-        if g_useauthproxy:
-            # if not g_root_cert:
-            #     g_root_cert = expanduser(g_root_cert)
-            #     if not isfile(g_root_cert):
-            #         logging.critical('Root Cert not found: %s' % g_root_cert)
-            #         param_missing = True
-            if g_authproxyurl == '':
-                logging.critical('Option authproxyurl missing')
-                param_missing = True
-
-    else:
-        return {'access_token': access_token, 'lifetime': lifetime}
-
-    if param_missing:
-        return {'access_token': access_token, 'lifetime': lifetime}
-
-    authreqdata = {'client_id': g_client_id, 'client_secret': g_client_secret, 'grant_type': grant_type}
-
-    # Disable invalid certificate warnings.
-    # requests.packages.urllib3.disable_warnings()
-
-    # modify request if we use an authentication proxy
-    if g_useauthproxy:
-        if g_client_fqdn != '':
-            authreqdata.update({'client_fqdn': g_client_fqdn})
-        verify = g_root_cert
-        authurl = g_authproxyurl
-
-    logger.debug('auth request: authurl=%s headers=%s data=%s proxies=%s verify=%s' % (authurl, authheaders, authreqdata, g_proxies, verify))
-    response = requests.post(authurl, headers=authheaders, data=authreqdata, proxies=g_proxies, verify=verify)
-
-    logger.debug('response.text: %s' % response.text)
-    if response.ok:
-        authresponse = json.loads(response.text)
-        access_token = authresponse.get("access_token")
-        # access_token = access_token.decode('ascii')
-        lifetime = int(authresponse.get("expires_in"))
+        self.__base_path = '~/var/ciscoapi'
+        self.__auth_proxy_url = 'https://cmk.bech-noc.de/api/cauthproxy.py'
+        self.__proxies = {}
+        self.__wait_after_start = True
+        self.__max_wait_time = 15
+        self.__log_level = 'warning'
+        self.__eox_refresh_known = 31
+        self.__eox_refresh_unknown = 7
+        self.__sn2info_refresh_covered = 31
+        self.__sn2info_refresh_not_covered = 7
+        self.__bug_refresh_found = 2
+        self.__bug_refresh_not_found = 1
+        self.__psirt_refresh_found = 1
+        self.__psirt_refresh_not_found = 1
+        self.__suggestion_refresh_found = 31
+        self.__suggestion_refresh_not_found = 7
+
+        if self.__settings['global'].get('http_proxy'):
+            self.__proxies .update({'http': self.__settings['global'].get('http_proxy')})
+        if self.__settings['global'].get('https_proxy'):
+            self.__proxies .update({'https': self.__settings['global'].get('https_proxy')})
+
+    @property
+    def client_id(self) -> str:
+        return self.__settings['cisco_api']['client_id']
+
+    @property
+    def client_secret(self) -> str:
+        return self.__settings['cisco_api']['client_secret']
+
+    @property
+    def proxies(self) -> Dict[str, str]:
+        return self.__proxies
+
+    @property
+    def use_system_proxies(self) -> bool:
+        return self.__settings['global'].get('use_system_proxies', False)
+
+    @property
+    def use_auth_proxy(self) -> bool:
+        return self.__settings['cisco_api'].get('use_auth_proxy', False)
+
+    @property
+    def client_fqdn(self) -> str:
+        return self.__settings['cisco_api'].get('client_fqdn')
+
+    @property
+    def root_cert(self) -> bool:
+        return self.__settings['cisco_api'].get('root_cert', False)
+
+    @property
+    def auth_proxy_url(self) -> str:
+        return self.__settings['cisco_api'].get('auth_proxy_url')
+
+    @property
+    def base_path(self) -> str:
+        return self.__settings['global'].get('base_path', self.__base_path)
+
+    @property
+    def wait_after_start(self) -> bool:
+        return self.__settings['global'].get('wait_after_start', self.__wait_after_start)
+
+    @property
+    def max_wait_time(self) -> int:
+        return self.__settings['global'].get('max_wait_time', self.__max_wait_time)
+
+    @property
+    def log_level(self) -> str:
+        return self.__settings['global'].get('log_level', self.__log_level)
+
+    @property
+    def eox_refresh_known(self) -> int:
+        return self.__settings['eox'].get('refresh_known', self.__eox_refresh_known)
+
+    @property
+    def eox_refresh_unknown(self) -> int:
+        return self.__settings['eox'].get('refresh_known', self.__eox_refresh_unknown)
+
+    @property
+    def sn2info_refresh_covered(self) -> int:
+        return self.__settings['sn2info'].get('refresh_covered', self.__sn2info_refresh_covered)
+
+    @property
+    def sn2info_refresh_not_covered(self) -> int:
+        return self.__settings['sn2info'].get('refresh_not_covered', self.__sn2info_refresh_not_covered)
+
+    @property
+    def bug_refresh_found(self) -> int:
+        return self.__settings['bug'].get('refresh_found', self.__bug_refresh_found)
+
+    @property
+    def bug_refresh_not_found(self) -> int:
+        return self.__settings['bug'].get('refresh_found', self.__bug_refresh_not_found)
+
+    @property
+    def psirt_refresh_found(self) -> int:
+        return self.__settings['psirt'].get('refresh_found', self.__psirt_refresh_found)
+
+    @property
+    def psirt_refresh_not_found(self) -> int:
+        return self.__settings['psirt'].get('refresh_not_found', self.__psirt_refresh_not_found)
+
+    @property
+    def suggestion_refresh_found(self) -> int:
+        return self.__settings['suggestion'].get('refresh_found', self.__suggestion_refresh_found)
+
+    @property
+    def suggestion_refresh_not_found(self) -> int:
+        return self.__settings['suggestion'].get('refresh_not_found', self.__suggestion_refresh_not_found)
+
+
+class AccessToken:
+    def __init__(
+            self,
+            client_id: str,
+            client_secret: str,
+    ):
+        self.__client_id = client_id
+        self.__client_secret = client_secret
+        self.__proxies = {}
+        self.__use_auth_proxy = None
+        self.__client_fqdn = ''
+        self.__root_cert = True
+        self.__auth_proxy_url = 'https://cmk.bech-noc.de/api/cauthproxy.py'
+        self.__access_token = ''
+        self.__lifetime = 0
+        self.__time = 0
+        self.__auth_headers = {
+            'content-Type': 'application/x-www-form-urlencoded',
+            'accept': 'application/json'
+        }
+        self.__grant_type = 'client_credentials'
+        self.__auth_url = 'https://id.cisco.com/oauth2/default/v1/token'
+        self.__verify = True
+        self.__auth_req_data = {
+            'client_id': self.__client_id,
+            'client_secret': self.__client_secret,
+            'grant_type': self.__grant_type
+        }
+
+    @property
+    def token(self) -> str:
+
+        if self.__access_token and time.time() < self.__lifetime:
+            return self.__access_token
+        else:
+            self.__time = time.time()
+            response = requests.post(
+                self.__auth_url,
+                headers=self.__auth_headers,
+                data=self.__auth_req_data,
+                proxies=self.__proxies,
+                verify=self.__verify)
 
-    return {'access_token': access_token, 'lifetime': lifetime}
+        if response.ok:
+            auth_response = json.loads(response.text)
+            self.__lifetime = self.__time + int(auth_response.get("expires_in")) - 60
+            self.__access_token = auth_response.get("access_token")
+            return self.__access_token
 
 
 # generic cisco api request for all get info by serialnumber
-def get_info_by_serials(serials, access_token, requrl, max_serials):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
-    # define global variables
-    global g_proxies
-
+def get_info_by_serials(
+        serials: List[str],
+        access_token: AccessToken,
+        req_url: str,
+        max_serials: int,
+        settings: Settings
+):
     # locale variablen
     max_serial_length = 40
     max_req_per_second = 5
@@ -171,9 +222,6 @@ def get_info_by_serials(serials, access_token, requrl, max_serials):
     count = 1
     info = []
 
-    # read config, we need only the proxies
-    read_config()
-
     # split list of Serials in chunks of max 75 serials, each max 40 bytes length
     for serial in serials:
         if len(serial) <= max_serial_length:
@@ -185,32 +233,26 @@ def get_info_by_serials(serials, access_token, requrl, max_serials):
             count = 1
     optimisedserials.append(serialsstr[:-1])
 
-    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token}
+    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token.token}
 
     count = 0
     for serials in optimisedserials:
         # Disable invalid certificate warnings.
         # requests.packages.urllib3.disable_warnings()
-        apiresponse = requests.get(requrl + serials, headers=headers, proxies=g_proxies)
+        response = requests.get(req_url + serials, headers=headers, proxies=settings.proxies)
         count += 1
         # only 5 request per second are allowed
         if count == max_req_per_second:
             time.sleep(wait_time)
             count = 0
-        if apiresponse.ok:
-            apiresponse.encoding = 'UTF-8'
-            info.append(json.loads(apiresponse.text))
+        if response.ok:
+            response.encoding = 'UTF-8'
+            info.append(json.loads(response.text))
 
     return info
 
 
-def get_eox_by_pid(pids, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
-    # define global variables
-    global g_proxies
-
+def get_eox_by_pid(pids: List[str], access_token: AccessToken, settings: Settings):
     # local variables
     max_pid_length = 240
     max_pids = 20
@@ -221,9 +263,6 @@ def get_eox_by_pid(pids, access_token):
     count = 1
     eoxr = []
 
-    # read config, we need only the proxies
-    read_config()
-
     # split list of PIDs in chunks of max 240 bytes length
     for pid in pids:
         if (len(pidstr) + len(pid)) < max_pid_length:
@@ -234,15 +273,14 @@ def get_eox_by_pid(pids, access_token):
             pidstr = ''
             count = 1
     optimisedpids.append(pidstr[:-1])
-
-    headers = {'accept': 'application/json', 'Authorization': f'Bearer {access_token}'}
-    requrl = 'https://api.cisco.com/supporttools/eox/rest/5/EOXByProductID/1/'
+    headers = {'accept': 'application/json', 'Authorization': f'Bearer {access_token.token}'}
+    req_url = 'https://apix.cisco.com/supporttools/eox/rest/5/EOXByProductID/1/'
 
     count = 0
     for productids in optimisedpids:
         # Disable invalid certificate warnings.
         # requests.packages.urllib3.disable_warnings()
-        eoxresponse = requests.get(requrl + productids, headers=headers, proxies=g_proxies)
+        eoxresponse = requests.get(req_url + productids, headers=headers, proxies=settings.proxies)
         count += 1
         # only 5 request per second are allowed
         if count == max_req_per_second:
@@ -253,181 +291,108 @@ def get_eox_by_pid(pids, access_token):
     return eoxr
 
 
-def get_eox_by_serials(serials, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
+def get_eox_by_serials(serials: List[str], access_token: AccessToken, settings: Settings):
     max_serials = 20
-    requrl = 'https://api.cisco.com/supporttools/eox/rest/5/EOXBySerialNumber/1/'
-    info = get_info_by_serials(serials, access_token, requrl, max_serials)
-    return info
-
-
-def get_coverage_status_by_serials(serials, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-    max_serials = 75
-    requrl = 'https://api.cisco.com/sn2info/v2/coverage/status/serial_numbers/'
-    info = get_info_by_serials(serials, access_token, requrl, max_serials)
+    req_url = 'https://apix.cisco.com/supporttools/eox/rest/5/EOXBySerialNumber/1/'
+    info = get_info_by_serials(serials, access_token, req_url, max_serials, settings)
     return info
 
 
-def get_coverage_summary_by_serials(serials, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
+def get_coverage_summary_by_serials(serials: List[str], access_token: AccessToken, settings: Settings):
     max_serials = 75
-    requrl = 'https://api.cisco.com/sn2info/v2/coverage/summary/serial_numbers/'
-    info = get_info_by_serials(serials, access_token, requrl, max_serials)
+    req_url = 'https://apix.cisco.com/sn2info/v2/coverage/summary/serial_numbers/'
+    info = get_info_by_serials(serials, access_token, req_url, max_serials, settings)
     return info
 
 
-def get_orderable_pid_by_serials(serials, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-    max_serials = 75
-    requrl = 'https://api.cisco.com/sn2info/v2/identifiers/orderable/serial_numbers/'
-    info = get_info_by_serials(serials, access_token, requrl, max_serials)
-    return info
-
-
-def get_owner_coverage_status_by_serials(serials, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-    max_serials = 75
-    requrl = 'https://api.cisco.com/sn2info/v2/coverage/owner_status/serial_numbers/'
-    info = get_info_by_serials(serials, access_token, requrl, max_serials)
-    return info
-
-
-def get_psirt_by_ios_version(psirtios, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
+def get_psirt_by_ios_version(psirtios: List[str], access_token: AccessToken, settings: Settings):
     info = []
 
-    # read config, we need only the proxies
-    read_config()
-
-    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token}
-    requrl = 'https://api.cisco.com/security/advisories/ios?version='
+    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token.token}
+    req_url = 'https://apix.cisco.com/security/advisories/ios?version='
 
     # requests.packages.urllib3.disable_warnings()
-    if list(psirtios) != []:
+    if list(psirtios) is not []:
         for ios_version in psirtios:
-            logger.debug('request          ios_version: %s, time: %s' % (ios_version, time.asctime(time.localtime(time.time()))))
-            psirt_response = requests.get(requrl + ios_version, headers=headers, proxies=g_proxies)
+            log_message('request ios_version: %s, time: %s' % (ios_version, time.asctime(time.localtime(time.time()))))
+            psirt_response = requests.get(req_url + ios_version, headers=headers, proxies=settings.proxies)
             if psirt_response.ok:
-                logger.debug('ok               ios_version: %s, time: %s, len: %s' % (ios_version, time.asctime(time.localtime(time.time())), len(str(psirt_response))))
-                psirt_response.encoding = 'UTF-8'  # makes json.loads() mutch more faster (from 4 min. down to 1 sec for about 2MB)
+                log_message(
+                    f'ok. ios_version: {ios_version}, '
+                    f'time: {time.asctime(time.localtime(time.time()))}, '
+                    f'len: {len(str(psirt_response))}'
+                )
+                # makes json.loads() mutch more faster (from 4 min. down to 1 sec for about 2MB)
+                psirt_response.encoding = 'UTF-8'
                 response = (json.loads(psirt_response.text))
-                logger.debug('response loaded: ios_version: %s, time: %s, len: %s' % (ios_version, time.asctime(time.localtime(time.time())), len(str(response))))
+                log_message(
+                    f'response loaded: ios_version: {ios_version}, '
+                    f'time: {time.asctime(time.localtime(time.time()))}, '
+                    f'len: {len(str(response))}'
+                )
                 info.append({'version': ios_version, 'advisories': response.get('advisories', 'notfound')})
-                logger.debug('ciscoapi:psirt-ios-found: %s' % info)
+                log_message('ciscoapi:psirt-ios-found: %s' % info)
             else:
-                logger.debug('notfound         ios_version: %s, time: %s, len: %s' % (ios_version, time.asctime(time.localtime(time.time())), len(str(psirt_response))))
+                log_message(
+                    f'notfound. ios_version: {ios_version}, '
+                    f'time: {time.asctime(time.localtime(time.time()))}, '
+                    f'len: {len(str(psirt_response))}'
+                )
                 info.append({'version': ios_version, 'advisories': 'notfound'})
-                logger.debug('ciscoapi:psirt-ios-notfound: %s' % info)
+                log_message('ciscoapi:psirt-ios-notfound: %s' % info)
     return info
 
 
-def get_psirt_by_iosxe_version(psirtios, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
+def get_psirt_by_iosxe_version(psirtios: List[str], access_token: AccessToken, settings: Settings):
     info = []
 
-    # read config, we need only the proxies
-    read_config()
-
-    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token}
-    requrl = 'https://api.cisco.com/security/advisories/iosxe?version='
+    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token.token}
+    req_url = 'https://apix.cisco.com/security/advisories/iosxe?version='
 
     # requests.packages.urllib3.disable_warnings()
-    if list(psirtios) != []:
+    if list(psirtios) is not []:
         for ios_version in psirtios:
-            psirt_response = requests.get(requrl + ios_version, headers=headers, proxies=g_proxies)
+            psirt_response = requests.get(req_url + ios_version, headers=headers, proxies=settings.proxies)
             if psirt_response.ok:
                 psirt_response.encoding = 'UTF-8'
                 response = (json.loads(psirt_response.text))
                 info.append({'version': ios_version, 'advisories': response.get('advisories', 'notfound')})
-                logger.debug('ciscoapi:psirt-iosxe-found: %s' % info)
+                log_message(f'ciscoapi:psirt-iosxe-found: {info}')
             else:
                 info.append({'version': ios_version, 'advisories': 'notfound'})
-                logger.debug('ciscoapi:psirt-iosxe-notfound: %s' % info)
+                log_message(f'ciscoapi:psirt-iosxe-notfound: {info}')
     return info
 
 
-def get_psirt_by_product_family(families, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
+def get_psirt_by_product_family(families: List[str], access_token: AccessToken, settings: Settings):
     info = []
-    # read config, we need only the proxies
-    read_config()
 
-    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token}
-    requrl = 'https://api.cisco.com/security/advisories/cvrf/product?product='
+    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token.token}
+    req_url = 'https://apix.cisco.com/security/advisories/cvrf/product?product='
 
     # requests.packages.urllib3.disable_warnings()
-    if list(families) != []:
-
+    if list(families) is not []:
         for family in families:
-            psirt_response = requests.get(requrl + family, headers=headers, proxies=g_proxies)
+            psirt_response = requests.get(req_url + family, headers=headers, proxies=settings.proxies)
             if psirt_response.ok:
                 psirt_response.encoding = 'UTF-8'
                 response = (json.loads(psirt_response.text))
                 info.append({'family': family, 'advisories': response.get('advisories', 'notfound')})
-                logger.debug('ciscoapi:psirt-family-found: %s' % info)
+                log_message('ciscoapi:psirt-family-found: %s' % info)
             else:
                 info.append({'family': family, 'advisories': 'notfound'})
-                logger.debug('ciscoapi:psirt-family-notfound: %s' % info)
+                log_message('ciscoapi:psirt-family-notfound: %s' % info)
     return info
 
 
-def get_suggested_image_and_release_by_pid(pids, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
-    info = []
-
-    # read config, we need only the proxies
-    read_config()
-
-    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token}
-    # requrl = 'https://api.cisco.com/software/suggestion/v1.0/suggestions/productid/'
-    requrl = 'https://api.cisco.com/software/suggestion/v2/suggestions/software/productIds/'
-
-    # requests.packages.urllib3.disable_warnings()
-    if list(pids) != []:
-        for pid in pids:
-            suggestion_response = requests.get(requrl + pid, headers=headers, proxies=g_proxies)
-            if suggestion_response.ok:
-                suggestion_response.encoding = 'UTF-8'
-                response = (json.loads(suggestion_response.text))
-                logger.debug('cisco-api:get_suggested_image_and_release_by_pid:response: %s' % response)
-                info.append({'pid': pid, 'suggetion': response.get('advisories', 'notfound')})
-                logger.debug('ciscoapi:info-found: %s' % info)
-            else:
-                info.append({'pid': pid, 'advisories': 'notfound'})
-                logger.debug('ciscoapi:info-notfound: %s' % info)
-    return info
-
-
-def get_suggested_release_by_pid(pids, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
+def get_suggested_release_by_pid(pids: List[str], access_token: AccessToken, settings: Settings):
     max_pid_length = 240
     max_pids = 10
-    max_req_per_second = 5
-    wait_time = 5
     optimisedpids = []
     pidstr = ''
     count = 1
     info = []
 
-    # read config, we need only the proxies
-    read_config()
-
     # split list of PIDs in chunks of max 240 bytes length
     for pid in pids:
         if (len(pidstr) + len(pid)) < max_pid_length:
@@ -439,32 +404,24 @@ def get_suggested_release_by_pid(pids, access_token):
             count = 1
     optimisedpids.append(pidstr[:-1])
 
-    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token}
-    # requrl = 'https://api.cisco.com/software/suggestion/v1.0/suggestions/releases/'
-    requrl = 'https://api.cisco.com/software/suggestion/v2/suggestions/releases/productIds/'
+    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token.token}
+    req_url = 'https://apix.cisco.com/software/suggestion/v2/suggestions/releases/productIds/'
 
     # requests.packages.urllib3.disable_warnings()
-    if optimisedpids != []:
+    if optimisedpids is not []:
         for productids in optimisedpids:
-            suggestion_response = requests.get(requrl + productids, headers=headers, proxies=g_proxies)
-            logger.debug('cisco-api:get_sugessted_release_by_pid:response:response.text %s' % suggestion_response.text)
+            suggestion_response = requests.get(req_url + productids, headers=headers, proxies=settings.proxies)
+            log_message('cisco-api:get_sugessted_release_by_pid:response:response.text %s' % suggestion_response.text)
             if suggestion_response.ok:
                 suggestion_response.encoding = 'UTF-8'
                 response = (json.loads(suggestion_response.text))
-                logger.debug('cisco-api:get_suggested_release_by_pid:response: %s' % response)
+                log_message('cisco-api:get_suggested_release_by_pid:response: %s' % response)
                 info.append(response.get('productList', 'notfound'))
-                logger.debug('ciscoapi:info-found: %s' % info)
+                log_message('ciscoapi:info-found: %s' % info)
 
     return info
 
 
-def get_sugessted_compatible_release_by_pid(pids, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
-    return
-
-
 # get_clean_sn_for_bug_api('ASA5510', '9.1(7)15,8.4(7)30,9.1(6)1')
 # return {'9.1(7)15': '9.1(7.15)', '9.1(6)1': '9.1(6.1)', '8.4(7)30': '8.4(7.30)'}
 def get_clean_sn_for_bug_api(pid, software_releases):
@@ -525,22 +482,21 @@ def get_clean_sn_for_bug_api(pid, software_releases):
     return clean_sns
 
 
-def get_bug_by_pid_and_release(pid, release, access_token, reqoptions):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
+def get_bug_by_pid_and_release(pid, release, access_token: AccessToken, reqoptions, settings: Settings):
     info = []
 
-    # read config, we need only the proxies
-    read_config()
-    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token}
-    requrl = 'https://api.cisco.com/bug/v2.0/bugs/products/product_id/'
+    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token.token}
+    req_url = 'https://apix.cisco.com/bug/v2.0/bugs/products/product_id/'
 
     if release != '':
         software_releases = get_clean_sn_for_bug_api(pid, release)
         clean_sn = ','.join(software_releases.values())
         missing = {}
-        bug_response = requests.get(requrl + '%s/software_releases/%s%s' % (pid, clean_sn, reqoptions), headers=headers, proxies=g_proxies)
+        bug_response = requests.get(
+            url=req_url + f'{pid}/software_releases/{clean_sn}{reqoptions}',
+            headers=headers,
+            proxies=settings.proxies
+        )
         if bug_response.ok:
             bug_response.encoding = 'UTF-8'
             response = (json.loads(bug_response.text))
@@ -548,7 +504,8 @@ def get_bug_by_pid_and_release(pid, release, access_token, reqoptions):
             pagination_record = response.get('pagination_response_record')
             last_page = int(pagination_record.get('last_index'))
             total_records = int(pagination_record.get('total_records'))
-            logger.info('PID: %s, Version: %s, Total records: %s, Pages: %s' % (pid, clean_sn, total_records, last_page))
+            log_message(message=f'PID: {pid}, Version: {clean_sn}, Total records: {total_records}, Pages: {last_page}',
+                        level='INFO')
             if last_page > 1:
                 if reqoptions != '':
                     reqoptions = reqoptions + '&page_index='
@@ -557,7 +514,8 @@ def get_bug_by_pid_and_release(pid, release, access_token, reqoptions):
                 for page in range(2, last_page + 1):
                     # time.sleep(2)
                     page_options = reqoptions + '%s' % page
-                    bug_response = requests.get(requrl + '%s/software_releases/%s%s' % (pid, clean_sn, page_options), headers=headers, proxies=g_proxies)
+                    bug_response = requests.get(req_url + f'{pid}/software_releases/{clean_sn}{page_options}',
+                                                headers=headers, proxies=settings.proxies)
                     if bug_response.ok:
                         response = (json.loads(bug_response.text))
                         bug_list += response.get('bugs')
@@ -567,7 +525,9 @@ def get_bug_by_pid_and_release(pid, release, access_token, reqoptions):
                         reason = bug_response.reason
                         url = bug_response.url
                         text = bug_response.text
-                        logging.warning('ciscoapi error: %s, %s, Page: %s, LastPage: %s, URL: \'%s\'. Text: \'%s\'' % (status_code, reason, page, last_page, url, text))
+                        log_message(message=f'ciscoapi error: {status_code}, {reason}, Page: {page}, LastPage: '
+                                            f'{last_page}, URL: \'{url}\'. Text: \'{text}\'',
+                                    level='WARNING')
                         missing.update({page: {'status_code': status_code,
                                                'reason': reason,
                                                'url': url,
@@ -577,7 +537,7 @@ def get_bug_by_pid_and_release(pid, release, access_token, reqoptions):
                          'bugs': bug_list,
                          'total_records': total_records,
                          'missing': missing})
-            logger.debug('ciscoapi:bug-found: %s' % info)
+            log_message('ciscoapi:bug-found: %s' % info)
         else:
             bug_response.encoding = 'UTF-8'
             status_code = bug_response.status_code
@@ -585,7 +545,7 @@ def get_bug_by_pid_and_release(pid, release, access_token, reqoptions):
             url = bug_response.url
             text = bug_response.text
             page = 'ALL'
-            logging.warning('ciscoapi error: %s, %s, URL: \'%s\'. Text: \'%s\'' % (status_code, reason, url, text))
+            log_message(f'ciscoapi error: {status_code}, {reason}, URL: \'{url}\'. Text: \'{text}\'', level='WARNING')
             missing.update({page: {'status_code': status_code,
                                    'reason': reason,
                                    'url': url,
@@ -598,54 +558,14 @@ def get_bug_by_pid_and_release(pid, release, access_token, reqoptions):
     return info
 
 
-def get_bug_by_productseries_and_affected_release(ps_release, access_token, reqoptions):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
-    info = []
-
-    # read config, we need only the proxies
-    read_config()
-    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token}
-    requrl = 'https://api.cisco.com/bug/v2.0/bugs/product_series/'
-
-    if len(ps_release.keys()) > 0:
-        for product_series in ps_release.keys():
-            affected_releases = ps_release.get(product_series).split(',')
-            for affected_release in affected_releases:
-                bug_response = requests.get(requrl + '%s/affected_releases/%s%s' % (product_series, affected_release, reqoptions), headers=headers, proxies=g_proxies)
-                if bug_response.ok:
-                    bug_response.encoding = 'UTF-8'
-                    response = (json.loads(bug_response.text))
-                    last_page = int(response.get('pagination_response_record').get('last_index'))
-                    total_records = int(response.get('pagination_response_record').get('total_records'))
-                    logger.debug('Product series: %s, Version: %s, Total records: %s, Pages: %s' % (product_series, affected_release, total_records, last_page))
-
-                    info.append({'produckt_series': product_series, 'affected_releases': affected_releases, 'bugs': response})
-                    logger.debug('ciscoapi:bug-found: %s' % info)
-                else:
-                    info.append({'produckt_series': product_series, 'affected_releases': affected_releases, 'bugs': 'notfound'})
-                    logger.debug('ciscoapi:bug-not-found: %s' % info)
-
-    return info
-
-
-def get_product_mdf_information_by_pid(pids, access_token):
-    # set logg modul name <file>:<module>.<function>
-    logger = logging.getLogger(__file__ + ':' + __name__ + '.' + sys._getframe().f_code.co_name)
-
+def get_product_mdf_information_by_pid(pids, access_token: AccessToken, settings: Settings):
     max_pid_length = 40
     max_pids = 5
-    max_req_per_second = 2
-    wait_time = 5
     optimisedpids = []
     pidstr = ''
     count = 1
     info = []
 
-    # read config, we need only the proxies
-    read_config()
-
     # split list of PIDs in chunks of max 240 bytes length
     for pid in pids:
         if (len(pidstr) + len(pid)) < max_pid_length:
@@ -657,21 +577,23 @@ def get_product_mdf_information_by_pid(pids, access_token):
             count = 1
     optimisedpids.append(pidstr[:-1])
 
-    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token}
-    requrl = 'https://api.cisco.com/product/v1/information/product_ids_mdf/'
-#    requrl = 'https://api.cisco.com/product/v1/information/product_ids/'
+    headers = {'accept': 'application/json', 'Authorization': 'Bearer ' + access_token.token}
+    req_url = 'https://apix.cisco.com/product/v1/information/product_ids_mdf/'
+#    req_url = 'https://apix.cisco.com/product/v1/information/product_ids/'
 
     # requests.packages.urllib3.disable_warnings()
-    if optimisedpids != []:
+    if optimisedpids is not []:
         for productids in optimisedpids:
-            productinfo_response = requests.get(requrl + productids, headers=headers, proxies=g_proxies)
-            logger.debug('cisco-api:get_product_mdf_information_by_pid:response:response.text %s' % productinfo_response.text)
+            productinfo_response = requests.get(req_url + productids, headers=headers, proxies=settings.proxies)
+            log_message(
+                f'cisco-api:get_product_mdf_information_by_pid:response:response.text {productinfo_response.text}'
+            )
             if productinfo_response.ok:
                 productinfo_response.encoding = 'UTF-8'
                 response = (json.loads(productinfo_response.text))
-                logger.debug('cisco-api:get_product_mdf_information_by_pid:response: %s' % response)
+                log_message('cisco-api:get_product_mdf_information_by_pid:response: %s' % response)
                 # info.append(response)
                 info.extend(response.get('product_list', 'notfound'))
-                logger.debug('ciscoapi:info-found: %s' % info)
+                log_message('ciscoapi:info-found: %s' % info)
 
-    return info
\ No newline at end of file
+    return info
diff --git a/gui/views/inv_cisco_livecycle.py b/gui/views/inv_cisco_livecycle.py
new file mode 100644
index 0000000..acca1e3
--- /dev/null
+++ b/gui/views/inv_cisco_livecycle.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2017-08-14
+#
+# CheckMK views for Cisco support APIs (EoX, SN2Info, PSIRT, SUGGESTION)
+#
+# 2021-07-23: rewrite for CMK 2.0
+#             suggestion removed --> table to complicated :-(
+#
+# 2021-07-25: removed inv_cisco_suggestion
+#             rework painter section
+
+import time
+from cmk.gui.plugins.views.inventory import (
+    declare_invtable_view,
+    decorate_inv_paint,
+    PaintResult,
+)
+from cmk.gui.plugins.visuals.inventory import (
+    FilterInvtableText,
+)
+from cmk.gui.i18n import _
+from cmk.gui.plugins.views.utils import (
+    inventory_displayhints,
+)
+from cmk.gui.htmllib import HTML
+
+#
+# to get the status colors and the clickable IDs for EOL, PSIRT and Bug you need to copy the file
+# ~/lib/check_mk/gui/plugins/views/inventory.py  to ~/local/lib/check_mk/gui/plugins/views.
+# Then change the value of ENABLE_PAINTERS to True and restart the apache service (omd restart apache)
+
+ENABLE_PAINTERS = True
+
+# #################################################################################
+#
+# Painter functions START
+#
+
+
+@decorate_inv_paint()
+def inv_paint_date_status(date_string) -> PaintResult:
+
+    warn_days = -90
+    crit_days = -30
+
+    #  check if date_sting not None, if so return no CSS Class and None
+    if date_string is None:
+        return '', ''
+
+    try:
+        days = int((time.time() - time.mktime(time.strptime(date_string, '%Y-%m-%d'))) / 86400)
+    except ValueError:
+        return '', date_string
+
+    if days > crit_days:
+        css_class = 'date_crit'
+    elif days > warn_days:
+        css_class = 'date_warn'
+    else:
+        css_class = 'date_default'
+
+    return css_class, '%s' % date_string
+
+
+@decorate_inv_paint()
+def inv_paint_last_checked_status(date_string) -> PaintResult:
+    warn_days = 32
+    crit_days = 40
+    if date_string is None:
+        return '', ''
+    try:
+        days = int((time.time() - time.mktime(time.strptime(date_string, '%Y-%m-%d'))) / 86400)
+    except ValueError:
+        return '', date_string
+    if days <= warn_days:
+        css_class = ''
+    elif days >= crit_days:
+        css_class = 'date_crit'
+    else:
+        css_class = 'date_warn'
+    return css_class, ' %s' % date_string
+
+
+@decorate_inv_paint()
+def inv_paint_psirt_advisoryid(advisoryId) -> PaintResult:
+    psirt_url = HTML(
+        f'<a class="href_blue" target="_blank" '
+        f'href="https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/{advisoryId}">{advisoryId}</a>')
+    return '', psirt_url
+
+
+@decorate_inv_paint()
+def inv_paint_eox_eolid(eolid) -> PaintResult:
+    if eolid is not None:
+        search_eolid_url = HTML(
+            f'<a class="href_blue" target="_blank" '
+            f'href="https://search.cisco.com/search?query={eolid}">{eolid}</a>')
+    else:
+        search_eolid_url = ''
+    return '', search_eolid_url
+
+
+@decorate_inv_paint()
+def inv_paint_bug_bugid(bugid) -> PaintResult:
+    if bugid is not None:
+        search_bugid_url = HTML(
+            f'<a class="href_blue" target="_blank" '
+            f'href="https://bst.cloudapps.cisco.com/bugsearch/bug/{bugid}">{bugid}</a>')
+    else:
+        search_bugid_url = ''
+    return '', search_bugid_url
+
+
+@decorate_inv_paint()
+def inv_paint_psirt_bugid(bugids) -> PaintResult:
+    search_bugid_url = ''
+    bugids = bugids.split(',')
+    if bugids:
+        search_bugid_url = []
+        for bugid in bugids:
+            bugid = bugid.strip(' ')
+            search_bugid_url.append(f'<a class="href_blue" target="_blank" '
+                                    f'href="https://bst.cloudapps.cisco.com/bugsearch/bug/{bugid}">{bugid}</a>')
+        search_bugid_url = HTML(', '.join(search_bugid_url))
+    return '', search_bugid_url
+
+#
+# Painter functions END
+#
+# #################################################################################
+
+
+# EoX display hints
+inventory_displayhints.update({
+    '.hardware.support': {'title': _('Cisco Live Cycle')},
+    '.hardware.support.cisco_eox:': {
+        'title': _('EoX'),
+        'keyorder':
+            [
+                'pid', 'serial_number', 'ProductIDDescription', 'Last_checked', 'ProductBulletinNumber',
+                'EOXExternalAnnouncementDate', 'EndOfSaleDate', 'LastDateOfSupport', 'EndOfSvcAttachDate',
+                'UpdatedTimeStamp',
+            ],
+        'view': 'invciscoeox_of_host',
+    },
+    '.hardware.support.cisco_eox:*.pid': {'title': _('PID (EoX)'), },
+    '.hardware.support.cisco_eox:*.serial_number': {'title': _('Serial number'), },
+    '.hardware.support.cisco_eox:*.ProductIDDescription': {'title': _('Description'), },
+    '.hardware.support.cisco_eox:*.LinkToProductBulletinURL': {'title': _('EOL bulletin URL'), },
+    '.hardware.support.cisco_eox:*.UpdatedTimeStamp': {'title': _('EOL bulletin last update'), },
+    '.hardware.support.cisco_eox:*.MigrationProductId': {'title': _('Migration PID'), },
+    '.hardware.support.cisco_eox:*.MigrationInformation': {'title': _('Migration information'), },
+    '.hardware.support.cisco_eox:*.MigrationProductInfoURL': {'title': _('Migration PID URL'), },
+    '.hardware.support.cisco_eox:*.MigrationProductName': {'title': _('Migration product name'), },
+})
+
+# SN2Info (contract) display hints
+inventory_displayhints.update({
+    '.hardware.support.cisco_contract:': {
+        'title': _('Contract'),
+        'keyorder': [
+            'pid', 'serial_number', 'ProductIDDescription', 'Last_checked', 'is_covered', 'service_contract_number',
+            'covered_product_line_end_date',
+        ],
+        'view': 'invciscocontract_of_host',
+    },
+    '.hardware.support.cisco_contract:*.pid': {'title': _('PID (contract)'), },
+    '.hardware.support.cisco_contract:*.serial_number': {'title': _('Serial number'), },
+    '.hardware.support.cisco_contract:*.ProductIDDescription': {'title': _('Description'), },
+    '.hardware.support.cisco_contract:*.is_covered': {'title': _('is covered'), },
+    '.hardware.support.cisco_contract:*.contract_site_customer_name': {'title': _('Customer name'), },
+    '.hardware.support.cisco_contract:*.contract_site_address1': {'title': _('Address'), },
+    '.hardware.support.cisco_contract:*.contract_site_city': {'title': _('City'), },
+    '.hardware.support.cisco_contract:*.contract_site_state_province': {'title': _('State/Province'), },
+    '.hardware.support.cisco_contract:*.contract_site_country': {'title': _('Country'), },
+    '.hardware.support.cisco_contract:*.service_line_descr': {'title': _('Service description'), },
+    '.hardware.support.cisco_contract:*.service_contract_number': {'title': _('Contract number'), },
+    '.hardware.support.cisco_contract:*.parent_sr_no': {'title': _('Parent S/N'), },
+    '.hardware.support.cisco_contract:*.warranty_type': {'title': _('Warranty type'), },
+    '.hardware.support.cisco_contract:*.warranty_type_description': {'title': _('Warranty Description'), },
+    '.hardware.support.cisco_contract:*.warranty_end_date': {'title': _('Warranty end date'), },
+})
+
+# BUG display hints
+inventory_displayhints.update({
+    '.software.support.cisco_bug.Total_records': {'title': _('Records total'), },
+    '.software.support.cisco_bug.duplicate_records': {'title': _('Records duplicate'), },
+    '.software.support.cisco_bug.missing_records': {'title': _('Records missing'), },
+    '.software.support.cisco_bug.PID': {'title': _('PID'), },
+    '.software.support.cisco_bug.os_version': {'title': _('OS version'), },
+    '.software.support.cisco_bug.bugs:': {
+        'title': _('Cisco BUG IDs'),
+        'keyorder': [
+            'bug_id', 'severity', 'status', 'last_modified_date', 'headline', 'support_case_count', 'behavior_changed',
+        ],
+        'view': 'invciscobugs_of_host',
+    },
+    '.software.support.cisco_bug.bugs:*.status': {'title': _('Status'), },
+    '.software.support.cisco_bug.bugs:*.product': {'title': _('Product'), },
+    '.software.support.cisco_bug.bugs:*.description': {'title': _('Description'), },
+    '.software.support.cisco_bug.bugs:*.headline': {'title': _('Headline'), },
+    '.software.support.cisco_bug.bugs:*.support_case_count': {'title': _('Support case count'), },
+    '.software.support.cisco_bug.bugs:*.last_modified_date': {'title': _('Last modified date'), },
+    '.software.support.cisco_bug.bugs:*.behavior_changed': {'title': _('Behavior changed'), },
+    '.software.support.cisco_bug.bugs:*.base_pid': {'title': _('Base PID'), },
+    '.software.support.cisco_bug.bugs:*.known_fixed_releases': {'title': _('Known fixed releases'), },
+    '.software.support.cisco_bug.bugs:*.id': {'title': _('ID'), },
+    '.software.support.cisco_bug.bugs:*.known_affected_releases': {'title': _('known affected releases'), },
+    '.software.support.cisco_bug.bugs:*.severity': {'title': _('Severity'), },
+})
+
+# PSIRT display hints
+inventory_displayhints.update({
+    '.software.support.cisco_psirt.dont_show_older_than': {'title': _('Don\'t show advisories not updated since'), },
+    '.software.support.cisco_psirt.dont_show_not_updated_since': {
+        'title': _('Don\'t show advisories not updated for X days'), },
+    '.software.support.cisco_psirt.removed_advisories': {'title': _('Advisories removed'), },
+    '.software.support.cisco_psirt.advisories:': {
+        'title': _('Cisco PSIRT advisories'),
+        'keyorder': [
+            'advisoryId', 'sir', 'cvssBaseScore', 'advisoryTitle',
+        ],
+        'view': 'invciscopsirt_of_host',
+    },
+    '.software.support.cisco_psirt.advisories:*.advisoryTitle': {'title': _('Advisory Title'), },
+    '.software.support.cisco_psirt.advisories:*.cvssBaseScore': {'title': _('CVSS base Score'), },
+    '.software.support.cisco_psirt.advisories:*.firstFixed': {'title': _('First fixed in'), },
+    '.software.support.cisco_psirt.advisories:*.firstPublished': {'title': _('First Published'), },
+    '.software.support.cisco_psirt.advisories:*.installed_version': {'title': _('OS version/family'), },
+    '.software.support.cisco_psirt.advisories:*.lastUpdated': {'title': _('Last Updated'), },
+    '.software.support.cisco_psirt.advisories:*.publicationUrl': {'title': _('Public URL'), },
+    '.software.support.cisco_psirt.advisories:*.sir': {'title': _('Severity'), },
+    '.software.support.cisco_psirt.advisories:*.summary': {'title': _('Summary'), },
+    '.software.support.cisco_psirt.advisories:*.cwe': {'title': _('CWE'), },
+    '.software.support.cisco_psirt.advisories:*.cves': {'title': _('CVEs'), },
+    '.software.support.cisco_psirt.advisories:*.productNames': {'title': _('Product names'), },
+    '.software.support.cisco_psirt.advisories:*.ipsSignatures': {'title': _('IPS signatures')},
+    '.software.support.cisco_psirt.advisories:*.cvrfUrl': {'title': _('CVRF URL')},
+    '.software.support.cisco_psirt.advisories:*.ovalUrl': {'title': _('OVAL URL')},
+    '.software.support.cisco_psirt.os_version': {'title': _('OS version')},
+    '.software.support.cisco_psirt.not_updated_for_x_days': {'title': _('don\'t show advisories not updated for X days')},
+    '.software.support.cisco_psirt.dont_show_older_then': {'title': _('don\'t show advisories not updated after')},
+})
+
+
+if ENABLE_PAINTERS:
+    inventory_displayhints.update({
+        # EoX
+        '.hardware.support.cisco_eox:*.EOXExternalAnnouncementDate': {'title': _('EOL Announcement'), 'paint': 'date_status'},
+        '.hardware.support.cisco_eox:*.EndOfSvcAttachDate': {'title': _('End of service attachment'), 'paint': 'date_status'},
+        '.hardware.support.cisco_eox:*.EndOfSecurityVulSupportDate': {'title': _('End of service vulnerability support'), 'paint': 'date_status'},
+        '.hardware.support.cisco_eox:*.EndOfSWMaintenanceReleases': {'title': _('End of software maintenace releases'), 'paint': 'date_status'},
+        '.hardware.support.cisco_eox:*.EndOfRoutineFailureAnalysisDate': {'title': _('End of routine failure analysis'), 'paint': 'date_status'},
+        '.hardware.support.cisco_eox:*.EndOfSaleDate': {'title': _('End of sale'), 'paint': 'date_status'},
+        '.hardware.support.cisco_eox:*.LastDateOfSupport': {'title': _('End of support'), 'paint': 'date_status'},
+        '.hardware.support.cisco_eox:*.ProductBulletinNumber': {'title': _('EOL bulletin ID'), 'filter': FilterInvtableText,'paint': 'eox_eolid'},
+        '.hardware.support.cisco_eox:*.Last_checked': {'title': _('Last checked'), 'paint': 'last_checked_status'},
+
+        # SN2Info
+        '.hardware.support.cisco_contract:*.Last_checked': {'title': _('Last checked'), 'paint': 'last_checked_status'},
+        '.hardware.support.cisco_contract:*.covered_product_line_end_date': {'title': _('Contract end date'), 'paint': 'date_status'},
+
+        # Bug
+        '.software.support.cisco_bug.bugs:*.bug_id': {'title': _('Bug ID'), 'paint': 'bug_bugid'},
+
+        # Psirt
+        '.software.support.cisco_psirt.advisories:*.advisoryId': {'title': _('Advisory ID'), 'paint': 'psirt_advisoryid'},
+        '.software.support.cisco_psirt.advisories:*.bugIDs': {'title': _('Bug IDs'), 'paint': 'psirt_bugid'},
+        '.software.support.cisco_psirt.Last_checked': {'title': _('Last checked'), 'paint': 'last_checked_status'},
+    })
+else:
+    inventory_displayhints.update(({
+        # EoX
+        '.hardware.support.cisco_eox:*.EOXExternalAnnouncementDate': {'title': _('EOL Announcement')},
+        '.hardware.support.cisco_eox:*.EndOfSvcAttachDate': {'title': _('End of service attachment')},
+        '.hardware.support.cisco_eox:*.EndOfSecurityVulSupportDate': {'title': _('End of service vulnerability support')},
+        '.hardware.support.cisco_eox:*.EndOfSWMaintenanceReleases': {'title': _('End of software maintenace releases')},
+        '.hardware.support.cisco_eox:*.EndOfRoutineFailureAnalysisDate': {'title': _('End of routine failure analysis')},
+        '.hardware.support.cisco_eox:*.EndOfSaleDate': {'title': _('End of sale')},
+        '.hardware.support.cisco_eox:*.LastDateOfSupport': {'title': _('End of support')},
+        '.hardware.support.cisco_eox:*.ProductBulletinNumber': {'title': _('EOL bulletin ID')},
+        '.hardware.support.cisco_eox:*.Last_checked': {'title': _('Last checked'),},
+
+        # SN2Info
+        '.hardware.support.cisco_contract:*.Last_checked': {'title': _('Last checked')},
+        '.hardware.support.cisco_contract:*.covered_product_line_end_date': {'title': _('Contract end date')},
+
+        # Bug
+        '.software.support.cisco_bug.bugs:*.bug_id': {'title': _('Bug ID')},
+
+        # Psirt
+        '.software.support.cisco_psirt.advisories:*.advisoryId': {'title': _('Advisory ID')},
+        '.software.support.cisco_psirt.advisories:*.bugIDs': {'title': _('Bug IDs')},
+        '.software.support.cisco_psirt.Last_checked': {'title': _('Last checked')},
+    }))
+
+
+declare_invtable_view('invciscoeox', '.hardware.support.cisco_eox:', _('Cisco EoX status'), _('Cisco EoX status'))
+declare_invtable_view('invciscocontract', '.hardware.support.cisco_contract:', _('Cisco contract status'), _('Cisco contract status'))
+declare_invtable_view('invciscopsirt', '.software.support.cisco_psirt.advisories:', _('Cisco PSIRT advisories'), _('Cisco PSIRT advisories'))
+declare_invtable_view('invciscobugs', '.software.support.cisco_bug.bugs:', _('Cisco BUG IDs'), _('Cisco Bug IDs'))
diff --git a/gui/wato/inv_cisco_bug.py b/gui/wato/inv_cisco_bug.py
new file mode 100644
index 0000000..c8c6b4d
--- /dev/null
+++ b/gui/wato/inv_cisco_bug.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  :
+#
+# 2021-07-23: rewritten for CMK 2.0
+#
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato.utils import (
+    HostRulespec,
+    rulespec_registry,
+)
+from cmk.gui.valuespec import (
+    Dictionary,
+    ListChoice,
+)
+from cmk.gui.plugins.wato.inventory import (
+    RulespecGroupInventory,
+)
+
+_removecolumns_inv_cisco_bug = [
+    # ('status', 'Status'),
+    ('product', 'Product'),
+    ('description', 'Description'),
+    # ('headline', 'Headline'),
+    # ('support_case_count', 'Support case count'),
+    # ('last_modified_date', 'Last modified date'),
+    # ('behavior_changed', 'Behavior changed'),
+    # ('bug_id', 'Bug ID'),
+    ('base_pid', 'Base PID'),
+    ('known_fixed_releases', 'Known fixed releases'),
+    ('id', 'ID'),
+    ('known_affected_releases', 'known affected releases'),
+    # ('severity', 'Severity'),
+]
+
+
+def _valuespec_inv_cisco_bug():
+    return Dictionary(
+        title=_('Cisco bugs'),
+        elements=[
+            ('removecolumns',
+             ListChoice(
+                 title=_('remove columns'),
+                 help=_('remove information from report'),
+                 choices=_removecolumns_inv_cisco_bug,
+                 default_value=[
+                     'base_pid',
+                     'description',
+                     'id',
+                     'known_affected_releases',
+                     'product',
+                 ],
+             )),
+        ]
+    )
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupInventory,
+        match_type='dict',
+        name='inv_parameters:inv_cisco_bug',
+        valuespec=_valuespec_inv_cisco_bug,
+    ))
diff --git a/gui/wato/inv_cisco_contract.py b/gui/wato/inv_cisco_contract.py
new file mode 100644
index 0000000..55dc4b3
--- /dev/null
+++ b/gui/wato/inv_cisco_contract.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  :
+#
+# 2021-07-23: rewritten for CMK 2.0
+#
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato.utils import (
+    HostRulespec,
+    rulespec_registry,
+)
+from cmk.gui.valuespec import (
+    Dictionary,
+    ListChoice,
+    ListOfStrings,
+)
+from cmk.gui.plugins.wato.inventory import (
+    RulespecGroupInventory,
+)
+
+_removecolumns_inv_cisco_contract = [
+    ('contract_site_address1', 'Address'),
+    ('contract_site_city', 'City'),
+    ('contract_site_country', 'Country'),
+    ('contract_site_customer_name', 'Customer name'),
+    ('parent_sr_no', 'Parent S/N'),
+    ('service_line_descr', 'Service description'),
+    ('contract_site_state_province', 'State/Province'),
+    ('warranty_type_description', 'Warranty Description'),
+    ('warranty_end_date', 'Warranty end date'),
+    ('warranty_type', 'Warranty type'),
+]
+
+
+def _valuespec_inv_cisco_contract():
+    return Dictionary(
+        title=_('Cisco contract staus'),
+        elements=[
+            ('removecolumns',
+             ListChoice(
+                 title=_('remove columns'),
+                 help=_('remove information from report'),
+                 choices=_removecolumns_inv_cisco_contract,
+                 default_value=[
+                     'contract_site_state_province',
+                     'warranty_type_description',
+                     'warranty_end_date',
+                     'warranty_type',
+                 ],
+             )),
+            ('PID_black_list',
+             ListOfStrings(
+                 title=_('drop Product IDs beginning with'),
+                 orientation='horizontal',
+                 help=_('there will be no request for the following PID(s)'),
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupInventory,
+        match_type='dict',
+        name='inv_parameters:inv_cisco_contract',
+        valuespec=_valuespec_inv_cisco_contract,
+    ))
diff --git a/gui/wato/inv_cisco_eox.py b/gui/wato/inv_cisco_eox.py
new file mode 100644
index 0000000..1475fbb
--- /dev/null
+++ b/gui/wato/inv_cisco_eox.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  :
+#
+# 2021-07-23: rewritten for CMK 2.0
+#
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato.utils import (
+    HostRulespec,
+    rulespec_registry,
+)
+from cmk.gui.valuespec import (
+    Dictionary,
+    FixedValue,
+    ListOfStrings,
+    ListChoice,
+)
+from cmk.gui.plugins.wato.inventory import (
+    RulespecGroupInventory,
+)
+
+_removecolumns_inv_cisco_eox = [
+    #    ('ProductIDDescription', 'PID Description'),
+    ('LinkToProductBulletinURL', 'EOL bulletin URL'),
+    ('EndOfSecurityVulSupportDate', 'End of service vulnerability support'),
+    ('EndOfSWMaintenanceReleases', 'End of software maintenance releases'),
+    ('EndOfRoutineFailureAnalysisDate', 'End of routine failure analysis'),
+    ('MigrationProductId', 'Migration PID'),
+    ('MigrationInformation', 'Migration information'),
+    ('MigrationProductInfoURL', 'Migration PID URL'),
+    ('MigrationProductName', 'Migration product name'),
+]
+
+
+def _valuespec_inv_cisco_eox():
+    return Dictionary(
+        title=_('Cisco EoX staus'),
+        elements=[
+
+            ('always_use_serial',
+             FixedValue(
+                 True,
+                 title=_('always use serial number'),
+                 help=_('if true, CMK will request Cisco EoX information via serial number (default is use PID)'),
+             )),
+            ('removecolumns',
+             ListChoice(
+                 title=_('remove columns'),
+                 help=_('remove information from EoX report'),
+                 choices=_removecolumns_inv_cisco_eox,
+                 default_value=[
+                     'EndOfSecurityVulSupportDate',
+                     'EndOfSWMaintenanceReleases',
+                     'EndOfRoutineFailureAnalysisDate',
+                     'MigrationInformation',
+                     'MigrationProductInfoURL',
+                     'MigrationProductName',
+                 ],
+             )),
+            ('PID_black_list',
+             ListOfStrings(
+                 title=_('drop Product IDs beginning with'),
+                 orientation='horizontal',
+                 help=_('there will be no request for the following PID'),
+             )),
+            ('PID_bad_list',
+             ListOfStrings(
+                 title=_('request EoX information for the following Product IDs via serial number'),
+                 orientation='horizontal',
+                 help=_('the EoX request for the following PID will by via serial number'),
+             )),
+            ('SN_black_list',
+             ListOfStrings(
+                 title=_('drop entrys with the following serial number(s)'),
+                 orientation='horizontal',
+                 help=_('there will be noe EoX request for the following serial numbers'),
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupInventory,
+        match_type='dict',
+        name='inv_parameters:inv_cisco_eox',
+        valuespec=_valuespec_inv_cisco_eox,
+    ))
diff --git a/gui/wato/inv_cisco_psirt.py b/gui/wato/inv_cisco_psirt.py
new file mode 100644
index 0000000..f213718
--- /dev/null
+++ b/gui/wato/inv_cisco_psirt.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  :
+#
+# 2021-07-23: rewritten for CMK 2.0
+#
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato.utils import (
+    HostRulespec,
+    rulespec_registry,
+)
+from cmk.gui.valuespec import (
+    Dictionary,
+    FixedValue,
+    TextAscii,
+    ListChoice,
+    Integer,
+    Alternative,
+)
+from cmk.gui.plugins.wato.inventory import (
+    RulespecGroupInventory,
+)
+
+_removecolumns_inv_cisco_psirt = [
+    ('bugIDs', 'Cisco Bug IDs'),
+    ('firstFixed', 'First fixed in'),
+    ('firstPublished', 'First Published'),
+    ('installed_version', 'installed version'),
+    ('lastUpdated', 'Last Updated'),
+    ('publicationUrl', 'Public URL'),
+    ('summary', 'Summary'),
+    ('cwe', 'CWE'),
+    ('cves', 'CVEs'),
+    ('productNames', 'Product names'),
+    ('ipsSignatures', 'IPS signatures'),
+    ('iosRelease', 'IOS Releases'),
+    ('cvrfUrl', 'CVRF URL'),
+    ('ovalUrl', 'OVAL URL'),
+]
+
+
+def _valuespec_inv_cisco_psirt():
+    return Dictionary(
+        title=_('Cisco PSIRT advisories'),
+        elements=[
+            ('removecolumns',
+             ListChoice(
+                 title=_('remove columns'),
+                 help=_('remove information from report'),
+                 choices=_removecolumns_inv_cisco_psirt,
+                 default_value=[
+                     'publicationUrl',
+                     'summary',
+                     'cwe',
+                     'cves',
+                     'productNames',
+                     'iosRelease',
+                     'ipsSignatures',
+                     'cvrfUrl',
+                     'ovalUrl',
+                 ],
+             )),
+            ('psirt_type',
+             Alternative(
+                 title=_('Cisco PSIRT advisory type'),
+                 style='dropdown',
+                 # default_value=True,
+                 elements=[
+                     FixedValue(
+                         'IOS',
+                         title=_('add Cisco PSIRT IOS security advisories'),
+                         # tototext=_('Cisco PSIRT IOS security advisories info enabled'),
+                         help=_('CMK will request Cisco IOS PSIRT security advisories'),
+                     ),
+                     FixedValue(
+                         'IOS-XE',
+                         title=_('add Cisco PSIRT IOS-XE security advisories'),
+                         # tototext=_('Cisco PSIRT IOS-XE security advisories info enabled'),
+                         help=_('CMK will request Cisco IOS-XE PSIRT security advisories'),
+                     ),
+                     Dictionary(
+                         title=_('add Cisco PSIRT advisories by base product id'),
+                         elements=[
+                             ('product_family',
+                              TextAscii(
+                                  title=_('product family'),
+                                  help=_('Product family for example: NEXUS, WSA, ESA or ASA'),
+                                  allow_empty=False,
+                                  size=24,
+                              )),
+                             ('not_updated',
+                              Integer(
+                                  title=_('don\'t show advisories not updated for the last X days'),
+                                  default_value=730,
+                                  # allow_empty=False,
+                              )
+                              ),
+                             ('dont_show_older_then',
+                              TextAscii(
+                                  title=_('don\'t show advisories from before YYYY-MM-DD'),
+                                  default_value='2000-01-01',
+                                  allow_empty=False,
+                              )),
+                         ])
+                 ]
+             )),
+        ])
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupInventory,
+        match_type='dict',
+        name='inv_parameters:inv_cisco_psirt',
+        valuespec=_valuespec_inv_cisco_psirt,
+    ))
diff --git a/inv_cisco_support-0.2.0-20230609.mkp b/inv_cisco_support-0.2.0-20230609.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..67db7b6f6e6bbea07cd0aa1337e0b9243ae32d33
GIT binary patch
literal 26029
zcmbT7Lv$q!ux?|cW7~Gewr$&H$LZL%Z6_VuwryJ{JokTZ@Md@N)~b2c@T<M{M-&YM
zbE6e(1_rct@GvyBb~SZ0bai)fa&&QHU}j`xWM*JxW@Tgk&CJbcZ|ekd(_`zi#g)X&
zlm9}uK5-#hNj8z>E8S+X(yVa!?9J)yV)y2DD*w46D%&y>D`q1#nLd&Hep6oML;~^`
zoq|`|aJ*xf6h0J8i5eX)w2HVp;^#3lpODXom-m^8@3fD1tLwY(+0(<r+o$XPjj?-g
z%je^nN#Tyka9^9U5=%5S;N4Y#NZ&EjK)jLHZF{Nuwz_UfuHGVd;%mr<i9b5+f<8*1
zJ73~rgFLHk+hfSN+@CcvSR7Z3Bn@uRR#2`OFq<j4bTaM9ShW6!kUV*u`*A6o`e$G6
z`^xB$YR6Et?EpKzOE8ymR`_`~C`c+@dMi`R7}qCx88(pfs3RPsHMfl_e5^c<vj-`O
z8p$`%=U=xQJpjp&JPu1C*X+-q3#v-w0CB8~Sgg<2j{t?Qkfko*E3<Rfoc~W{EJSN=
za`C{y!W3t>3*h@nQIH@fhp^jfL%Am;ZLWA-lg1Nu&$DjPEfJyZU$;0&t!z=|UanEB
z{`oQkZ{3vx^3T)I`~_Ds9aDFRhuk;3Be!gBG*=ey67j>V<^Atie8CdIu35pNQnZiz
z#lOGyO^9szU>MVd4)t4Na_z27useojBEG7R=)W>HF%$|SpTzO?KV7Mjt%mRE|0az-
z`>f+S@{F)(Gh!;|&`!G`4QZ?GDn}Td%=M6GSZM{ulU+YXf``bb_X}d}@@4F7e3)F8
z|Aa_LChdNmtUUd8x@Kr1W(NCO7u;~<-EnABUoHEY?|^X#3ay~12aa8MdUmy~qI$3g
zn!=E|qCr<OB_ee8q!J9^;Oho`A^CAysKPYN7+aOuqJVNB5zvO=k64|jFD9^1qQiXS
zRs5E2yvm`Rcgc3<dL@F5JEzPM-*xMbv83i6uGt4G_rYLTtiT&dhwwuIkp#n*s*p8m
zVu@)N4Bfj^K8%5VUypa_ispr2@<(?f(O#tix9dOxkis6q0n)9RW&bsq<RmukXKF0+
zBa7Iu4+!@;L<+*uu?X>+=b8;t9)Or@ngbqBv*ykHto!3E2U-R5w&g8;GI*vIInt*B
zJ5PD;9hYZ^i`1IhoA8)o|5YJ2!FDA@PJ@+xJN8fhuxEK6<*TaJFIuxp|D%kI{j*=|
z^9p;Wa6aSL`}>NSy?K#1ci~Kw=7)_1p_<n4`<RCw)4~;&vauKrhO_TfC3MX{$H_hj
zLf&#7&+hHjTd=~g>xmeD>_;$NSng>X@_p$h_l+YXl=B_rkodC~`y5182V-pNmsc1l
zBFsd2-*Ws-;l@v&G`c_kcR*L)4%;)Z+=usD2M8qn0Fspf1#x-eHLig1o3mu%-(w=S
zmB6>f7g>x?`Bp%z`s?S#S!&8dE5}{y^0m*!vMt>_U5hyg^=j~%nm4Rw5KmX+t&CiK
zMcw#IXcZk;@+q7Wa~tanhJRmx87(A?{R;gvvK;@y9;`g*9;R(_{OmqkMS@zFeCY6@
zhTp;?i7FBUk-B${jp0wQ{219^;YPB*Q|P>6mMe$!L@{x#mzHVBP0~_mRz_k=w20Rz
zRz|aAYW?kQ%fbz~i+%T3qUVNxtRvK&++pYzI2ccg%bZBaHQUvG6*^AL6*yMzsk=uH
zBy_%1XteoL#gi6xR>1f<e<Py{e(5d&KMFurKlZQ|f$l7T%&|V8+ZoMg`m?Vu)K=FP
zILlA4K>+e-fX}`8*q-x`OD}@O5^B5pUO@TWk>kHK>265c!89TR-e}%+gpjS+F@-bU
z`NSgYUj|6I=H3hMgnR6SL+P3Y)8UbVZvH$U8}Ady-|N}jj_GG?N@(w#XWl{upDk_J
zJR`brARq4l3@bCya;0*x3@k$GP!RC1hnA(Su#=d3#i9*_=lR-W+RlTkvs5faXAHG}
zI1rOEw;oV}%ouK$fG2V9Gy1<YDX`^iRy2W?$eM-UT!BzwQ|}!_yam2q2QCA@{P!+y
z+`I)5LT@9hxN9CBkC5;E#yR9gPu#P(o))n^aC2wl;{c$v3Q7OeAi6?fOafS*D3z{G
z=y{;w>iLP$HB8T3d@(3!s)%Rh6ATKIuI0KnrU%wcefR9l-F^2i9Fa?T=o6*1mJ`@Q
zq`(o77KN~(_=kmNV#<2Y3Cp?jh6Q49WKvmf-3}{V8xgFh=2<&4-Ss0zDg~`R$-^46
zw}V{R?xOUiaWnI=alRGqtSuYtcZ4f``H0%XY;4(gXli+}IMo-R+mem6EEthpiA4h7
z?I{oM*fTz3p%!v?83Gfz$hesPN>2(BOCGUq=})Jn3um~kq-wtV#CX5E8yZ<9{b6`z
z3S#=oz=2eZGw9<F%`@p!l79vv`8)~rJUajT9h<};p8&ajr;5LRbY8Y&WiO_Rg?kon
zoSuEYEY0z{u4n{|KBwEa#0^joURC~VgU`r53Z>cvS#rk@J#yXuLT1<YQWf3O1x5J$
z4Y{m11|R|co-l2H#_6Di949^cItA0tjaTF{<U4aj-p}W~OoVdFNzTWV2cU7r*i(^a
zM{$D3G@tOv>4>gEF4VHQ2>2Hf4L~*+VMSg*!D6C~a5D?ApB0A^O*+Ow51LkN<Ofw5
z&k`fv`_{!p^mVnL*c-I43jsY2nN-g1cI_^RhFK!s@blIc)14#OIh&*f5E*Zsia;C|
zAkKHVdy_&e?(a`~J}1F(*gGDnh`uU)pdeA&vr8TzQ(gMLCC|40oNZNZSr}TNL~wtk
zsIS>va2cP&rrOb|EVv=>c6(3B;fFKng~pA|UhT75SQLt`e^rf-x<0^CLQW58n+$y_
zka`USsy$Pe3IIIq6T0Set>pgHzgR4#s`V(v?QB_aKq}R3*|Z{t2rUdSjHB+id^5)g
zEho~zYOeF`vhHJolT1cm!j(HRDs*QW2I_z6;q1Mb3Cj0OsN<+0mVsHAafE~x9hMA>
z<v>>krXx=`Q&7`d{~}DpROa&MW~QqY1{|=n$^@dC7q(+Bh5^n-(6c!CL$zI#yr0Ag
zjgg8TGv1Ra=%+jb3}?O0QW5hA+FkVfy2D<WUqoBd2tOM(sr*&cQZfG7$d46FLlpv1
zEnZk(-;9&CDTGxPo07m*d0J)Q#Zii-{L!0?CL_jWX*7~Cc30J4y)rV#>55imQ%JGY
zgkUG8Ql-;FtJIuB!i#MW&M4fDEk8QPAOI2H(Y9(0R+sQpH9H9B*(e31M+6c6O1={@
zj&(n)EARa1Txh8k(dc&S!xE5H1GUIBMisqAymNP>*VX@gArDM4<CH6#>vY2b@94dq
z+Pokg+Nij$U|USo_t&=}v<Hi_j-U*^F%c|VvK#5f8VuH0CWXhB5P>cXGI=RxWzm!s
z=DU2>qD%>w0^~cN{4t`u_3^o_`0K7XHgsfb**jjI6JD^igm-g^Pm9?U0)805!(%YL
zJxuA2;tIs2NmboSne#OC*7=Fm12eE19T3^9;`^3%Mnq)6JnSw4)HtxFIxU0n=IOCE
zqtgEljG1EsT=tANPj}6)bBGi%aJE*S938eoX6KK8Bg<pVOe8*z*sC+VzTS&VbGt()
zGmQ!wk<e1KG0%(G%MOX7&szU*gZmw}>k>=r^<GKWk75;oC~TC>2%VRLK|D?)Q43P{
zdwm5`IYLnf-28S)Sa%AUeGQdIL`jpt=rdQ+SBq1&p`oZ`pv`P$qsyhj;&Q;~07;^1
zE6~#@RHh|sD=1N5q+^IqCPwqX(7Pz<`t>#?f^zk!4KGhI;Yk@_t*iEX3?1f21YE>c
zanS$wuz*yJVPV37zSd1rSyQv$wcL@_K>-c?I^PBlw+y~gSl$7>vjON(^%Z(uHMgyB
za<Ts$E$<bWSag~R1ZORbJR?)sDNo*zi@T%)N(*l1dubQ;t}{1XKhm1oo7GwLim+*8
zE^{pbtNbrml-mRMs}kulV_*X(Vf?#1thFsDqRE;r{g=}wJ0uM(3igq&@Ns;NTJMiu
z@q`emAI&)Z`B9NP9~eJqaUBLIC649eXK|q^0{2ON3#(_4V782p7MmjbbfmJyBTa=v
z$yYA4S_(SS&q61DlDNsa*2ieC@8;XbkO<+F>B6T7kyus+81$><k-+nA{HmgetPy-8
zn?9q(07N^P^2x6=J1xiqPD6@BbtSuC`hhka%|Rx1_5%?jxvuTMyKZet^RXEGZ;h@f
zflB*afmb{QnH~Zm3-T3{*h83>^qh)f?qMJYq|IF=J8n;8Uxb_V!Q$tSS>xsEDNLfd
z9swFcJ-yc$tp(dzno(Bnis(%_xg(QuYNBKOQ6hW@Lajq8TFuNzoXt$Qa@8^72Bb3Y
zqrPz&s0A@-0p@TndO3E*rL^MWrlr{-(a{44?SBqkbXinzLz{Vp8NswlmBkxE)5)(~
z5_+5svjUn<-lH4i)yaxZJgpR-5Dt&`z4UQHvkuY5s*cQfvafaPaB6<3(azGk(C!5y
zim6MBt|qDB=2d+g8*_HSJ?f_DBNKNHx7$;9%8b^Dxm?)&i`?&w7yGDvm{?0uF6d-w
zD#RE^DiPB0aIn32sdn>jT~z!iLtfE*dCKH^JnAGyik043+d_4U+QnM((<rDpdYwJ@
z4t=*{m=?IgaK~CGvUYR6;+*Fcf5s(Pw1T;da6p~KGVN_MQY)I9l<H$XuNngkE}6D`
zr~wBRsWizBd=lNkaHl04+V*yCZwG+I>DRNW0KpGrIlBGt;NqpBr2sbrA^|+4!bHbH
zj)wTmL<XK_aWJ}==OshW{z*D>E22{HmrrhL>u^ruHrIsupa%=9nweRSb0%lNF#fmX
zbS=4UixZFaCE^(HxnyBn{aE5OI*E?eNc?z<0I-KV?;ZoKd(KND$#sN!s?ubW!sf-j
zm^K8CmIhzxY>`Rm_hkmQK!KS5E_FiZ$l>q!lOL7*h4liwzI%Qh2f8-w;9b9<)b+6e
znjVO3fOC7Xz%!wb03JGgq1aEfRxGPRtaIcjEUR7EWq9};p(lZYH_sC_q64`}&YZ6g
zls&g9g<Rgj8@87r(lN#J0rIR*ygvb?XE_o~MTJLuP&9u!DQEY7pzdtj=J)>TR&ddL
zi#X)+ME`!DQ+ZQBQawGaENJZfQ?*y!>HWxx*Y0D2=-)VJ=}_-+K<WVP%qu_wI1g~4
z>k6xiwZ&eZ;(raca}jKni_c<)+jtcE`3(yP!J?-JqyBcZ+*MkO48q%~c<79+ji2!s
z!s~Q%tN~`#W%A9}cw$T%1c3+C9lFFw?r|@!wx*x<dEUA)pZuFPgW_5yEBLt%wGyTc
z4(Ae#`R3@H2Zk!uyPvu-Y11mQsStGlpFJKm1G0WPco<H(X)vum(Dc!1WZdkelurx9
z&h~fXcE%opB|CsPwR{@5u=&+Q`c5lEc{JF68j4X2l_&|)DSjP#LC{gP!E#Parxa73
z<?}-8hU*1;`Dic|?5EBtrcgM7k;nv!U(m0q$h<1beXXtch^sAExY)6$RCJGy)C5V5
zR|kghH8g7AfP9`-W-CaCKTZ1{1xsLwJIw9L@-uVFS_UAi#4dr}NL$Ia7MF%CPu0ko
zl$ms?sD1e=fRKc>tgwlbwe287yt~;QWGHt5=X1$2T#644m6}RPNkWTOWH_3haFH5^
zZW>z19IU<XZobZ#IA<x;!aRS$%z3w7*U_Gk>GH9D3M#bYZ}@0$sUceBW@O+3qq~>|
zgQm{qh}%U6AO?gb)5A|~^sG-J362D=BMDU#{7s9MdLXfS0aq%|l$e@OuVyAUzGZgn
z0bhVV3SnX$G<;!~bsP3WYCOhO%QsW!o%q-xG{Yg&KVX+l@tP-N2#wjB>d^SE@%b4m
zvh)iDF!k*8{`qO+U*D~q171D}>VBo)@qP<iHc-VqonKeA)#k@Pz)*-v3aW^L*Lej!
ztem2YqENdejnGT26va7XQalS~P~7ReDB&-?lT-+OZ4%;&%Jh0vMwMN)*RE9bM8j*<
z$TaAJJj1Q>;BB$ZjcN?@W{Rh$dnr}rxoXFC7%b?ga{3w$6AOJlQL-s<`u))%H}q>o
zYvc@PLK?iNT4MQX%`bCy>XrL0Ids-|Ich@d$2U-MznSy%4~ynQIGpZ#?dUST6`SEA
z6~%ZFY)&i!Qt|FIpHOVI+$RL~%UILT9<L+&ON3z;n@t~NCF4C<Zb{#wj-0Q~s-gCh
zm}uVXS!jY8DWe(`#nT6Obg~)3f8zcsR9m||tn0iG0GfZj1s^33aY_P_?eZkZ%F}Op
zS*`k0zkj(Rz;)l{7lOgzWrY%Pb|6YSLZh!3MjYDLp$d%N#p(PVeY1KC;F<G$%R}<_
zzhbX9(oEkKEApAJL^Tye;+2;)IymsybKlKjU-~lz`(~tX&r8KeT(VSxm3tCSq+@?}
zhrh7oQ2*|CRk3$HG<6iL3H?b0Jv)(|Ufy?2M8q{$Jfe@UX8<}Tr$bERP3-FP9rQ$3
z|M(TR<}E_?CXKi5zUXeCRAG45iUp=P+EmA1VM~1JO*n%EDltl6hv=<~{V;>`9Nt6t
zrJ1#yVM(pC+=4W%y{u+XV0BEo%#}t#-XPmO0E!DIN^c*xM7NDI)<AAX;cJhUe8&Fq
zV<0-oEnQ$WAOX0zuNl9tE4ZrKiYT0_*iyV5oXAf8BGe%heShgSRMIwvHBa=~(`~lP
z+bP5{D&~H9FtN<HcC9jOz!&4rO^w#l^i*q-H>k-`HU(z+&pFeDXa9P|@br}1k0IAt
zLe>ZZ6>hvi+JKbtLLoopf-v4he`(7BVw>M!Z^m%a3SZBMBpj8>F^x=BXy}G1C%8rp
zk;|7WQV+tQBRl?;CD8|^ZJDbes8u$!TOf(7R8c~xf>rS2LXU*}T2zAUp~Ma?N!>f%
zNE#H<zSDWH#ts)LL=1o2XlH@>K(J|u+ae2c0-PT21ksPn)kSJEXi%SO-o;d$cl@&%
zNl9vhd4DxzIXn%rw3`H-)F=ia2nSSiWq2XjT(N^edPY)8Dmk3~u-|({bbTj($2^AM
z6}BF6b&P|_R>-ngCG)v?uze=iw@pgkAXR*#GPE!$x2hxe?e1@J!W;53@|LEk2-*Mg
zcI)Eq@}8towJAiaytdp@mST+*c&qQeB90p4voK!rCBZZ9Udw(&F1b^PZaW}6;N`RZ
zhhl4FN{+`A<dlr9&}*F*oW_o(@;*v)=_{&|zDK7+%=?Uf`Q%e)_wcl9asx}1`WMR!
z+p^BZSmSeZ4T)wihwIWzO&c1nu6SU<d^^lf=4q;9RR7QFTx>UD9x{kypF{mggydhO
zCl6wS2CE7Sjjcp>B=KAJEKN<{`<lyn6JdJ(7>iA}f|;DZ#TEn=R#WAHPVrIozV~_;
zU)bdhH`my^^<12o6l=U}8nU&n1~qAPd~~ym+gh_xjpBBve@wP2q6_R8%`Gc;@ac|(
zdmi-(=lyM{eaKF#PjtGJHq+CYv%Nf^&qF0b$y7Z)F_jib;w6e)bkq-OD&Pj`XXDSA
zKZ6!5xu{(>Y=YqfQA@&zh|DF)`_UII7v1q7soc~zbyieWs~>kAvbNopAj=RB_D)0d
zF6|;(QC^0C0)JdfyzG%C?Ahv_iX`1syVA;jeaQ>pN8xY0-CC!3vmwzk=$Wp((5w(|
zD$K!Pu_6ogL4PwECItks5(%FCHeti2Lh9G&(2=rX+S7+??GBWvM_ll1z*ww=*hGbo
z1Z<uwK`azqS=HT}#*G8QY=~#=l$=odJHv&KdMn&w3Zp{$u<955Z>I&L?iskrYl~DU
zC{<Jvft+xI796G*lRVe|RBSm;G?tRG+U>Z|WD@FlE%#)VGQ11p=<Am@r&^+3vrZ=o
z$k_+2pzttnzs7gvA=TFUMCJsG<&XOY1Gm%?bK7IwF$9`|vw9VB=EDBGelJs#$^6wW
z)W`*%eSrvh^;tH*)Noasny&?#V1ZT)BJI*96|j;jDA1C06m%`_ZNRLvgPJAF;Z+<9
zJR9){tC#d4_UubNrxg8p8WG=XT<;FWrPal#$O%(K3?0*%indxwNZ~=#hIhQxEqO<;
zJ&}FZJq67^DpLBDX*3ZRkrj)YUS#(%^-50mZfOeMM!fBy_6U>Y62=W?uDjeVtF+4y
z@#WBRhv`Xl$$t9tDC*fTMPLK9qkr1^^mTvyo;`bT^_`EDL8t72o-A41dDMW0HUg~<
zE~pw-E2H}R&573fH?OSSKNy_m4GFBYX2{dg<tbji2ZEEv0Q;c&!&mY`PuKoA%d+D9
z^XBHgCqH1!6P=fo^lbp~8MVgy-3k+J{>^RlC-52x%8w1Wv|I2Bto#m$dK5gs_$m5Q
z93IvAt+{=I-^;yGv_y39`#D@{XZgQe7&glX<4iPWV-xKKd3_&tTV--mlqvH%PI;Lu
z7n=1i*Xs9+DK<5e8IA5!BIr4c_#Ck0ooS&Jn7B(MZ%uMDiJuwOGVv*bBelxV=Zst3
znp4UuNP~hE=m6im{;Oe=jqq5PwUZ+!7V2y=RY1dBK^;S{(m!|s@<-@L70*YuM|_t0
zG5xU3L_5lS#y!eVl(ZK$J;CWoymjGs%pci(f1TNL>kv*;Vb(ZnhxjEr!D*sRCuq9i
zX|f}@;Ra~5j16kbqGEEbpkXsa^#s3Ko1ZdN<fPOn-Ku84l1;)=+&pO^fAwi8xv03-
zq$rLw6^mxa<F}-Ni{)vj@X0Y)<_OXnldtio>w+xbP2j;NVWjtbLTKw_N{4BNg*{>|
zKWc|^Yqb&Q0tbeJi$8fETD5zX^rzLPNbyLd|BT?gW8<5_JX5QKRpxeNn+}8J)Vsf9
z`I>E`(e-N-`(^;XHqN$7u#8823?`_nK&Uu|n2g64rPjA<H5izCOc-9gVQJO4Y-~&Q
z@uW)j!#gN#$oKRCe3QErTBiX8w9&g$Ra?-XSoC7`z*Qmsj@K!x(z&aGu7|0H9RLpN
z)=7g{?##7N#RG_hXGV-RteCD{c6zJj=)27uo^o)Ib&1Rfdy>Ce(20Sm0`_24Cct^~
zx|QJOWVtVuU}N!bjnlJCt_b3bs5^^l)csMH-U-7mW&Rb2snm(LZF}RYei^zygweS9
z*icb8P6cbO2@>iu!Hs7acYL?KNuU)!at)`3X14xI_a5RHf%r=Mdxct#`rFf7w{T}#
ze=oav8$gS|<7B%Elj1Yq?mrhhQz$!YWZK9h8o(|r&JY<p80#I9IANoxcLRI?+m&+E
zBAO&m=leTzxP{f#6Pg1uO*=H=t^M-0dax5r_4Hh?<%EGlEhy6EIp2^{f2K(&@aw9T
zy_)hRe_ro*{2svIFzTIb4Q86mCf)Kh2}i&e0&7^q4&BYssp{dCa?~UqqIYA%jW11U
z>6Mf-u=sXZbX>QQ4X2#jyaqdrhasWjbqPm~hR5urZ4Fz9IeQ8ZBE9Fj&}<EI#yMSQ
zbkS4q5XK=x-tS${JTIo|vua8u0~lWvClG_T;og-zq1~7!TW^uH{9@qm5ZC#WH1}{C
z(xzgYTw*exP8nx5i@d7pUDb&*Fx#KfcQEghG5jjf9(*1-+q^=txTuyK+LL^mOqSQj
znf{cTHXVM;zOc`X#;vA#ZqTGUxZu=kOz6b2N}8<NYiODj`3+HPz&F(<Z`_}Gm34ko
zPQ7mr8M(@gSK~1-Vr+q&;D<i+EBO$K!72(>_UMyS4Va$~{5s!Hz5)yuP;|apY*e#F
zOUriEN|w>*`Ka}(Gax<6pmeF4ZCw|Gng()iwSyjAg>5Znm6(hR2t8bfQ=&hJtG<W1
z7~#sPkh!L8<ZHtkq(Xs2N6AB-`D}_6`?_;f7sdVeZpqpGX6Ed|7fNh&+bVBr8{{DP
zUBq67Fn&-gsoOaO23_q*jTf3r;aAd%oOxS@Kn!(XA}^zRYm*}6Lor0`#Y{pdSDz#!
z@KDn|Lzma9^>x^c8pYYYgJS@#uD5Sbc+b=D?2{gB&h95JXpL?gxA0EVu$1?NN=H-C
zGU!x7OD#6WPPVi(UX+N*IefxqA4|C&jgFcReP)JNOWVhr=vU!nE&^<SEDQOlEL8xx
z)l76!g)@8`#yI70P-)P<C-$Uq1LbD-R_@Y%(Bd7}J(`55eaY63D=13U-<jrxznQy$
zEgzFSWeltdKQ0`bmKxL%*HbcBi%0{llUNd%IHBY0=h!2_W^A|wjd^jSzf$i#{#VMg
zu$mH<1j+A+wOO%?h;%Y7U+!KwGKIl!1M{=S(9@kDxgTl<*=qc+<UXl$kTX+9qfw;v
znX9nBTC3h>TmSQG`WX$&9O>zdY?5loTCX|9)+t*&nvBVLW%R4y;0VIcp3NyoTuD0K
zf$vdn(F}3y_Ju;T7XY<L*W#rSKnPn#=ffTjS7VK_(?R!cp8c(J89p;In*P?c>jj7^
z>hLdvJO}-**~;e9VY4qus^-9(+T8eH<JMh6T1Gw+s&#RL#IgykCK`{_`K1(|{xyi)
z(Pe+Ky+gQ+?5qCMmRs%<27J4Hb?AEq)_wQEfAwkqv_b9GXHKW7mi=lKF3y_Caoy9V
zY)~e7iCT5ZOiLUgn>3ivn$D+T!}rAA#Z(ya50Yh}B#xeVx0{T~5+n5PV!Ra_mvQyb
z=?;&rh-s|vz`z={EHN|7pD1iks&^=Cu1NzkqyGDqSh<F4e$SFgG!OcDa{%vRm^Hdk
z<jlRwrk~Jpu`w53ufQ8F*`ClV;OqYt_T$|P?sKtL&Sco_G)I3vkLl-M9^Wo>C(m{)
zNR->n@8u78yx)g3@#_Fy1MazhLK(5NW{m3h0^T~=y#5I7DH`^C`oCG<jl4FW)dQl_
z_wHT;ym-eAh{f_nwG^m9j{$wWS`|+zw0@tLfSoPP+~l*|<Xn5K`0Z4vTswlwZ&w#H
zw>j;BjsjfSZ7xE!u#~ut$)=775FYw+KN_o3o9W=m#xGQzThnji3_cLG#pzny8%e8v
z?69&Zx`2I0#qGk?^`<;EONa~SbvWetR<~KQ8_P`1K!enst2L3N(URDegQIpVkPeV_
zq?9I<nT6g?;*ZRG>5)Mdr`?9r#@{ON$EdYu85P=?A8`O{wVd`6>WmbNutq@I<~RMs
z3;`x4k2~?B_-%@aQl^@Cw9P>CScyEMSm!9$vErjax1cSCSesF)w%ZEn_5i!+)}dFh
zHHl2Iejv`mIZhGwe<5=;DC6`F2JFma`i=tT36j@4P+Y*F6S(_V|0PX}>4ZpM?-AfH
z#qR?Suw_a!Vr<Jx6x)yMC=yu4FxktdrJ8{J7oa`reMIu9^D+va2E#bT$eS@^Lb2O*
z{X5fV^t%Pc1lOpD6ZY#~ICwaT+3d8SsX^HHnS#al%ig-GC4c)3BI7W|lcn#sW!?2-
zf(jGkmgxcndHq>0Kg)cJ4rPz;gkzPU#=_(PyNtMU@~m7bb0xZAo)ru`92)<enpUkK
zhrCcHNEl?#fBX$D^P`-K2T7V*H!4VS%qwHOCR-kGp-8P$^Bf=$UxZT)SSXg1W1deL
zDNZClwYdGKRogKI!kGqToerD-t%VquvNG69h~`QQQvQItj9Ux!%uZQzKI;~I@LN#o
zKAjNG7c}1No|RgvMZ}Epr=V2=wK#&?OY)8Xq)lVU#L*&^T1Xq*We{?5x(8XHpOSJ_
z4p%EzuhRJve{}Z1)G7}`w|iBb4Tt)6&g7EfE9ec0c^~@UR6aoZP?%|4;3>6kV7#Yt
zu^IQW8m72tRD3FAYceNbKifv{v+eSD0<x<AHN>ExtK_ss<a~%mvLRLU-Yi7k=GaXk
zctM)@tj9;cwOE}S=QL@ICA8ctjc?2bO}qyTlN{o@V3m~tLIEM6_Rh{(f}~S@Nt~%v
zGb5j#hdo{=m5Cg;MMMdOwa~nX&>G~FCmX;ucJBL>toiY7&|J`l6Bm-;a$rzOlg5Fd
zj<TJ7z`2S*AhorW@HdU6g_^3f&^&jc>EQTR?8<#y0A(dc0oLhpn|o3dX5Esw7K;Yl
z<zN(&3fAoP;k;d#L)YL$y#42<NPSTKLaZRgf7^<>1GNc1cVMH%_uTe?d*8Fb3wM9)
zc>kS`)~Bmv!>+!ck1HH3JhNqEou;UwZ2GzEI$48Kh6{x{ajEnkx@({UbM|}sd<}U!
zg0=8L%wUbY27GXPJk10kEGJu6i^oS=w=XSsh?~LW6FGOn4mU$=A8L-{yRyNtpm<04
zIZhm@9f{90jMTDBlUcEmPcnLBBFE|0Rox9|>BNWrwsA?u%{c}H3|&_&=r&{4kXL@<
zhO3vS`K+agulh-Z0^eZxA2*(mxwg&KFF(0#121TObOSg6^qiGHi{Gv4lx}ON?G&tP
z%Cd07O=gm2kfge{)k=Uw*sNRE;^wfwyN+mU?;5h-R16?`=(2|H;rco3mSbl*W2@Tq
zuq_H^yXe*qm5VrVItyfzbm~a=ozdc;$)Gv<sw9Oc%V#HjC_U9MAPe-OP&LE^Klo9{
zMZ<7)hli=z5~&$rDEbnreq-gceEfE=%y$e@FY}hQ8tWWT$!FyHS<mj|y<bfMzHVO6
z$x>l1;<W#cRBIHs=VwVXqN3OPkc!MjwDXmEAb5<|qSnr{)?azuNWz@0)N7va&rh;H
z8k+ns%m3H$pPD;iJufr((!Nsq0zNDNZ;;O&Z-ITy@^4^y4sZYZN`QiD?^Fc9tNuRa
zyMXDxwgE1jneWJ6;3Z!_W3RVM_J4q;mJOnBg0E1)A3tO1UjFHCg1vXoo-l$0B0WDu
z;q4habp_O6q*iY~TSLRvgkpD_vl9#Z%-s>2vs=kSN2>o%E9&L8dH5u%uCujLsGFLS
z6(mV#MA0U41x*;@CfJs6&C9fn3cvP7?2=gpJ+TSzw^D-~7JGoUJW#&1MA<A#j7N+2
z3p>=)n<-G3U<A43WG?$LI~_URQWT3v>0}TP$L>$~`l-};{bBgY98qDaVAJ+)9@H^}
zVzU||sefATn=ys^*b6V3Z?7?SbCs8@*ONd<8kz3u0*gx4!_d6&{S7}Wz5(R%`>qlu
z8$LovyhDp#7mTz}p7sUY-$0B$gU7OXD-!$QcmEmDjtb0UV9M>XqT#2dL@_w%FyTxo
z2n%o&9?_ltH2N`yuh=-O-Aqc#-~he*A%>z3S}W2_xiX;yLx3AVC00sZJ70~yC4`pz
zoHHPZ*}Eko%q7InC)RlEGiIDURuqQp4&^j<FkEAf&9z{k>uq+dl^7EHeMmJNpF4*9
zJ)hBi;>*NXOgTGo@$*1)s%Z6PnWvu3fRY*eO?b2el31MxjGcu%J}z`(e*+Uowxkvb
z%Hb7k7&k>rfPCEXP{co{W2``6@b-<!i9U|b5<3Lpi^(~oqC(msEOSUlnQJ;^*_oD!
zNr_#g`L#o(wUT8>RSvIfz>U<UVyuk)IvSPn0jCZ3Phyq4;Bu_ytm$tuIZiZ4EF*?E
zF-0IP6D@R64K>)tVaX{;hhtDRH-t3vHKfb-{H97|kA+M~u#BCB%f>75m>F*mqSg`T
zEDo*d*O=AG{VBFdivU}ytJo+nri0UOb7)L>DF|EGvKjiim|P64AoCbT>Gogdo~ex6
zz<YdBtLJmtSEkXk`Hgs?kqF~hTz(P9`THTVF?Bd%Y!G;U+9)Fm${Von;(w@wtAF6t
z*b^#r&%+@C>=P%+O$6>-z1svVQUbi6i$AUe|8*0&0|_-pIYPqJu4x22LxD2|(dWRM
zp5R9Bhid*@`$M0H<0#`sj{}Jvt1B6e<kfV*p(9Z5<6-BVOgXS;_(zFn9L6q(O6%>_
zLcoegY2>Gbey{*V$$Ka1r=-60Tl!aio8Vk>%YSfus<KV1f<B7dCKBe$_KHmT@Au@7
z)=E9?LFhMa&}!C#%pB!w9Ya}AstIgAOZGpMUY!_el}$pjDFmVsW=%B>>dT|v80?;o
zLc^t{t6vkDoVa^~5KGAXx8`<P`bO*|I<+g)Mr$0%aR&40;cNEFrV@g-y{gVu)r$>x
zM$aH}4sVmu<u(fJp69-9OT@Xxk4etS;g12Kv$1mvX-EIOh|_!*>SE%U#ptyQ#2^V0
zDkaLC1p%JQd@rU)MU51EbEE}kjME%$)4uT+E<Et?UI39u#*n*KFJ+wV<`cWqV1K`1
zlw&#`uczC6%rM4hi%(<h0f6$hA3Gj#Ua-^0>EUqp`yr%8NWjn*{VI8IXWn%=jhzR!
zRWEJc)*1S9Y4UP569P8Hb#}BaTTDD;vCK}4t$~}c_PJLj?a?EF!2m}%w%^G@!@}Rh
z$_Q~HNbtSLOF{#Ja(80H<;(KP2t&w&@TGBVV1B$|=D0Bs(Iw7LLRRGk*X2kn3}?kR
zkFL=hu^wCw0(1tmCk0O&HfW9Jw~%iJ1v<S%tr<Z#^iAOK;<pa?>Qz896vBXdjKQ$~
zC|zPV5(4y_*7{3MS$o8`_piiF4hK#wI7t-i0wEDxm4{tamOyzKx0|tEq2RJCdPYgB
z<OD`07R&`LOX2f)<3_5Z2rxa$E;EcPSmuqO5fwQkJ&axDd;S_e)n5Tng=I#X67&5y
z1wDy=+Q_B&+2sBF_pH*z9Ym@LtvNRRf>mhN%{JW^?61isj;jrGyL<Jp4QMlT9QU^Z
zQVTpsNBHe!)Gd@l`)jprhgUrn(BI(T*x88t^=qdtS%>VFG#TNcD-#C1I~f$w!%}si
z*H0GBHlT(ql+5?$Daqi^h(oBgk?6gn1{u4J*Kkm)h5$*KIwzvxBkM-ugj7356f=Dl
za;z0lkhr4Y28{cSIYIlDV+=EmFn;AXb{XNOM~G2MjxpAH77%NBh5;`9$EOB$Eea#`
z=_g`o=Jh4GZu}Zrjpeb&X!Vsv9cFLDiEK1U3*V|R__tAtOKAI-1W0BoOAZ1Ed2ta$
zP!pxPf970<fM~l-^uL_<p>g}|n!Vw|_sbyPN3dZoB+lWEbKi7#JQ0U1bA$TI&HYfA
z))>_vCtY<hB00&YQ)ab{KMKc?6S2GjJ%mjcADu%sB`ydEF+hsl`tVuS7z@G2V7Cw_
z>|t+pEw70RFb+LQA+9A33xRslF%JpIIe=#(zQ6u6dL4Crm%tFCwkV~O8`0o7CBABi
z^e^ocXPU7dU@$WuTxp1QeHLF2p33C{|0b#l>@<o|_97jHvO>qf-3ms0ZkynKmZZdP
z9f$N^ZqMR-O-}b;GBZ#?qi%_$Boj0V7`8K(GSo>Q7!^Wv54=2l)e2D*styVr>8Z~9
zm+Pr^NOWmzw~B>kM)fUqG~D=3u|?ySx5qrvPE~n<xI(t+fjp%;)eOqlzl?e~XxGl~
zI=xq3>v~+**W^1fev|6h%71^~QBk4$%^2r%R*T4<)*b{z8n&;)4Sp7AKIQ6GjSDzx
zgfjqrg3|s`uvXfuCFW5H^j$|fW*c)pf@RsjKaI25yR0l6LC~g;+L|6;z`4pm`Sg%X
z?H%KMrw7NLDH@#e13!hEE?_D*FmG%qa7=!W)Sp?hV|}$zq3eVM*xN4?(9f9GNyZtn
zj&6dKkE2;DboAZz=|EeyGH7t<T@J!uodVLn<m9@SUNCpuH3KL(4?i$`uxN12+QXJ%
zToeL^P@yM${jqqmrqhO8MEy55vQOm1Lxul&UgQvH>W-+-eJ|JP`TZ=<)^Ow$;g#Im
zKEvD_SD)>&{pU~t;wr%i)~0Yi6!M|jrdt`~T!>;y3=Nj7JtE$>;^Eyqg;CCwEN7!Z
z+^YzI#1I6MQ|SLHn0kz$9<7MlPZ(j7lKi8zLC^lCI`J7CA9PCL!(cr}jV(8PuBHmw
zGFIFjaP|8;7<lwgc!b|Va$5~~Mwfd?q&)BFG-IWxDgDux@?FYubgm!f!4Mvq18O7}
zV(Ss5q`A{F3P#YewpDBFiOec>9&bFV6juEW4c-8k{~Uc(aSE+b<;le1Q1Q50aZj_0
ze6&1r5i~<J{?NJ%R_d{_g4vX-ol&q;pG?!Nxf$3%Sbd#-sP$z4(nh~y>9q769)7K0
z9@Mw3`^SmDurcQ4`y_tR)9t3~E%x3gy>O?OF?GZE<+-1_)=;_h7zMpDXnto^sgnMg
zP5Tq}k8O+oqlWU)ZRVr1wMu5d!2HD`Pg92Bur&7Xc3Z01eM#`udhJ%J#AQ?be==Jf
z6B#8hyu%iff2!x-=Bi<;5uxeH7sr}o5>=pjJ8)-f*Z2(xz11_I3V2L62(Y|2zXPtl
z^%4F2yjiyY=sPLnrBHlVd6?eNjc_5_aYg~@WEM@QwL9;r<jO|B)-p=9Mq;){UrahZ
zqltO`Grz;6cg2w$rw1OtX#XP7b<4}EVd#}&s(nLbZ5=B0EB)?a;mta#92(oa9<3(-
z0<%?heoy#8eXhNL(~OvA<M{l&!msA;2o<U8j-|Yf*3?<cNUjk8u0492Vd74lVE(8;
z6E{Of9GpJO;sQRs#Xtahuj>Jr>(iNg0d3l+&rdg5fAo4RzXj3oUCeu_I-D=YUu72)
z>1#Ao$Yl^CckmadJX*Pa#G=6?>zJH(Db1MzV`=AQYi8%vkHwjR$JiimAh%BDc%*&+
zlblK_y_w8sKvx<$%MDG5_jAyl!pc?po~W?f)QXDq9a}C=+g{#YlVOzy4g8%AXCxDa
z)g%krowNRaXF1Bt@$#XaMzxa?pr2^V!^G0e(j!L0L7Sw_s@s#UP&a<$a;yLzJ4tWs
zmKJYcftUzJpXsYMe8+d^Lol#24-7&5hI|ry^YGqMMErL2Y|tG8R=)HJ#{N+G_jMRq
zyCpM~p-$>I&%<Xs3~(UJ8PeB#XbDs4J?wLGTr+>6Lj0Zh{N*8ag9|^1r>PlIRkcee
z<fq;v+iy&tPAw(eq@UA(YPwBufZOb07?Muc%LNh&#|WPx-dwF6xAL~9kqR}%#FtX-
zR}^}6<zH24{%*MdCSJ^`0XfB8RiFgRTT5%)v9I~pM?W?Ju{tkp_II61Nh%`4X^m@$
zD0<i`5A*@9NuBm&i7f$hOLZs>;_Y~-IVAw=R6VPM!Y<L^y%8DPl1)w>)5NPRV6a8%
zj|Lk8AWXZkLB~pq&H99P)$Q=rQIBSJx<;MDG<VGQ1)x|C{9L%fY6ITByyl%=_ic5x
z{uo{X1I)hj_0DPjW~l>#GL$C2K%ycuY9AmAVecP%)#Djrc7j+m9v^tTDp?H?F>^|z
zo=U=|FZ~MlS@{`7cJ7o%)DM*sN$4N6j@#);gbUhnpoSqdhJ3B|y{+Plc)ZS$nn`;;
zYY(_uNF`w69%mr$7d}4W{3G<*OPNy?9X*bAD2~hzpYT)4Zqwyiq8}rTWw$7JXolh@
zCSSHIOYxB9T%*0DF%yeu)TV1fFYCzjjoN4yji72ArX6*w!hX_THP^d8uNwnxfA1Qk
zPR1{?dax*Kl*r+tr!*^`s`sCw*TKwDI`$MUak^oYC1(BcJ{pB5ot|(Yk+~?$q4w%m
zI7DkMarC0vRVOCfv!#+m9%U2Af<QAt4VH?f-rD^N^0HF5w00x!bA$(d_gCjYk~+}a
zg8XUt3^;vw?Z*s!{0`__BeJ9W444KsHg~mY-T|+^f%(?Jc+Z;GWa(e)@zBV^qCL;1
zuciSKn(WMe-&oBE306vRupPQ=xo_4E<tCDq5O5#`dQKo1v|aN|BrCi>gW9y7_C(;M
zQRy;z6iD^Ey;%Mx8?iplz7>W=l3iim&Ib6zk93#EMU)QJ(aD2&9(>a2vm;%$7S{Wo
zWA61l9t3=@waJ?O;=HZ8JLg0e+sA2v%7bro5HF|0+_TzD!x#>v5_(&hL?ilkfQ+3!
zgT`hm0j&T>L(HWkWM3Ppp4NxFRkK+z=80T!s(8+kPnFTilU<V><LK@sbVhox1@6uS
z^w}!NJ&HDmrbcs3fE`tC6f=V<IXs>v^i79}v^S@yJN_&C()noTQh*(^aFB47k&7Ce
z%S12ufzon)=ZY<l`*K>55=tZ)oJD=9u{8uR=w<r44a|=H#ONx#jkK(^VnmIBxt_#d
zV~K|ytEYauIoA_9+k+9^Z~ccs2#}y3qt2(tw6z*{sbA4@{}l(xiRy7#(4AX-no7z8
zSm7jutLPzp2~s=G!f+uU4}+~T?=FN39Z~98nM`85-t&GMK}dNn4)zqxZ^<=Oc-@*E
z`0uv8SH;)rgSYupme;fBXNTwi>|6g-5$SuT0QPll$W0w_;U)FKrkZQFI>P#u6AbXq
zg7@&lz9}ag4B7?p&!roKRFU|#yNA`PJ35~Y+@RB^doSVe<Rtf7QNzz!!TpPF|D8V%
zCdvLDESYxY(4RxSpW4{nDYkR;!Oj{c1Yb9sknc0&RcXTF6SeliFRFt7-;@8=@i5m_
zi50NQlk(XIzy>0Dc+&%i6dWBrEwgVS1qt~4J}B;hBB=q34}CJ_3*;MF<dH7$dX$9H
zNzjA=x?gPqUy|Fv-77M^0LRa%IAH$U&)ce}+n6w(=UG>+1ka7iUtyHkh|*-<H%g-U
zH@+MX$_0da55e0P${yjl_plwN*TLs{r2Xy~KS41*HQLS_a?M@#P8^<|5r%I^yq`BO
z){gcJxg27-ujhJ*EaMT$kxjsIg4m9ivzFWfBwr7{xTnC!M|vW=P*THc>qX|Uu#QB$
zHs(d-_XW?ekvn3&55_0f(bLAF<;nxC#lW^De;sNBC)3wf3)>47N;DF?TOgz0DD}97
z>Sb!f|B8(MSDJM8_Lc*Eu=WDPf4=$2-)aS(rF)G(%;`et9>#|&0%eb;zxf${^1BqF
zzk{%WpmV?_JiE1@e8a=WQ{cfxz?YIN$g?J36LzqYs4VyVkn~}xuvt_)2*jZ5F7spU
zhh7KZoX%Cn8+odGY%-lI%iC`{fjM`)6tH<=@A=P1l!E{CXG`>qVwAi$@(?+8%)9&a
zVmUv`uAcr3IhB_i7oV`lSJXT^-TyK|>@-7xU7wOc8}I8a+?XV<E#)Yz!H5==DaWMy
z(-Yd}-Cz10Em8UP|F+{&L?9X(7xzq!E(aJ>%fwtd4$r1!p*zDVSPsSg3rOelQ&J$<
zmZAPnHBI&2`wT_a7Ugq-6b`MAE^Hcy`*yCJiFdCneiMnZP$~x~U(~=G-ED2+MjN{K
zI$LZGH^hxBLKT}so@KhJdM*LRG}|$ZJ-Tu0KiB_{w}=1oa3U4U;1TAsFaUfcDFyc|
zd`TP~<VGIgp6x6>MNId~WCTJchj-qe5Vv#=z8onEmXmJ6DqIY*z?b=M(609@-~mY@
z%t!DgshTY&Jzlz^VwN6KJ@`!GFcJy%0nbP7D;LT&|3o_~>2^@I{y9YE=LU>gmolRu
z^2}7`4pWK;dWas{UPgPUnIm!Ng}(iDESZ<s+fG`5Bbsr{RZzNHcJguAO3uO{iHoZH
zogN(d<N^oUI3aFqW;kE}ewuIEhr1iw5Q2?p<6uwMpJ!uo%EzwMmLZ9wipH?5iM%_d
z7{$W7!q>ffxC7gUWo`-JkP#gn7veEy%95m%X*PEnN+_|@mkWqqF66_9c1E~{a0mQJ
zk#Xc;+9uCoYU&OZrGyFt`aPbG56IvXu^{Hg|4_BvOe<N$ZX3SF$0No2yF3|he{T`n
z>r8mV)(S)|rk_9P=XRdW8xNF<e#cxuF*b0aF3nW@@%Q!e2KWNiS-264IaxkOGQ5(*
zJ~yLJsJkd@+T`j-i6tHGMyI^OAVWaL_)N}zj;qill5dyyNG*h&{zAPFhr<gR;R6$&
z9{%f&j)IRqGpYy@9*IQ54l~ci!v219z@eUH3%t0?`n4Xk%qB%=00PoGp$sO9*mMtO
zHnRc{#oh@4>E2-q)(Hc<t%OYr0hh}n6{aF~Td>^=TMQXl#=!AK;(+mnogDQ)Mwkrz
zl@Btl&bSIfum{(m5)-M{>tfYb4N^UxZ{drpmw^WC@!^i1?aB06g~Zt-r!=#>`1dSr
zcCV9ees1MoLVD{&Fr2SrtCC_Tq@ogACPosK0Hpc~TM_6<Ui4!f%K3L>G&$V0^p4V!
z#YGl+W;CTfT0*4o!v-KpXt$)h3{odz77)@$P<Hm~-fPNoiuFZaX>FWsE|U4vNLrJE
z_`@ju{m!L1@CSWHqfMNsgiqktLJD1px`YU&;aaW1#bnH1gq_LFKX-;-uDA{Y5j7T&
zsk&N*_=PpWnr{vj!!1p*AD8ZX7MJT$y0mL+9CXV#GA2P9S@535E2pg9f_c9i%~LWA
z;b0druVZlMuhu9ehEkM^dKk$?Z6M!pQ6nj;4SH#7c*<>SHsCXSbeVgjD2qunMJaUJ
zC7!e^58TlgRSS4(rP0Pr7Dp1zQ!th_GI_+ceX!v$LPpeRg+@@vmeJNqkSDWSP;kYc
zGdR?W#4kPbQwg<YN#rqSJmsUb%Bo$m=v&oFtd{(nR45WLl>c@1MLmDGZx|G5FSv@o
z)Qawx`Dw|Ol#)$d&d@V`Cd1ktC@%amXX!nDh4QZAstiJQj%@Nb#ch7n-*9pgp}<_%
zp6G)Q#O_2$_%^V7tE<ifaX}CD7q+jUINarHqe-{XAJ_$w$fFR({%XV6jL3w<5@=(2
zo^}+!i|nV{%l=?-R~4Pp!4IX$8dhY%xSx0K84)?Q+wHvB-rjbbci9RmOLYF7KD8*G
zg;lAo#yNE&amxBCk~WK-JrNEPhE@9ndOqtB9KX;vpvJN&3B$5}2uk#??o)R;np>>F
z1QN^B+!W^%h(DyT-u#@p9g5_Nu=DTlqx|vw<fcSojUp@HI(IQ0axi?;mO2SjHfYq;
zDqf=ZB8hO@<!8u@eaEZ-o(>~934#Bi)&pubPsSd~#sdn3cral{Urc(Fp0yV)Zrrlv
zxLcs<K7bHg(%TI0hmRVIgG~SN_y9XPmOaeYT9gEtuL#-O&>7B5)2y6OUK^^|q{WWE
z1_ruyE`R^;(lYbX-^cMjeTaJ~%s@#7BOJ?m%ORU_a(F_FL*;7Pq5a0KQX-K%xpikS
zg8B%%8L!*J84EABK^MXNJ<v34Gtu^({7+|aZo)ZrDH{Ghyykdm)y&0b6RC1ct90e0
zn(7dQ75B#4nkk^zEvp9a_Nw&oe64*ckADpbG8eAzyAQ%vcO>Uit}QZL-W<SeLTNyO
zp_{z<O+nFr@B^zozEqVSFe*1$m73WTiFwZ^^+i(-FVJmit@{pdCG;;%PKZLPbSA|+
zZJ)aoR_cB^Q#hV`0kS2;7(v9+1v0w~!Vt`Pc1b^|`v$Ok9A$9(Y?Pp)6{YP8Lxw~a
zEJj{*wp__fmKk~{{1NlmV={@lQ9?x)^d9+C@hzn(RgtQww#2M9vL&!6p-gA_YL1o0
zp0CEKeDi5s9<WMVB(2-@w4;yXCyHX)j*!aGWIwhO&W$rN(09%N#{bl_9#4SPDPjJ?
z_$_EC1Yyl@T42>KFVpPceccU%dTavH^=eTtQRslKM=akvr1(3j4lF;?)$wrvoWB+R
z$p$mW(X$+3Nh?Jq4PwhBa4<|!)+)nHh~zdjLi3nCJ3{}bXodP9eoO&<_BKbKCdlaV
zfy@j#ewb#hNs!@~%C8sKGNS#If^E-`9V0s-R?$0EBQoj91re#dZNG6aHN+J!eOU`a
ztU001iUahZ6Q)cakWVQm8&V;Tec7ZGH7GX8E0jMm5JU>oXyEHkv@q`M)Dh7aWlqY@
z&6pVJh-|0@aabS)5Y~s0&n=I$M>`=TD}kJz4ro;ZU-A(p`lG<(#7J643&_GPCyh%3
zZ{hgQ;B+=qTA)ox*3xpq7Bxdjun4IC6<5l|i4}z<LhIiWA@-&!`ab~$CHmS~^wmv<
z?&TrefYK<MC0oEMTj&_FwYzoj=H0Wqw{bLGPSV2{Tm3D!NXjl45OSm{Xmt+xLQ)oa
zeWjqy2>t`hTBRp);ugPI#Hd<?OHxIU;@7+&6<VrAIo(K}Dw<3tBk#$@OzS%$HJcb&
z(G+bOw_J$T2DAkgZI#BXC9RT0hs?^r!sBE)pL_A$=kK_uyHz`mS;4oi2U~*5El%YY
zS6kWsB>4*c#>}ZuLl7mn?My)MHR&b1xOa~kdxg)ZomLzPf3l2&^lr<WUIz)__meGX
z=HGa`N3K}D*A|SpDS@t%J=b!Agxs9oD~I|h$(3%VHD2^|qsVj074l9gIdr~-;U!ZG
z{N*~|I!)y(`_lE237Jgj2We2*Pi9NOM_+U`&&p!yu2r^yc;`K4IC7dI)a;4eN9t2I
z`q0(;=A-iK6Yx?&Io5q2EB93isu|9RkF+aI<EGv$D3~vn_iuX)Q}=_fx~w)^&U~5T
zJ~@Kr?ZQh^;QuChQj*VV*O{UhR~k8eTnCx;gIrn%ub<^BSm`yJE1~d#x`Y{slvQla
zfs^<VuRk6BwnlNy@l&@=A6-tjJJhF&o5>w_=x7Ep^%DSs=wQb+s^^wfJP3EkA&pB1
z>g!NRAsLV`!;Ld%ZLK(9f~Y^jeA{5WvO(EkOhnoIu&iE}Z~Z^(%6#kp=GNxl-WvIZ
zCHvQsbQhLsb?XaZ_YukZ<W`Y%pL6OL5Sh(>jm{NQpKqea7v4OW-8JbSpy$sp_b1o!
z#TIY>-}t`|AOb`e7K#AY)j0cQZ*MgF8J<7##Ahu;8yRov7f^0kRh#KIYf-=PQqL(|
zceUrfIQ|p{VdkT2>_ZyRtC-6Bz0IxPD^3J!>-Sf)e*ZS)JHH{im3f?@EiC($Y;mqn
zgvdXfCR_KC_BtOI2>VJ_bvmt8UFANr>Dw-0@CxyeOA7dqmlQ)m*iaMWT>e-ZU~vfv
zF06pIrN;)h`TA2xUKQc1c8yhtW?jR3Lv9sI7YTg@<D-g_SYN`bt`CUXwsKikg~!aI
zjn{g|NjL^pB_CnH(scJv_IG#tJ*44>Zom1o)!%J@-`#;fwtH=Sv)Agoc(0hF{3yY2
zKGWab{%%W@M`-?juiK~B0vo=kzq{MLmisBQwA<){ZiWSjPju1$Qs2DDe?rmfx(=83
z^dslr%AGSUW%KX4wB|J3Hdn0$mE6fw&;gZo>6S-=S9z&B)hlj~`5kTt-aBF|NG3Pz
zp+T$PLwg(j-R<{Unlv#<BIgy8%%R}}%ZRiz$efr0^gYOR=Nss*mYbiI3O@0t=$Dq|
zPA&JO5uhy`hQZKkb5St6-zME}lNMQ>B~?98P2>-AHIri@uM3*39ZDE+C(xhSM(gm{
zI$FQHdajSw_ubuYf6(jFaKVoz{rJs|moWfhthyjoa4dFKj)kRUwc%@47)0gAK>e}(
zAj7Nb=wEI)G<NFmb$jLoSD|vuqiY`q$D;-9Uw#}V4ub#C?e)pzzSjjQ(75N&V7qUz
zp)s;?v)9(=W2=1p-`}1o^}w(03^c!B(R6zSY@qTb7S^S18PoLKvbI9wy8jym3hBjt
zn#LaNtD#f(JO9V){3{1|bA=HC)ae6kweaI+3p>i)fA;*v!ONfi>+rw-=hf?@H*f#H
z<CD{$|NhInfBYY}@@ygH*w``_@knpGh({(-c#R(Zn&3fj`0vii0dmQ9ce}aMIyv}L
z^T{;04ALaOm(d!gNSa|0Nw?h~A!N-~F)_S0*w5V-_BvFecF5qY8~clyH}RXSG$=uq
zj<Lzm7C(J07NG*8QrrEdC)bZ;QN@yg3K>&-$6hEkVWyw)AEibF*vH^T2o&Gnj{y<d
z3>(UB5C4!`NcqP&n2Nn5`A4$V<r|%+Z8~PTvdaM#pCyGq+FTyy)zoW@=>i+otQ_n)
z6SiwoE+er!f%dJY#y-$9BgO3Kegxt^ZRP6S`Y3tmV>ZN}jC(oecC}%@$)Imt8~H=F
z;6iIaZU?D-T(NB|*fMG;EPF-#P6nuvVTwc^F=qF|y9`2)Z$BqdJk1r-AlL^EYM`2V
zNje5-Bo}W`<WTe5*9eAj#cs_FWE!R3jKe17NHkCrkGcuv|Bf!)w}&r=4zWnv`MW&7
zm8{WrP7$ZWapGyMS_gc8i}n{hdll_8SxBRSMfJfjWp2*WkoDA$PT#5;XMAeTR-Hd2
z)JXmD#Bu*$M9;c;lwW)7X5t)5_iv?G$c}`qkgM~ct+efl(=S-89;;r51N%BmH5avx
zEj<WgEn6l*))W{j8D-;L^lWGat13+%Kw4NO$CC=8V>L6aEAKQb8-?&1;}uGP*03m_
zN;<=XE-*{7w}pk+Qmd7KSB2nYWHjLMU9nKG3MOGDlR?Uq_JP>>$cW|w2t^o*p0@J}
zCK`L=uEmwW_L&50J3k-48altaAEBY2es#OfDKvmyU`yalMV?<7Q_WcNrN*~ljdGPn
z<8{vL*V=Q=WgSKbarnpj2rw+n(6Qc?TvZf%4a!pI8RuvEDcpi?#V*W?usXJ!Xu_^B
z-<2VtX*-njx(rlbQiu9#Tvm{eC=}s;eOhJFN1HH^RCbt|7b@!rk`07MWr0yaNK_IG
zTvKxQU%hf0t9>d~N{7`GxqOm-o{729WL$Fs{?;blCOx)BKNU{60+$-T6`W5m$fZ7>
zGj&=yWq+Wf_58{DZhf#`AFO{Cy9eiLj9Z~FwPN>3km0vn7Bu)F@cot!<pm%MF!hB`
z<@5VM<1o5h;uM|Mf3!7<J{eBUd3P~eL95f44e%bWV?_k7cXnU3yH=jyKenFX7o7A1
znT03)q$_^rqy9P<$JfvQ(D9?&hfe@ep8ui$v^VHu{)fT#V0XJec#8QS`u*KH|HD_y
z|FF#yKxpY7DANOm)qfRCd=fuD9sTV5gaK&0ne%pe4hy~b=3Ea5lr8n3h+oY*llcdX
zy&o;pSrmQ9qVMBA1w_G6W{}{(-78q{qHYvl0?Z4%wGA*V3Bzuuzf1Tx%Q|7^GVpVm
z473aYmE-kKD60DsHU%IGFMS^MMvLOlqPJsMeTw(WUeMiE&`+?U@igG&*b#B|A=|Et
z2z9H=$PZ*$9mh~_G?y6)<W5p+MJ||+(DE~4v!E8acjCS+<tq?6`hqJkEYv!N%o1VO
zp%m?heA=B5H0i-~H=HZCh*<<_=Q{;_1t{b@sn*MdIbavavnBuF&AVg!d4~L=?0;ou
ziMR5&;g}aHz)}QQfYd)k8#-VqDkrfrNE;e7_*FwAA&aOvmS-%h={XjMEO}IPVp0{C
z3hZj<W!YG9y%@s|>e?F)Hf;HDoF%mN-~@ogFu#)FCEQloDT-t`p*aB#yZzE`zg25O
zq4iPF@JRjgsP)N~+M&>Pp7H!zWFa~44#UMVr3@MdIm(xe9_cM9I|6oT@^8=rIVs8)
zM%X81&S&ARZWsO}O&m{d)iKMDU=k8U7^4hd$`ECWG!U2l6@j3|>1r6<V9t7FC`Luh
z(6DzLkB-IKa}eDQd7ch-aHyhCM^f)@txn~G+cKRr^U=Pv0>cuMAR~)~oj`*i{gJ!>
z6^UpFoTy2(xN8={WXTM4vWJ|$Pu37#f-^HbtrD^s!8r1mh(#9p<m$Tvj+^n8ckL6a
zh(qBtVp&vxb)Zdc0I9%lda|kAZm%tUgw=9b8I5+r_z`~MGKZ~$ZL%k=FAT1T8#iXg
z$9e$}h5mez-Vu7WNtB02EU5T_7F4H6_F=Rqp#=595SV0wv8FXat5TGgh{Y6ZtZd5(
zM0seQI87CWbS-kXa5FiET_pT-<J!^&(YAWJoG(z!wH+fV5OulWHnj?abr6i3K56(A
zX`&6`qeskMcLG335rgsB!{U>$&_Vn0rDBP}(Wd)J)wr&aS^m?jA*+VE?dHmleM-ZH
z?4Dj}EYBKv%(ykHP9rYK*f&=an_9@WneZ_<SC?sAMp$`4U&obVmK8V0E?S8~-q87j
z5wnU#6uiYeGWUY8DOVYpn@VWFTv{3dJr#wyDUD`XSX;+@$70vEtXqbr%sY_T-^^45
zC@FcCCkd0KetP1#TQKI#W`%ELA|6=|L6{XM15z{gXn<L;><m~$VKG4YYi<@*A;)yD
zLEZT@HAGk%k78N|)kWnPrIu2X+M<$KJG0Vxa)G5*kqaPsatq336&j^7atli8<g(J-
z=nPDRVqQD{0FfbR6br#J!HF%;S41c!Wrx@_N2=AxuhrO{!kX+bx2Z&E7}A~Dn*mMJ
zJHF2&ib(PyjVcAUtt~%y(#L*dN~mr@4u=L|XI(0n8&aw9+B%d<QfV8{X~mo?&UVk4
zdUpvfHarfuPEdZ|-^`PuNE}Pfj<&;^fYH0x?cSAitfE1qfT#FbyWb4PHx|C~DUfX)
z%4Y$<*(k$Vs#3<$t(XX+Qk}~(Qml+7_fNWbxeryM#!ctNS`=%dZB43;2_oq(n<FZ5
ztEUMj>Rd5RWOIsU%8G8ULeMH=Oi~J`%&N|0_s8g>;rlb5M3s{_(oP+<LmZ4BPSXry
zO48<|>%53?KXHYQA#TgKq$mas<3>8n*hr3@eB|gV$#UT|DFbJ+KrWQ$p|bsE3M$1f
zT`^*2nwBk5lxVKySQRafBU@<RQQq-kqz4uhRgSV)g34x%nF$cR*gAj~ooy!bwofMJ
zm}ah1r`tjGT5w08mPgBNR-Q{}b*sv>^vsmgvM;g>{nVfNAX_CX;hsR&mMFuWvootJ
zqozxk#OuvpgM49eY89`)#f?yE-K-fo^h7HONQU`__H3|M<FZpEK!yd0S6;PVrBT`J
z;E}~EFtiaKb7T#Zxtg`@HXE#sZH1Z5=9Bw1CIPp|WxMo@PlX>)6oSYK)A)|Z#wD|&
zVXl(3C}x4&bZMCkY}PA~(IRSCVQe+3c8Jnd-eSrHyeA@nD^-<WcUDbgVNNS!Mx888
zDOx!UVq_m~AmqgVf<s|ZUsem3dv<NE5>0V@5Ghm0Z;b}CebjCke`@~^9-jGOeLz<D
zfAo6W1I7Pi5B)#(o(^jNkJ|sE!2e^X)88FZ1<a;?ax}nub!1n68GCd8CW=4M_x1ck
z9y9USVYY-$8g&%+yUm<OYVVPp_ee=}dgeBw=4fSVfy~Y-bEwjqFD&)^Er(L_H}Ma!
zm}}px?ji<mW!uR<6x@c@gVs~Dp$Bvwxu?s>JzYf}z(wStT|@N2D0L4}(q^fJtX?AO
zfmV>n<h>Mm#{I{^Nr9(`!FhT*sw%!2LUIZA%xpKzLnDcSdDrz6$+P|Dgkkpz;>u~0
zUL!`Qpv!>%rtP?S5*4uQ<tI}bXbL-fnXEjE=YR?)sIyzRL}2u6q5iO$jqOu69g<Hf
z9c7AR$!ceqtm5)ROfh=D>(fgyl(4uIA7F~S+Ll91<%CQ{CC@astmkVhN=i7bv~tW@
zQkFw)ZE!##CYgCi!TEK?A%)cr%!_KaVD>I|93ZB3!SRG7!fxyr44aM4ed$p}%>&S+
z<ZoV^F7p6_LmLMXefvR#LgdPW2xWei<cDuNvT22f5vx183Sp~=$`e$4BvGM@vjrWO
z@-KW2@wrYOlopw`T0_Saadk@4HQBuEMxyie%(sQsT?2<<>9vHcDH=#|@93k^4plwL
zxU8BAZ!^o4toD3qHdKsOUJk8gf4d(QiW1YZ3!e>%u^R$~j4U+;a-emMfwdv<&u#ys
z!0iux18jx;Z+mBNhwOjwpPill0PTM}PkXif?>B1y`%Ff?r=5Q99+$fM-*<X@@L%+!
zy#*-<!f;BVHE~5IhiE1rNzI;fPyUpY2);#Va$y_IrYxHT2SUHxmTLRk5w^b+c2GI%
zpS1slDauvxD@yX0%F??9QOMq-Cog+H^-^y#^AZfb$3Mzf4{uR?I0K??C(KzZ?`t?L
z$OU5o(DFptzh_@@&HK-+f9e07w?Hws67b8*Ny>I-l3}t}eBov<EXa;ok7?+FFg4NP
zt48CJj~1vPXxHL<`>{w%!bfF{T*-5lF!yn&yUnwp1dKMBGFo^nFs6or^gfO6h6O60
zRv=(gfIRVJeHcZ6*QIKIQPO23Hm#s7&J-9P!g+IYKoM*dH~1vcn~Sy)t|`jAEcnA{
zsQ8)d2vx08yF@Y8*vPaRZ8BqxPRT{9VLKVl`gzsR2?E<nH#OAF4C|4}l|T6~R_iY4
z60PxkLzk~jx%fbT3>RMP%^elxF#jR2z04{q`Y48gedaf93<4-+Bg;E;Co_&|F&>qy
zG+N+uZa-LtH(rR|jLM-6)0ne@vXrQ)yNDJt%)ya2r=&bM?^*?*!6G>cE<@0`<JGWH
za?HX5tpLOfPd~@A6;RQ&H(L$GH<3B06gJLd*}<c%lyMJ?JVksO0<B0FUM6O=VOU({
zcN`;t;q_wq_wU`KefJEe6aJI8e`<thMH}k0SuFx8^1E$LWs3qv)FJ<FZD|q0gcbv~
zCbY%+Hxy#M<#c|`vJx3w{hxd;=xDW18FD8&|6hNSGVw$*32z@ki^3_IDB04nmAUP{
zJvlr+)!e5zPLo6pF*8J>Ws;e%d^{O(JPn%@`aZk-bnXjmP$6XnBO)X@tXkHsL+v(#
zcCjjF6+L|6YPL{TyLn?l9h)M1C@wkTUWVS!R_AhB(=_*TwUR<tZl((o)y8cBgGT$c
z0TqZdR99T=czB}a=sYaJ>TQ$<A=<FBvJ%WlN5<9MMTi{f1%}KrTICGxDrQ)ty@j_U
zstv>%bgrV&PG9leiHe=hkB_vELMpPWzfv%2VmD!Pyv=jPjYAI;+2*8VYnVk^Q%alb
zx*mH?K}oBJd-&!A?}@@cop%T30wTzR?#-(TB9UcT{K!%SJSU#w@2I39w5ud^DkuXa
z>2<B8y=i=*b_yOhRS3VzHlE$YU)ai*b;&wwZf=&XPpK)rOK8=^8>1rIojc7dIwDQ*
z=4>dYlFVP3@N!eO^*>);I%edA0v&zDNErJXO}F@69L5U4I}(aQQ&9t<)k+XJ-akx^
zF`*=3B^MOIOMnJDXi$VCI|tSdSnX%R1g;#<GA|PN*Q7bas~ig3h}8j=GvKyjHYeUR
zK;@BdzB!=s16>xyk_)qirbD*$lH*&yxG;*qvhtkU?d7>R%a<32R!xO`^qy#um%dJ!
zygQ^<IQpX;+-c3SoZe|G7uQCM@)N7L^qUu@mo3WIURVqDfi!97BegE=mbB^|)kBi5
z^RR{VP3X>3{lFwE^!^b~#*FhHSR21|{J+7@)7~DQ|LpYkb_cya`G5D}Rek>R=Q;oR
zzSHY>1}vzbH=Q~WJ6Iv6bog<P18mxLCa|U?`~zxoc#tsY_PS6IOU%)hp&9@a-yg2)
z1`c?2Z|@zOx3}i(Z5;1>Ew^u$`t=-s7o6wNB8(vTB`G?#Ay6uM-!mI~3a-r0`*)!x
zV<XBVt^mXeXGMu4i@s99QBf<Eg<@Ihq^Ok>aaoj7S)Q%JQX;6lP;ZghGSj0>(8b@2
zeS}CaOKE$hu@5IIzw66vegtj?B{3PdY5MdO25wi0c#nxvWuU1s8W3P3d8TF}v%6JN
zMNi6e0j&9m{SWGy8GErb5Xw%fB`smXddHbT?YC$)1r<2O4X&%~s~AHtQ?6o8ZL;eP
z$}U07>6{0meg?IgWW~41GSqbKQ`n!Xjc|!SE9(Gm%)&@uNy~^yvWh1-!*0wK9K#a|
zz+Z_%+9G9HpBcFsC93nIi1RP{mY=b-oFAPYMs8ES^U^BBu+gw)=@P#0f~BUxMc_}z
zQ}q(;W2X<0c-h1G#rHob?+4=jb`Mr)sEiw6RkyTl0kh{gucHvuW98$H`1lXsi<S4g
zD7j}d3(dm8-PLFv_0{_$E1|dD7S@9NkYfJy@KU?04B{Nt?>k2{2R9p_O0<j~IT3Ju
zqf6w6fzc20!?w`}^23hN3G&0P@?lT?u&14F<{B;<Ga4AT@7d`|NfX~dEpGsc^6DkL
zdWkMG%DYo|ck0J;yrQFhun|L*j@}rgM6^XyL&P#b^^G=wP80TBuv$A8AR#~yS=dgF
zqV|rdZsQ3q$dtOGu!=D-BxnRE9_3$DTWduVSz|_`dcCQZ0!o&=fnh_&DV>$z^SC78
zo=eI5xQJ2;mRNCh46aJ++L2kRn_AX0w=i<3^Q9G1S?%;J7@2rC1f?PYvz3UU$$|n<
zJ1_8Bs3m=rYF8*o7n{!-VN($_>hNp;7mPeuv17JAa`|t?j@$Vh7}#tUa{>BIY3R^K
zHY$M#%QHR%Q_E#DTS{1^P(DMF1%;M^3sZTj2$T#-ZP<79R^*ou>n@!-tBE{M2vII8
zR+is0N2={^9ar`X1Nmvngp6fs%ZrW2J~)9=3hBuLd)|1cBe48kZJJ$?a~Y8{BIZ2-
z<kl;SYX6O}kA_9LE{)NloNuN(NIt0~^crRixd19|wuCb|VarVS*8G9MY&aT>)skVU
z_DlvQbW@r7$s`Vl+1bL)&vumer8SD&#dxVNmsprf2gU6GqmUqxq^43J5?)9kT1B-$
zj(fmdeJs6>kpp@4B}*iT`Aw-T%w2|%i8;<sZaG#MurVL@_h+S$YmJqbZ&da+jv%oW
zMH_*&;KHAPlAuieVWs_(AX+S%@OP_GTJkZu>?vNkrO>$xnPPwnE@S4Bd8+P_tC@q}
z?3USpnis8=rMV*{1*IilNF>d#R;$iQ#5zOCFT*69FUHLL1mt0EMed;Y-zRU599rc?
z`apk^EVjACfh)KU<IHdl&AMx4B3YGdB@X1l4B_g|!or-_u&7|WYQ2nJ38F4Z?l|B#
z!#OVf!?1E^W|(=fb&ik3A$vv6=tw#9-12Y85!`92;<;71LOJEQkFKb%s>rC`ci8}`
z(;M4`)?I7|err^lR__^);AUOnBw8|P3C;w&>?P^!R0X@9=oG6#B|WRE#a43cam9H~
z3#z@Y5GuVEUVKeFqZ<8=NuejBG-DRkUewqiGjr8twXtHxM3@LKz3Te6Fbat&epj~_
z$}drA&-Iz&9r}kgdhD)c^cd7ekJ{)_8$HU59(fCbZb}_~0jq$hv9=5RzU>0Pw+;R0
z+_N{n`p*18cI7L(YUQ^5+hpU7yK)ShjjlL&Z95-7wN`A1SqN6*kn_7rrVI`vc4Hq`
zYGajhqzhPc5GZ{)Kk{E$nAmy<np_3gT*~v(BA<RQMiF&%#I{E>kW?>h-__VESh0J5
zAY<rf+!m>gq6?X;b|}~roNwfT>Ng{&x4P1z&JZ(sqwaXHF44P%)07J;R((fkmwobf
zk+#BSOKC;nSJai-&7Ji-Q>Qnh)%i#=b`@0*%$ihZ=?LhzpNmC3w~yzp7jI;{%nz!5
zd-;ANtK0(D(<WJmlU=4zECh`e_R`$N@zvc4+6Leb9X#XY9m$gEO#_gSDc#`7h3e6L
z<(l>wJteUA06;d#;&4GWXg;qW#3Nbv|IPU-K8Q2$3jg2!c7MR*zYO{S_?KRP@9B2!
z|NHg)f4TdwA8HQ3e}%6d+~0?3C%U+R?dH(gA+KO^mhJC$dpli><>CyT)2r^QF8q7K
zU3XE%VzHX{-yUul<wZEyqTePed^yisv>A%OnGb^amE0vzrRtz7f8p(S^c}W)xiU*!
z=GMx7(<KCc-(x<#7%Tq9GB5UHN4U7=JWjJX6=bStJNN;%{;(AclW67-o%1NdkfeAE
zwe3i6R9OUrMhcA*zp~m>iW$Otr~6X8Yr5Yyy<|eZ7l|{3{YsOt;XO9-Lj8LV?V7P)
z--@KhEwOP2>`EQb53g90+&GF-Ve|=?b3YCyjA&*>0ZPcz_LB4w*`h8CF_dnpds$G=
z0uXO7Ekjr(G+b>o545zqMg|?NF0kb*gw;#(z$2QnQ(9Vl<R@Ix)seazuN;m@f8lTC
zX4a$A2Lkxf*>&dUP7?gfSISaYB0m;5L^b?%(me*P9eM2~eE%=@vdN3f(S}cL<sA%|
zKXN@+d*|IgyG#9KwCjB5^m~IH{*MZC?oB={7thgnIO_M*FOTKaAK|#@pFmOY?nXWS
zPU{%8aoCj^4{BW6Dk-A(J~Fxj-SwtZ(J5wOPKf%NPba0DPf{4Bxj+F@p_`=BXsNiK
z8f90uqM%GsGfEo4OAD!CNiELrS?jXk#lf?me^P{jb$Yfkhf`(NQE=<$$A_nf&-Y)s
z+QjHi;vfws-b_jWK7p(_4vvrC92*G87*?sYI7HUV-*|Bdji`iy<e^?1MRKLGtpD`F
zQy(;9v$P>PB!L&MNdKY;>W}m<x%#pI)~aJ1`oqnGaGCltf<1jEN3{`Oy1MueT0{G7
zXRim-S1pzEL(Y=Vf6Q=wauV46hf}l_@&kLea<K4E0MRAjW>&<w$c(!VZz_Geah~yL
z5_lE1>Ho9qG~c$+=NZ=blY`^K{Z~oLX-=ciO~r{RhNHy(o{(yfoso027E1V??tV@Y
zv7keGyqDB(N>By*`JMCq-cFB6C2~v@P}qgkR60@Qdq?Jx&V6N2H$f8E<r-`m-SI|C
z0<@R?P2p@Jbbp+E$jDWeBF(a%mDBeqbS`tJQYMZ{p-bjOprAu;iU_H(<;DBDN+UZe
zVmw^YIx%m0p2{;DjCsx~$os}?VMyuDE@KAn!!N&{!`lyBM#Hl0qfUi;E!b+2al8q=
zfvSlN&%`?y*dvC2{B+XocC`@ln4&Gmdr+;qS(9AIMuOiB5Ul5gcXY!z<G0++1G>Kh
ze~1~#cUXmNA+Jo)=;oQi!1sB2Mi7zjp2IgMTkyYk2V%FL@1Y8_l3%8^%uL>_Yk~YL
z%pOs9o_W6>s|uQEK)4AdClL*~DaJ$G8e!dU3(!j`0nPr>`bxX;lC%0`c9^VME>X&?
zYGq~?9-~j1qb!XT!G@46>9dn%X0tYxLKIlr%B<-RFRdlsu78^%FDYf$;w4Fvz=$<V
z?D-0z9pcZt#I;X{z&xG}E);b9<j5}N`QWojVwbQKiO=z7a>RnEdPNWSvHtA>IuL*q
z<|QjB2c;v?HbtVQ<p|a_KfcD)7oHOBi$Fp3ZIFvG=N{bPIsy7^&1PcyARgcuWzLA@
z465h+V~M7u0O?vp+acCsH5!^kKKO|8rKQ|%<BAlc=dp~P)};Uc&Y}GkX=(6(oz9OA
ze@{9|%ci{G;;+7Ht*OB%ePD}=mTN|!b(<~Hg2r?T?Aj`f+PTHj<}+zD3a=aZ83Wjj
z#-;Z1Oo~=(S>ryYYm%>)nJWDbux{p9N1g^aia2IC519!fNV{@o^9iPwLSamhcsU*&
z7oraeJjE3g1rRqcgjX81Qur<U!0cNT+6o0R&LT!dPU>c&V<i0p;T?)x1y-;sVb{F~
zZDQQE;LW`cKAFl5tl1!#enVNq)sDxWqn>Bd!MTd&h?jZ-eOOUDr@Ip9x8p&(WEc5L
zW6_wEDji83W}bNQ7Ks{0O4AW=nV^B~-)bsv3h#x}B|$+<AJs6rbgm}QJ)sxx`@^$_
z+P$m-kZBCVRu03H5w=k)V;yOw1xoh`4=fR94sB)7nQB-`7LqGk(gI;Wen5LGieDD)
zLB#b!UBV}a2lT8#y^CqD42LkxGAK2}cTr@Rp)~NeSXMz1CqP)~+<$L@?zg3%m0&aq
zG$p&10+s=kpIfpDPAMZatLoZ|v#K}@%Z8*C;|*kY?gdK4`!*nyO1;C(uT(kZ%)axp
z&BuAk_&6t~m`&Tf?~sSHHIbEl@2X8Z<4$HKI7Z(w-<kCk-J*EB;?z^QBjHE4L*|ZE
za6uw};h}60wF#ahAGh|}Tfs(!W0=QbA4^MJwlU2ykUoeUnr~0|?R`8Z=}vurLD7Qo
zWh*1sK==)^q*^JuSfIgN1LKYt3Yg-lsZ?%KkM(gq8xYurSt%^fp)p3E(!pxu6kX_X
zu8$~NoQOMBdgN0oVwB)hkBt^folC2-e9Xj!k&mi_rYMegP#nt#R@7~M%4jHI9nIh2
zvBk4NM@uda8S9|XA6o^LV-4Ey*jSIp1?^p6#CPKxcdBhWnX`x1NWKJF5vyC-oI`-R
zSvAh#^VTD7JSw*}Whn^>gj^&U@QPjhTt$P)1*ufgmfdoVOc#9<FC?C4TP~1s0`;f1
z!xYqyIVTUf^XJLqV3!x7I*Hz{%Xq>lgOz<s_Ym03z#SXxmcrQ`xp}e!L6jmOP%(dd
zR+0q+5+O>m_iYnj+xhOh4>w+Xnb@tuxFuoV8TYH7L5}xYmYr77M$5DeS_e0yRU6)M
zHojwhfZ5L0vT0NL@rfwcGTrE@w8ev-7q&Q6m7^u)T<Ky90%HV<u+S|%TmZQZ&*DhQ
zN#V<+O7auCLz7xHFO?&<plF4iszOf7x@T-=?6KySwA!wcwm%9L?OcQT)o2Pj+awEy
zHuW-Jxh(cih5hG>d#3i2C0_`JHXk|inwPYH;>1UcdiZFzrRqgfu4}PVMH#8qCWh6y
zSLgDopZckv`l+A#sh|3(pZckv`l+A#sh|3(pZckv`l+A#sh|3(pZckv`l+8k@ALly
L#4<N!0MG&e-Qs)_

literal 0
HcmV?d00001

diff --git a/inv_cisco_support.mkp b/inv_cisco_support.mkp
index 865d7a381c8f887616c722a162d3556e9267b80b..67db7b6f6e6bbea07cd0aa1337e0b9243ae32d33 100644
GIT binary patch
literal 26029
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
L#4<N!0MG&e-Qs)_

literal 26335
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
I(g4r`07u-cdjJ3c

diff --git a/packages/inv_cisco_support b/packages/inv_cisco_support
index 967067e..47f89b5 100644
--- a/packages/inv_cisco_support
+++ b/packages/inv_cisco_support
@@ -13,7 +13,10 @@
                 'v.0.0.11: fixes for CMK 1.5.x\n'
                 '\n'
                 'v0.1: rewrite for CMK 2.0\n'
-                '          - suggestion and api_status removed\n',
+                '          - suggestion and api_status removed\n'
+                '\n'
+                'v0.2.0: moved to CMK 2.1\n'
+                '        - changed to new rest API (apix.cisco.com)\n',
  'download_url': 'https://thl-cmk.hopto.org',
  'files': {'agent_based': ['inv_cisco_eox.py',
                            'inv_cisco_contract.py',
@@ -21,22 +24,21 @@
                            'inv_cisco_psirt.py',
                            'utils/inv_cisco_support.py'],
            'bin': ['ciscoapi/ciscoapi.py',
-                   'ciscoapi/ciscosupport.py',
                    'ciscoapi/cisco-eox.py',
                    'ciscoapi/cisco-sn2info.py',
                    'ciscoapi/cisco-psirt.py',
-                   'ciscoapi/cisco-bug.py'],
-           'web': ['plugins/views/inv_cisco_support.py',
-                   'plugins/wato/inv_cisco_bug.py',
-                   'plugins/wato/inv_cisco_eox.py',
-                   'plugins/wato/inv_cisco_contract.py',
-                   'plugins/wato/inv_cisco_psirt.py',
-                   'htdocs/css/inv_cisco_support.css']},
+                   'ciscoapi/cisco-bug.py',
+                   'ciscoapi/cisco_live_cycle_utils.py'],
+           'gui': ['views/inv_cisco_livecycle.py',
+                   'wato/inv_cisco_bug.py',
+                   'wato/inv_cisco_contract.py',
+                   'wato/inv_cisco_eox.py',
+                   'wato/inv_cisco_psirt.py'],
+           'web': ['htdocs/css/inv_cisco_support.css']},
  'name': 'inv_cisco_support',
- 'num_files': 17,
  'title': 'Inventory for Cisco Bug, EoX, contract status, PSIRT advisories and '
           'suggested software',
- 'version': '20221130.v0.1c',
- 'version.min_required': '2.0.0',
- 'version.packaged': '2021.09.20',
- 'version.usable_until': None}
\ No newline at end of file
+ 'version': '0.2.0-20230609',
+ 'version.min_required': '2.1.0b1',
+ 'version.packaged': '2.1.0p21',
+ 'version.usable_until': '2.2.0b1'}
\ No newline at end of file
-- 
GitLab