private/Test-MachineSatisfiesDependency.ps1

function Test-MachineSatisfiesDependency {
    [CmdletBinding()]
    [OutputType('System.Int32')]
    Param (
        [ValidateNotNullOrEmpty()]
        [System.Xml.XmlElement]$Dependency,
        [Parameter( Mandatory = $true )]
        [string]$PackagePath,
        [int]$DebugIndent = 0,
        [switch]$FailInboxDrivers
    )

    # 0 SUCCESS, Dependency is met
    # -1 FAILRE, Dependency is not met
    # -2 Unknown dependency kind - status uncertain

    switch ($Dependency.SchemaInfo.Name) {
        '_Bios' {
            Write-Debug "$('- ' * $DebugIndent)[ Got: $($CachedHardwareTable._Bios) ]"
            foreach ($entry in $Dependency.Level) {
                if ($CachedHardwareTable._Bios -like "$entry*") {
                    return 0
                }
            }
            return -1
        }
        '_Coreq' {
            $DependencyPackage = $AllPackagesDependenciesInfo[$Dependency.name]
            if ($DependencyPackage) {
                if ($DependencyPackage.IsInstalled) {
                    Write-Debug "$('- ' * $DebugIndent)[ Got: $($Dependency.name) $($DependencyPackage.Version), Expected: $($Dependency.Version) ]"
                    return (Test-VersionPattern -LenovoString $Dependency.Version -SystemString $DependencyPackage.Version)
                } else {
                    Write-Debug "$('- ' * $DebugIndent)[ $($Dependency.name) is not installed yet, Expected: $($Dependency.Version) ]"
                }
            } else {
                Write-Debug "$('- ' * $DebugIndent)[ $($Dependency.name) is not in the repository, Expected: $($Dependency.Version) ]"
            }
            return -1
        }
        '_CPUAddressWidth' {
            Write-Debug "$('- ' * $DebugIndent)[ Got: $($CachedHardwareTable._CPUAddressWidth), Expected: $($dependency.AddressWidth) ]"
            if ($CachedHardwareTable._CPUAddressWidth -like "$($Dependency.AddressWidth)*") {
                return 0
            } else {
                return -1
            }
        }
        '_Driver' {
            [array]$SupportedDriverNodes = 'HardwareID', 'Version', 'Date', 'File'
            [array]$DriverChildNodes = $Dependency.ChildNodes.SchemaInfo.Name
            if (-not (Compare-Array $DriverChildNodes -in $SupportedDriverNodes)) {
                Write-Debug "$('- ' * $DebugIndent)_Driver node contained unknown element - skipping checks"
                return -2
            }

            if ($DriverChildNodes -contains 'HardwareID') {
                [System.Collections.Generic.List[object]]$DevicesMatchedExact = [System.Collections.Generic.List[object]]::new()
                [System.Collections.Generic.List[object]]$DevicesMatchedWildcard = [System.Collections.Generic.List[object]]::new()
                [System.Collections.Generic.List[object]]$DevicesToTest = [System.Collections.Generic.List[object]]::new()

                :NextDevice foreach ($DeviceInMachine in $CachedHardwareTable._PnPID) {
                    [bool]$DeviceHwIdWildcardMatched = $false

                    foreach ($HardwareInMachine in $DeviceInMachine.HardwareID) {
                        # A _Driver node can have multiple 'HardwareID' child nodes, e.g. https://download.lenovo.com/pccbbs/mobiles/r1kwq15w_2_.xml
                        foreach ($HardwareID in $Dependency.HardwareID.'#cdata-section') {
                            # Matching with wildcards may have been a mistake, some HardwareIDs just contain a * (star).
                            # Try exact equal matches first and fall back to wildcard only when needed. I want to see how often that happens.
                            if ($HardwareInMachine -eq "$HardwareID") {
                                Write-Debug "$('- ' * $DebugIndent)Matched device '$HardwareInMachine' with required '$HardwareID' (EXACT)"
                                $DevicesMatchedExact.Add($DeviceInMachine)
                                continue NextDevice
                            }
                            # Lenovo HardwareIDs can contain wildcards (*) so we have to compare with "-like"
                            if ($HardwareInMachine -like "*$HardwareID*") {
                                Write-Debug "$('- ' * $DebugIndent)Matched device '$HardwareInMachine' with required '$HardwareID' (WILDCARD)"
                                $DeviceHwIdWildcardMatched = $true
                            }
                        }
                    }

                    # To preserve the old behavior whilst fully testing the new, do add devices that were only matched via wildcards
                    if ($DeviceHwIdWildcardMatched) {
                        Write-Debug "$('- ' * $DebugIndent)Adding device - HardwareIDs matched only when using wildcards"
                        $DevicesMatchedWildcard.Add($DeviceInMachine)
                    }
                }

                Write-Debug "$('- ' * $DebugIndent)Matched devices: $($DevicesMatchedExact.Count) exact, $($DevicesMatchedWildcard.Count) wildcard"
                $DevicesToTest = if ($DevicesMatchedExact) {
                    $DevicesMatchedExact
                } else {
                    $DevicesMatchedWildcard
                }

                if ($DevicesToTest.Count -ge 1) {
                    $TestResults = [System.Collections.Generic.List[bool]]::new()
                    foreach ($Device in $DevicesToTest) {
                        Write-Debug "$('- ' * $DebugIndent)Testing $($Device.DeviceId)"
                        # First, check if there is a driver installed for the device at all before proceeding (issue#24)
                        if ($Device.Problem -eq 'CM_PROB_FAILED_INSTALL') {
                            [string]$HexDeviceProblemStatus = '0x{0:X8}' -f (Get-PnpDeviceProperty -InputObject $Device -KeyName 'DEVPKEY_Device_ProblemStatus').Data
                            Write-Debug "$('- ' * $DebugIndent)Device '$($Device.InstanceId)' does not have any driver (ProblemStatus: $HexDeviceProblemStatus)"
                            return -1
                        }

                        if ($FailInboxDrivers) {
                            # This approach of identifying 'inbox' drivers seems to produce the most matching SeverityOverride results.
                            # Some alternatives tested were DEVPKEY_Device_GenericDriverInstalled and Get-AuthenticodeSignature .IsOSBinary property.
                            [bool]$DriverIsInbox = (
                                (Get-PnpDeviceProperty -InputObject $Device -KeyName 'DEVPKEY_Device_DriverProvider').Data -eq 'Microsoft' -and
                                (Get-PnpDeviceProperty -InputObject $Device -KeyName 'DEVPKEY_Device_DriverInfPath').Data -notmatch '^oem\d+\.inf$'
                            )
                            if ($DriverIsInbox) {
                                Write-Debug "$('- ' * $DebugIndent)Failed because device is using an inbox driver"
                                return -1
                            }
                        }

                        $icmParams = @{
                            'InputObject' = $Device
                            'MethodName'  = 'GetDeviceProperties'
                            'Arguments'   = @{'devicePropertyKeys' = @('DEVPKEY_Device_DriverVersion')}
                            'Verbose'     = $false
                            'ErrorAction' = 'SilentlyContinue'
                        }

                        $DriverVersionObject = Invoke-CimMethod @icmParams | Select-Object -ExpandProperty deviceProperties
                        if (-not $DriverVersionObject) {
                            # Fall back to the much slower Get-PnpDeviceProperty cmdlet in cases where GetDeviceProperties fails (e.g. disconnected "phantom" devices)
                            $DriverVersionObject = Get-PnpDeviceProperty -InputObject $Device -KeyName 'DEVPKEY_Device_DriverVersion'
                        }
                        $DriverVersion = $DriverVersionObject.Data

                        $icmParams = @{
                            'InputObject' = $Device
                            'MethodName'  = 'GetDeviceProperties'
                            'Arguments'   = @{'devicePropertyKeys' = @('DEVPKEY_Device_DriverDate')}
                            'Verbose'     = $false
                            'ErrorAction' = 'SilentlyContinue'
                        }

                        $DriverDateObject = Invoke-CimMethod @icmParams | Select-Object -ExpandProperty deviceProperties
                        if (-not $DriverDateObject) {
                            # Fall back to the much slower Get-PnpDeviceProperty cmdlet in cases where GetDeviceProperties fails (e.g. disconnected "phantom" devices)
                            $DriverDateObject = Get-PnpDeviceProperty -InputObject $Device -KeyName 'DEVPKEY_Device_DriverDate'
                        }
                        $DriverDate = $DriverDateObject.Data

                        # Documentation for this: https://docs.microsoft.com/en-us/windows-hardware/drivers/install/identifier-score--windows-vista-and-later-
                        # To be clear, this is a 'pretty good / best effort' approach, but it can detect false positives or miss generic drivers.
                        # AFAIK it is not possible to detect with 100% certainty that a driver is generic/inbox and even if - it's not always a problem.
                        # So this information should only be used for informaing the user or as an aid in making non-critical decisions,
                        # do not rely on this detection/boolean to be accurate!
                        [UInt32]$DriverRank = (Get-PnpDeviceProperty -InputObject $Device -KeyName 'DEVPKEY_Device_DriverRank').Data
                        [byte]$DriverMatchTypeScore = $DriverRank -shr 12 -band 0xF
                        Write-Debug "$('- ' * $DebugIndent)Device '$($Device.Name)' DriverRank is 0x$('{0:X8}' -f $DriverRank)"
                        if ($DriverMatchTypeScore -ge 2) {
                            Write-Verbose "Device '$($Device.Name)' may currently be using a generic or inbox driver"
                        }

                        if ($DriverChildNodes -contains 'Date') {
                            Write-Debug "$('- ' * $DebugIndent)Trying to match driver based on Date"
                            $LenovoDate = [DateTime]::new(0)
                            [bool]$LenovoDateIsValid = [DateTime]::TryParseExact(
                                $Dependency.Date,
                                'yyyy-MM-dd',
                                [CultureInfo]::InvariantCulture,
                                [System.Globalization.DateTimeStyles]::AdjustToUniversal -bor [System.Globalization.DateTimeStyles]::AssumeUniversal,
                                [ref]$LenovoDate
                            )
                            if ($LenovoDateIsValid) {
                                if ($DriverDate) {
                                    # WMI and therefore CIM stores datetime values in a DMTF string format.
                                    # When these are converted to DateTime objects, they are always converted to the local timezone, aka an offset
                                    # is "artificially" added. For driver dates, this can lead to GitHub#33 where the offset is enough to change the date,
                                    # which leads to false driver results. We have to remove the offset by converting the DateTime of Kind 'Local' back to UTC.
                                    # See GitHub#33 and https://docs.microsoft.com/en-us/dotnet/api/system.management.managementdatetimeconverter.todatetime?view=netframework-4.8#remarks
                                    $DriverDate = $DriverDate.ToUniversalTime().Date
                                    Write-Debug "$('- ' * $DebugIndent)[Got: $DriverDate, Expected: $LenovoDate]"
                                    if ($DriverDate -ge $LenovoDate) {
                                        Write-Debug "$('- ' * $DebugIndent)Passed DriverDate test"
                                        $TestResults.Add($true)
                                    } else {
                                        Write-Debug "$('- ' * $DebugIndent)Failed DriverDate test"
                                        $TestResults.Add($false)
                                    }
                                } else {
                                    Write-Verbose "Device '$($Device.InstanceId)' does not report its driver date"
                                }
                            } else {
                                Write-Verbose "Got unsupported date format from Lenovo: '$($Dependency.Date)' (expected yyyy-MM-dd)"
                            }
                        }

                        if ($DriverChildNodes -contains 'Version') {
                            Write-Debug "$('- ' * $DebugIndent)Trying to match driver based on Version"
                            # Not all drivers tell us their versions via the OS API. I think later I can try to parse the INIs as an alternative, but it would get tricky
                            if ($DriverVersion) {
                                Write-Debug "$('- ' * $DebugIndent)[Got: $DriverVersion, Expected: $($Dependency.Version)]"
                                if ((Test-VersionPattern -LenovoString $Dependency.Version -SystemString $DriverVersion) -eq 0) {
                                    Write-Debug "$('- ' * $DebugIndent)Passed DriverVersion test"
                                    $TestResults.Add($true)
                                } else {
                                    Write-Debug "$('- ' * $DebugIndent)Failed DriverVersion test"
                                    $TestResults.Add($false)
                                }
                            } else {
                                Write-Verbose "Device '$($Device.InstanceId)' does not report its driver version"
                            }
                        }
                    }

                    # If all HardwareID-tests were successful, return SUCCESS
                   # if (-not ($TestResults -contains $false)) {
                        #return 0 #SUCCESS
                    #}
                    if ($TestResults -contains $true) {
                        return 0 
                    }
                    


                    # If one or more HardwareID-tests were completed but failed (e.g. Date) continue in case there are further tests like FileVersion
                }
            }

            if (Compare-Array @('File', 'Version') -in $DriverChildNodes) {
                # This may not be 100% yet as Lenovo sometimes uses some non-system environment variables in their file paths
                [string]$Path = Resolve-CmdVariable -String $Dependency.File -ExtraVariables @{'WINDOWS' = $env:SystemRoot}
                if (Test-Path -LiteralPath $Path -PathType Leaf) {
                    $filProductVersion = (Get-Item -LiteralPath $Path).VersionInfo.ProductVersion
                    $FileVersionCompare = Test-VersionPattern -LenovoString $Dependency.Version -SystemString $filProductVersion
                    if ($FileVersionCompare -eq -2) {
                        Write-Debug "$('- ' * $DebugIndent)Got unsupported with ProductVersion, trying comparison with FileVersion"
                        $filFileVersion = (Get-Item -LiteralPath $Path).VersionInfo.FileVersion
                        return (Test-VersionPattern -LenovoString $Dependency.Version -SystemString $filFileVersion)
                    } else {
                        return $FileVersionCompare
                    }
                } else {
                    Write-Debug "$('- ' * $DebugIndent)The file '$Path' was not found."
                    return -1
                }
            }

            # If we have not hit a success condition before the end, return with failure
            return -1
        }
        '_EmbeddedControllerVersion' {
            if ($CachedHardwareTable._EmbeddedControllerVersion) {
                if ($CachedHardwareTable._EmbeddedControllerVersion -eq '255.255') {
                    Write-Warning "This computers EC firmware is not upgradable but is being used to evaluate a package"
                }
                return (Test-VersionPattern -LenovoString $Dependency.Version -SystemString $CachedHardwareTable._EmbeddedControllerVersion)
            }
            return -1
        }
        '_ExternalDetection' {
            $externalDetection = Invoke-PackageCommand -Command $Dependency.'#text' -Path $PackagePath -RuntimeLimit $script:LnvUpdateConfiguration.MaxExternalDetectionRuntime
            if ($externalDetection.Err) {
                Write-Debug "$('- ' * $DebugIndent)[ External process did not run properly: $($externalDetection.Err) ]"
                return -1
            } else {
                Write-Debug "$('- ' * $DebugIndent)[ Got ExitCode: $($externalDetection.Info.ExitCode), Expected: $($Dependency.rc) ]"
                if ($externalDetection.Info.ExitCode -in ($Dependency.rc -split ',')) {
                    return 0
                } else {
                    return -1
                }
            }
        }
        '_FileExists' {
            # This may not be 100% yet as Lenovo sometimes uses some non-system environment variables in their file paths
            [string]$Path = Resolve-CmdVariable -String $Dependency.'#text' -ExtraVariables @{'WINDOWS' = $env:SystemRoot}
            if (Test-Path -LiteralPath $Path -PathType Leaf) {
                return 0
            } else {
                return -1
            }
        }
        '_FileVersion' {
            # This may not be 100% yet as Lenovo sometimes uses some non-system environment variables in their file paths
            [string]$Path = Resolve-CmdVariable -String $Dependency.File -ExtraVariables @{'WINDOWS' = $env:SystemRoot}
            if (Test-Path -LiteralPath $Path -PathType Leaf) {
                $filProductVersion = (Get-Item -LiteralPath $Path).VersionInfo.ProductVersion
                $FileVersionCompare = Test-VersionPattern -LenovoString $Dependency.Version -SystemString $filProductVersion
                if ($FileVersionCompare -eq -2) {
                    Write-Debug "$('- ' * $DebugIndent)Got unsupported with ProductVersion, trying comparison with FileVersion"
                    $filFileVersion = (Get-Item -LiteralPath $Path).VersionInfo.FileVersion
                    return (Test-VersionPattern -LenovoString $Dependency.Version -SystemString $filFileVersion)
                } else {
                    return $FileVersionCompare
                }
            } else {
                Write-Debug "$('- ' * $DebugIndent)The file '$Path' was not found."
                return -1
            }
        }
        '_Firmware' {
            # https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/query-version-and-status-ps1-script?view=windows-11
            # Dependency.Version can also have a hex2dec attribute (True/False) and depending on whether it exists PowerShell deserializes
            # the XML differently (.Version can be string or XmlElement). Using SelectNode is consistent.
            [string]$LenovoVersion    = $Dependency.SelectSingleNode('Version').'#text'
            [bool]$LenovoVersionIsHex = $Dependency.SelectSingleNode('Version').GetAttribute('hex2dec') -eq 'True'
            foreach ($PnpDevice in $CachedHardwareTable._PnPID) {
                foreach ($entry in $Dependency.HardwareIDs) {
                    # Only exact HardwareID matches will be found (no wildcards)
                    if ($entry.'#cdata-section' -in $PnpDevice.HardwareID) {
                        [string]$PnpDeviceFirmwareRev = $PnpDevice.HardwareID[0].Substring($PnpDevice.HardwareID[0].IndexOf('&REV_') + 5)
                        Write-Debug "$('- ' * $DebugIndent)[ Got: ${PnpDeviceFirmwareRev}, Expected: ${LenovoVersion} (IsHex: ${LenovoVersionIsHex}) ]"
                        if ($LenovoVersionIsHex) {
                            # If hex2dec is explicitly set to True only interpret the LenovoVersion as hexadecimal.
                            # This is important because any decimal-looking number can also be interpreted in hex but has a very different value there.
                            return (Test-VersionPattern -LenovoString $LenovoVersion -SystemString $PnpDeviceFirmwareRev -SystemStringFormat Hex -LenovoStringFormat Hex)
                        } else {
                            # Some packages, like https://download.lenovo.com/pccbbs/mobiles/n2wrg16w_v2_2_.xml, use hexadecimal versions but set hex2dec=False.
                            # We leave LenovoStringFormat set to the default 'Auto' to try and support that case as best as possible with fallback logic
                            return (Test-VersionPattern -LenovoString $LenovoVersion -SystemString $PnpDeviceFirmwareRev -SystemStringFormat Hex)
                        }
                    }
                }
            }
            return -1 # HardwareID not in system - fail
        }
        '_OS' {
            foreach ($entry in $Dependency.OS) {
                if ("$entry" -like "WIN$($CachedHardwareTable._OS)*") {
                    return 0
                }
            }
            return -1
        }
        '_OSLang' {
            if ($Dependency.Lang -eq [CultureInfo]::CurrentUICulture.ThreeLetterWindowsLanguageName) {
                return 0
            } else {
                return -1
            }
        }
        '_PnPID' {
            foreach ($HardwareID in $CachedHardwareTable._PnPID.HardwareID) {
                if ($HardwareID -like "*$($Dependency.'#cdata-section')*") {
                    return 0
                }
            }
            return -1
        }
        '_RegistryKey' {
            if ($Dependency.Key) {
                if (Test-Path -LiteralPath ('Microsoft.PowerShell.Core\Registry::{0}' -f $Dependency.Key) -PathType Container) {
                    return 0
                }
            }
            return -1
        }
        '_RegistryKeyValue' {
            if ($Dependency.Version -and $Dependency.KeyValue -or
                $Dependency.Version -and $Dependency.type -ne 'REG_SZ') {
                return -2
            }

            if (Test-Path -LiteralPath ('Microsoft.PowerShell.Core\Registry::{0}' -f $Dependency.Key) -PathType Container) {
                try {
                    $regValue = Get-ItemPropertyValue -LiteralPath ('Microsoft.PowerShell.Core\Registry::{0}' -f $Dependency.Key) -Name $Dependency.KeyName -ErrorAction Stop
                }
                catch {
                    return -1
                }

                [string]$DependencyVersion = if ($Dependency.KeyValue) {
                    $Dependency.KeyValue
                } elseif ($Dependency.Version) {
                    $Dependency.Version
                } else {
                    Write-Verbose "Could not get LenovoString from _RegistryKeyValue dependency node"
                    return -2
                }

                return (Test-VersionPattern -LenovoString $DependencyVersion -SystemString $regValue)
            } else {
                return -1
            }
        }
        '_WindowsBuildVersion' {
            # A _WindowsBuildVersion test can specify multiple Build Versions, see issue #42
            [array]$TestResults = foreach ($DependencyVersion in $Dependency.Version) {
                Write-Debug "$('- ' * $DebugIndent)[ Got: $($CachedHardwareTable._WindowsBuildVersion), Expected: $DependencyVersion ]"
                Test-VersionPattern -LenovoString $DependencyVersion -SystemString $CachedHardwareTable._WindowsBuildVersion
            }

            # If we had a clear success match, return success overall.
            # If we had no clear successes, but an unsupported case, return
            # -2 for unsupported so the calling function can evaluate that.
            # Otherwise return -1 to indicate failure (no matches).
            if ($TestResults -contains 0) {
                return 0
            } elseif ($TestResults -contains -2) {
                return -2
            } else {
                return -1
            }
        }
        default {
            Write-Verbose "Unsupported dependency encountered: $_"
            return -2
        }
    }

    return -2
}

# SIG # Begin signature block
# MIItugYJKoZIhvcNAQcCoIItqzCCLacCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUo87Pk7Y92rxcf6wYGYJKEb8c
# WEyggibcMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B
# AQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk
# IElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQsw
# CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
# ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw
# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz
# 7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS
# 5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7
# bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfI
# SKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jH
# trHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14
# Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2
# h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt
# 6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPR
# iQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ER
# ElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4K
# Jpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAd
# BgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SS
# y4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAC
# hjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS
# b290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRV
# HSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyh
# hyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO
# 0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo
# 8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++h
# UD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5x
# aiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMIIFkDCCA3ig
# AwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQG
# EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
# cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMTMw
# ODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD
# VQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Y
# q3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lX
# FllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxe
# TsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbu
# yntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I
# 9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmg
# Z92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse
# 5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKy
# Ebe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwh
# HbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/
# Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwID
# AQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4E
# FgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQADggIBALth2X2p
# bL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2SV1EY+CtnJYY
# ZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd+SeuMIW59mdN
# Oj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWcfFqK1qI4mfN4
# i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqasjYUegbyJLkJ
# EVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9NcCOGDErcgdLM
# MpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N0XWs0Mr7QbhD
# parTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie4u1Ki7wb/UdK
# Dd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mIr/OSmbaz5mEP
# 0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1/YldvIViHTLS
# oCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCmgKDWHrO8Dw9T
# dSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+MIIGsDCCBJigAwIBAgIQCK1AsmDS
# nEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD
# VQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjEwNDI5MDAwMDAwWhcN
# MzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs
# IEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5n
# IFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
# MIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zrPYGXcMW7xIUmMJ+kjmjYXPXr
# NCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHMgQM+TXAkZLON4gh9NH1MgFcS
# a0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8IrgnQnAZaf6mIBJNYc9URnokCF4
# RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyCEUhSaN4QvRRXXegYE2XFf7JP
# hSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0p6MDDnSlrzm2q2AS4+jWufcx
# 4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQakhCBj7A7CdfHmzJawv9qYFSL
# ScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0XLyTRSiDNipmKF+wc86LJiUG
# soPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960IHnWmZcy740hQ83eRGv7bUKJG
# yGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2FKZbS110YU0/EpF23r9Yy3IQ
# KUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBHX8mBUHOFECMhWWCKZFTBzCEa
# 6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q27IwyCQLMbDwMVhECAwEAAaOC
# AVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFGg34Ou2O/hfEYb7
# /mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1Ud
# DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB3BggrBgEFBQcBAQRrMGkw
# JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcw
# AoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv
# b3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQu
# Y29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwHAYDVR0gBBUwEzAHBgVngQwB
# AzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIBADojRD2NCHbuj7w6mdNW4AIa
# pfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6jfCbVN7w6XUhtldU/SfQnuxaB
# RVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmImoqKwba9oUgYftzYgBoRGRjN
# YZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtfJqGVWEjVGv7XJz/9kNF2ht0c
# sGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrxoj7bQ7gzyE84FJKZ9d3OVG3Z
# XQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3LIU/Gs4m6Ri+kAewQ3+ViCCC
# cPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx4b6cpwoG1iZnt5LmTl/eeqxJ
# zy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9Oj9FpsToFpFSi0HASIRLlk2r
# REDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+ICw2/O/TOHnuO77Xry7fwdxPm
# 5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug0wcCampAMEhLNKhRILutG4UI
# 4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5Vzu0nAPthkX0tGFuv2jiJmCG
# 6sivqf6UHedjGzqGVnhOMIIGtDCCBJygAwIBAgIQDcesVwX/IZkuQEMiDDpJhjAN
# BgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQg
# SW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2Vy
# dCBUcnVzdGVkIFJvb3QgRzQwHhcNMjUwNTA3MDAwMDAwWhcNMzgwMTE0MjM1OTU5
# WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNV
# BAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hB
# MjU2IDIwMjUgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtHgx
# 0wqYQXK+PEbAHKx126NGaHS0URedTa2NDZS1mZaDLFTtQ2oRjzUXMmxCqvkbsDpz
# 4aH+qbxeLho8I6jY3xL1IusLopuW2qftJYJaDNs1+JH7Z+QdSKWM06qchUP+AbdJ
# gMQB3h2DZ0Mal5kYp77jYMVQXSZH++0trj6Ao+xh/AS7sQRuQL37QXbDhAktVJMQ
# bzIBHYJBYgzWIjk8eDrYhXDEpKk7RdoX0M980EpLtlrNyHw0Xm+nt5pnYJU3Gmq6
# bNMI1I7Gb5IBZK4ivbVCiZv7PNBYqHEpNVWC2ZQ8BbfnFRQVESYOszFI2Wv82wnJ
# RfN20VRS3hpLgIR4hjzL0hpoYGk81coWJ+KdPvMvaB0WkE/2qHxJ0ucS638ZxqU1
# 4lDnki7CcoKCz6eum5A19WZQHkqUJfdkDjHkccpL6uoG8pbF0LJAQQZxst7VvwDD
# jAmSFTUms+wV/FbWBqi7fTJnjq3hj0XbQcd8hjj/q8d6ylgxCZSKi17yVp2NL+cn
# T6Toy+rN+nM8M7LnLqCrO2JP3oW//1sfuZDKiDEb1AQ8es9Xr/u6bDTnYCTKIsDq
# 1BtmXUqEG1NqzJKS4kOmxkYp2WyODi7vQTCBZtVFJfVZ3j7OgWmnhFr4yUozZtqg
# PrHRVHhGNKlYzyjlroPxul+bgIspzOwbtmsgY1MCAwEAAaOCAV0wggFZMBIGA1Ud
# EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFO9vU0rp5AZ8esrikFb2L9RJ7MtOMB8G
# A1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjAT
# BgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGG
# GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2Nh
# Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYD
# VR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9
# bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQAXzvsWgBz+Bz0RdnEwvb4LyLU0pn/N0IfF
# iBowf0/Dm1wGc/Do7oVMY2mhXZXjDNJQa8j00DNqhCT3t+s8G0iP5kvN2n7Jd2E4
# /iEIUBO41P5F448rSYJ59Ib61eoalhnd6ywFLerycvZTAz40y8S4F3/a+Z1jEMK/
# DMm/axFSgoR8n6c3nuZB9BfBwAQYK9FHaoq2e26MHvVY9gCDA/JYsq7pGdogP8HR
# trYfctSLANEBfHU16r3J05qX3kId+ZOczgj5kjatVB+NdADVZKON/gnZruMvNYY2
# o1f4MXRJDMdTSlOLh0HCn2cQLwQCqjFbqrXuvTPSegOOzr4EWj7PtspIHBldNE2K
# 9i697cvaiIo2p61Ed2p8xMJb82Yosn0z4y25xUbI7GIN/TpVfHIqQ6Ku/qjTY6hc
# 3hsXMrS+U0yy+GWqAXam4ToWd2UQ1KYT70kZjE4YtL8Pbzg0c1ugMZyZZd/BdHLi
# Ru7hAWE6bTEm4XYRkA6Tl4KSFLFk43esaUeqGkH/wyW4N7OigizwJWeukcyIPbAv
# jSabnf7+Pu0VrFgoiovRDiyx3zEdmcif/sYQsfch28bZeUz2rtY/9TCA6TD8dC3J
# E3rYkrhLULy7Dc90G6e8BlqmyIjlgp2+VqsS9/wQD7yFylIz0scmbKvFoW2jNrbM
# 1pD2T7m3XDCCBu0wggTVoAMCAQICEAqA7xhLjfEFgtHEdqeVdGgwDQYJKoZIhvcN
# AQELBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEw
# PwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2
# IFNIQTI1NiAyMDI1IENBMTAeFw0yNTA2MDQwMDAwMDBaFw0zNjA5MDMyMzU5NTla
# MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UE
# AxMyRGlnaUNlcnQgU0hBMjU2IFJTQTQwOTYgVGltZXN0YW1wIFJlc3BvbmRlciAy
# MDI1IDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDQRqwtEsae0Oqu
# YFazK1e6b1H/hnAKAd/KN8wZQjBjMqiZ3xTWcfsLwOvRxUwXcGx8AUjni6bz52fG
# Tfr6PHRNv6T7zsf1Y/E3IU8kgNkeECqVQ+3bzWYesFtkepErvUSbf+EIYLkrLKd6
# qJnuzK8Vcn0DvbDMemQFoxQ2Dsw4vEjoT1FpS54dNApZfKY61HAldytxNM89PZXU
# P/5wWWURK+IfxiOg8W9lKMqzdIo7VA1R0V3Zp3DjjANwqAf4lEkTlCDQ0/fKJLKL
# kzGBTpx6EYevvOi7XOc4zyh1uSqgr6UnbksIcFJqLbkIXIPbcNmA98Oskkkrvt6l
# PAw/p4oDSRZreiwB7x9ykrjS6GS3NR39iTTFS+ENTqW8m6THuOmHHjQNC3zbJ6nJ
# 6SXiLSvw4Smz8U07hqF+8CTXaETkVWz0dVVZw7knh1WZXOLHgDvundrAtuvz0D3T
# +dYaNcwafsVCGZKUhQPL1naFKBy1p6llN3QgshRta6Eq4B40h5avMcpi54wm0i2e
# PZD5pPIssoszQyF4//3DoK2O65Uck5Wggn8O2klETsJ7u8xEehGifgJYi+6I03Uu
# T1j7FnrqVrOzaQoVJOeeStPeldYRNMmSF3voIgMFtNGh86w3ISHNm0IaadCKCkUe
# 2LnwJKa8TIlwCUNVwppwn4D3/Pt5pwIDAQABo4IBlTCCAZEwDAYDVR0TAQH/BAIw
# ADAdBgNVHQ4EFgQU5Dv88jHt/f3X85FxYxlQQ89hjOgwHwYDVR0jBBgwFoAU729T
# SunkBnx6yuKQVvYv1Ensy04wDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoG
# CCsGAQUFBwMIMIGVBggrBgEFBQcBAQSBiDCBhTAkBggrBgEFBQcwAYYYaHR0cDov
# L29jc3AuZGlnaWNlcnQuY29tMF0GCCsGAQUFBzAChlFodHRwOi8vY2FjZXJ0cy5k
# aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2
# U0hBMjU2MjAyNUNBMS5jcnQwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL2NybDMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0YW1waW5nUlNBNDA5
# NlNIQTI1NjIwMjVDQTEuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG
# /WwHATANBgkqhkiG9w0BAQsFAAOCAgEAZSqt8RwnBLmuYEHs0QhEnmNAciH45PYi
# T9s1i6UKtW+FERp8FgXRGQ/YAavXzWjZhY+hIfP2JkQ38U+wtJPBVBajYfrbIYG+
# Dui4I4PCvHpQuPqFgqp1PzC/ZRX4pvP/ciZmUnthfAEP1HShTrY+2DE5qjzvZs7J
# IIgt0GCFD9ktx0LxxtRQ7vllKluHWiKk6FxRPyUPxAAYH2Vy1lNM4kzekd8oEARz
# FAWgeW3az2xejEWLNN4eKGxDJ8WDl/FQUSntbjZ80FU3i54tpx5F/0Kr15zW/mJA
# xZMVBrTE2oi0fcI8VMbtoRAmaaslNXdCG1+lqvP4FbrQ6IwSBXkZagHLhFU9HCrG
# /syTRLLhAezu/3Lr00GrJzPQFnCEH1Y58678IgmfORBPC1JKkYaEt2OdDh4GmO0/
# 5cHelAK2/gTlQJINqDr6JfwyYHXSd+V08X1JUPvB4ILfJdmL+66Gp3CSBXG6IwXM
# ZUXBhtCyIaehr0XkBoDIGMUG1dUtwq1qmcwbdUfcSYCn+OwncVUXf53VJUNOaMWM
# ts0VlRYxe5nK+At+DI96HAlXHAL5SlfYxJ7La54i71McVWRP66bW+yERNpbJCjyC
# YG2j+bdpxo/1Cy4uPcU3AWVPGrbn5PhDBf3Froguzzhk++ami+r3Qrx5bIbY3TVz
# giFI7Gq3zWcwggdWMIIFPqADAgECAhADMlFYfN/evhzf5XYSzZUnMA0GCSqGSIb3
# DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFB
# MD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5
# NiBTSEEzODQgMjAyMSBDQTEwHhcNMjUwMzIwMDAwMDAwWhcNMjYwNjAzMjM1OTU5
# WjBeMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExFDASBgNV
# BAcTC01vcnJpc3ZpbGxlMQ8wDQYDVQQKEwZMZW5vdm8xDzANBgNVBAMTBkxlbm92
# bzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOPjJ/+Kdi4SqmdpYRYm
# 5E/ctl9H/KHwC3GK10hQmHGetCCuJkcx+STyvxLIuuzh6CIupbxzDPXQ2x2/5jA6
# 2EROThgMKl/0fV+hwvZhVl45idBUi0qo+91jYeK9kXjjLrxXEsX6A5Uu4Lgl56vr
# 8h6cGZg/te9ozF3k2JN80MIzSj/F769/ZpuGq9i4j1HQ7xq/aoXFlrTD86zSC7YG
# AVU5PSU06ZOOTMAAvGm7ifKv/xQyeO8EE4acIgFB5a8RRC0JQj19eIRBhtfkh1dy
# TX/ocPdsBQICpqo0VXvRb/9iaHj3+r9CWSPtx0kQxRkpHMv/qCtM7kBscljbejLA
# VOXuhWKmNemNGIu7UMIZyro3+XzI4s1biJlGp6bTShs02EbmzlyUJTgithsYgC5n
# X/WRcaHbshvy5S1EJo8m1fi5v/4bj9OTBUOjaYAVKvOjzYE7QR4PhuN/ww8HpGdR
# jLS/eS8Sz3Jxz7EVApPNSzwycDkxAR6Y0w4ymaGy3ZnTOUJjESfwqJvqigjYMcbZ
# +LJOqbLE6bQEmQ+tZiclcdoU4FhleAqQlfksb9kLc5GcU23uIp1aKQ1nji6pxMif
# IHtE5OcMgJzy60tyX/dPpxBGbR3l6+K02v5KI1/GtrVSWxvJHKlXnIMQ4EcgIZBz
# U+NPRgmPG7ZSzYRhpZl/+PrhAgMBAAGjggIDMIIB/zAfBgNVHSMEGDAWgBRoN+Dr
# tjv4XxGG+/5hewiIZfROQjAdBgNVHQ4EFgQUcBJh2GrEdlUHxwi/fkRtYI55VfAw
# PgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5k
# aWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEF
# BQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIx
# Q0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwgZQG
# CCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
# dC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E
# aWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEu
# Y3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBACeB1ob7bkUKbCC40mTr
# HpXQHQbaeE7ymacNpXKyHefcQij+Op9DsduyOHNLbEojHm24k8GiGjx3ZnaZGKTh
# RQHiijGN+H8Qy27SDvw2MzLnyB7XNg+uCPqIf6xWLdtdQ65T7MaBon6BIX/shzxQ
# t+Jpkr1+qcAP6wWCQ0Q0W5I0w5PKb19dMaT26mw6mnGd06pnTvgpCVRnVy8UJtb7
# Ltt7dfE1G0Cz3LdWW9iBVCI73n/DGWhO8fbiK4D4NpdiNnWVfsxhJ7DSb+6RKJXP
# eG3GwGbmuyDD3D2N9mJnW/6VYAiBwnewGRqwA6D20QKPB0QFHlqVHwkyoYIynVcE
# dfM4K3dtxP8mh6IrEEbWfctNLRgnvRsEE/GnAEmpHxLyzWRx+FILzlaZmRPSyYAO
# O8bE4nWNOTKLdpa/OMum6r/qDJmjcLs80aqMlRiG1k4F2grobscDV+lzy65du9+W
# a8qUeY6rZsnHK02DGOf4iWLqEgaUf36QH10MUpGgj/dkK5cwLCpA1+/d+mySgEF3
# 1N2RHkf5bRVq0DsR8AGT76npVtpyRdnIlIHksfB0G8dDjioKEzCneATEUkketoL1
# ML+ZOcM8t2uURmjK8ZecklHZF74jmrkYVyve2HrxcHOr2qPuwOkRQ5NLnYluYKQo
# Qv4KrbHKxS/bQKd55kJZVzTbMYIGSDCCBkQCAQEwfTBpMQswCQYDVQQGEwJVUzEX
# MBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0
# ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhADMlFY
# fN/evhzf5XYSzZUnMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgACh
# AoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAM
# BgorBgEEAYI3AgEVMCMGCSqGSIb3DQEJBDEWBBSYIpJQ15NQ7lrZmFpofSwN37bd
# GTANBgkqhkiG9w0BAQEFAASCAgBhpq1yhg18P+6Wy3Ye2Fyw28oArMkSmzMxRPno
# 9jcDE1endT7mzi1l+aiSgN6Dxi2nEblmNhsDRRYkuc3XMWuFuxSHdMMjDsehe1ZC
# zkoDnEmYYA9LLf3DP81X3FJsY/Rln5ycgZWEa31NXcZRfDxgBIezjCg/7aceZn8G
# kBrDZMjRyCxUympAKing7aQmUs0bAJvrjmD52gLkLkiC+jBP6pMRFex3lzxnWQKy
# ivlTO8Wn/v0x5JN8xvj9cTE14fVTm1MK7GcnmPbHkk83hwkZoNGNJyu8foY1E1tW
# XXkSaBbw8nebqQHCfzV/sp7ufZEVos7K1k9zoOvZTJBkl7gosf6ABP6CLMFURzFL
# KxdfTZOBTRxmljw+EbvlA2YZN0lcjIwkWX0pytXBPClJIeUz+YvR6Hxbmchu4nhv
# NRwU0Hwvkyo0AuQJ4w/v7GRf1n+2EnmfFiKNGahHvHH9szxJhdfVsKRdtuG808Jl
# z0/QXuk414vz7D9b7r6OiB6j0W7ErLOTmNBQVf8NuGR8uUt/XHyQLzSmn3WDYiyc
# +L4bHM/PZ8LW6fEEQR0Vciuuvb4hPswLX6duePZD7jXKhWkEeIp1BkooJ/0/cqTs
# qt81LVAtIszy+4M67MXANTa7QYaPNpH/DKPY4+ET8Msq77CfIHuLF6GSwTk3qEnH
# lH8NPKGCAyYwggMiBgkqhkiG9w0BCQYxggMTMIIDDwIBATB9MGkxCzAJBgNVBAYT
# AlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQg
# VHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEC
# EAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMx
# CwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNjAxMjMxNjQ2NTBaMC8GCSqG
# SIb3DQEJBDEiBCC7eO6sv4uZK0TJ7JWQ7P87bTpBkh5t9FDDMZK/RmxJojANBgkq
# hkiG9w0BAQEFAASCAgBp+7YJoPsCxqid7IhdDiaSLXhq0G7L+tm2pkvA+8aiDHoB
# k4zEHkkk+UtFOvhvS/pt3/JmcFqdHRpCQGiqgf0IIHVDa48pdjiLeLH1EC1ymPN3
# 7UDweqwwrbgbetp9hcy2sz1/2bxRiQiiWIZVS3vKYuseJ9NmzPKmpr41qox7VxL6
# tokXx5G9t00t3Izrryjd9dqRWT81aW98RRSJttcsTKR1YJmCpQUXMoM7FKgEtJMq
# D2pszJ2FRoXzuxLQd2gEbGeL61nraThA+5ZADe6WMlU6dfTa1u+v6ifMrFTSOLC+
# jLzfGdvM0n7bfDfRSoKZCRATt0bg9PB/135rOqr7w3UBwDr6APxa5+qtBJWXNJla
# UqdUyfC2xJF9q5PcM8p0kk9rXH/EukPIP33nr1wf31AupgGMHDAdoh2f+Y9dWXxC
# hSCWqv2KEnu4+nCyNFr+iUY8lwYVf7j5Ag5YfDYhZFuPRazA85drAsjpvTh4/oRz
# cgCAz44wKOd/htvNq4wDfAxpY8/tOfJ41FcoBaMtHhylKIrys6swV9WoZrRJcGB/
# sFCy5yjb06Leu1MCio/xDqaktuYU5Wwj/oPXj3pn2H876/Mkev12X6qV9dm/VyLT
# IwYfxzH+U7XFNyfJDqc8yxi33pp8KOClYJ/BRkI8ah9kXjvjJG4NcVD+i3JG1A==
# SIG # End signature block