Private/Util/AzClient.ps1

Set-StrictMode -Version Latest

function New-AzNetRunContext {
    [CmdletBinding()]
    param()

    [pscustomobject]@{
        RunId          = [guid]::NewGuid().ToString()
        StartedAtUtc   = [datetimeoffset]::UtcNow
        Errors         = [System.Collections.Generic.List[object]]::new()
        SkipCounts     = @{}
        CacheStats     = [ordered]@{ hits = 0; misses = 0; writes = 0; stale = 0 }
        SubscriptionWorkers = [System.Collections.Generic.List[object]]::new()
        VisitedSubs    = [System.Collections.Generic.HashSet[string]]::new(
            [System.StringComparer]::OrdinalIgnoreCase)
        VisitedVNets   = [System.Collections.Generic.HashSet[string]]::new(
            [System.StringComparer]::OrdinalIgnoreCase)
    }
}

function Invoke-AzCall {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$Step,
        [Parameter(Mandatory)][scriptblock]$Action,
        [string]$SubscriptionId,
        [string]$ResourceId,
        [Parameter(Mandatory)]$RunContext,
        [int]$MaxAttempts = 5,
        [int]$InitialBackoffSeconds = 1
    )

    $attempt = 0
    $backoff = $InitialBackoffSeconds

    while ($true) {
        $attempt++
        try {
            return & $Action
        } catch {
            $class = Get-AzNetErrorClass -ErrorRecord $_
            $msg   = $_.Exception.Message

            switch ($class) {
                'AuthorizationFailed' {
                    Write-AzNetLog -Level Verbose -Message "Access denied" -Data @{
                        step = $Step; sub = $SubscriptionId; resource = $ResourceId; class = $class
                    }
                    [void]$RunContext.Errors.Add([pscustomobject]@{
                        SubscriptionId = $SubscriptionId
                        Step           = $Step
                        ResourceId     = $ResourceId
                        Class          = $class
                        Message        = $msg
                        AtUtc          = [datetimeoffset]::UtcNow.ToString('o')
                    })
                    if (-not $RunContext.SkipCounts.ContainsKey($class)) { $RunContext.SkipCounts[$class] = 0 }
                    $RunContext.SkipCounts[$class]++
                    return $null
                }
                'NotFound' {
                    Write-AzNetLog -Level Verbose -Message "Resource missing" -Data @{
                        step = $Step; sub = $SubscriptionId; resource = $ResourceId; class = $class
                    }
                    [void]$RunContext.Errors.Add([pscustomobject]@{
                        SubscriptionId = $SubscriptionId
                        Step           = $Step
                        ResourceId     = $ResourceId
                        Class          = $class
                        Message        = $msg
                        AtUtc          = [datetimeoffset]::UtcNow.ToString('o')
                    })
                    if (-not $RunContext.SkipCounts.ContainsKey($class)) { $RunContext.SkipCounts[$class] = 0 }
                    $RunContext.SkipCounts[$class]++
                    return $null
                }
                'Detached' {
                    Write-AzNetLog -Level Verbose -Message "Resource not attached" -Data @{
                        step = $Step; sub = $SubscriptionId; resource = $ResourceId; class = $class
                    }
                    [void]$RunContext.Errors.Add([pscustomobject]@{
                        SubscriptionId = $SubscriptionId
                        Step           = $Step
                        ResourceId     = $ResourceId
                        Class          = $class
                        Message        = $msg
                        AtUtc          = [datetimeoffset]::UtcNow.ToString('o')
                    })
                    if (-not $RunContext.SkipCounts.ContainsKey($class)) { $RunContext.SkipCounts[$class] = 0 }
                    $RunContext.SkipCounts[$class]++
                    return $null
                }
                { $_ -in 'Throttled','Transient' } {
                    if ($attempt -ge $MaxAttempts) {
                        Write-AzNetLog -Level Verbose -Message "Retry budget exhausted" -Data @{
                            step = $Step; sub = $SubscriptionId; resource = $ResourceId; class = $class; attempts = $attempt
                        }
                        [void]$RunContext.Errors.Add([pscustomobject]@{
                            SubscriptionId = $SubscriptionId
                            Step           = $Step
                            ResourceId     = $ResourceId
                            Class          = $class
                            Message        = $msg
                            AtUtc          = [datetimeoffset]::UtcNow.ToString('o')
                        })
                        if (-not $RunContext.SkipCounts.ContainsKey($class)) { $RunContext.SkipCounts[$class] = 0 }
                        $RunContext.SkipCounts[$class]++
                        return $null
                    }
                    $wait = Get-AzNetRetryAfterSecond -ErrorRecord $_ -Default $backoff
                    $jitter = [double](Get-Random -Minimum 0 -Maximum 1000) / 1000.0
                    $sleep = [math]::Min(30, $wait + $jitter)
                    Write-AzNetLog -Level Verbose -Message "Backing off" -Data @{
                        step = $Step; class = $class; attempt = $attempt; wait = $sleep
                    }
                    Start-Sleep -Seconds $sleep
                    $backoff = [math]::Min($backoff * 2, 30)
                    continue
                }
                default {
                    # Per-resource API failures are recorded in $RunContext.Errors
                    # and reported in the run summary; logging at Verbose keeps
                    # the console quiet during sweeps with detached or
                    # malformed resources. Use -Verbose to surface every call.
                    Write-AzNetLog -Level Verbose -Message "Step failed" -Data @{
                        step = $Step; sub = $SubscriptionId; resource = $ResourceId; class = $class; message = $msg
                    }
                    [void]$RunContext.Errors.Add([pscustomobject]@{
                        SubscriptionId = $SubscriptionId
                        Step           = $Step
                        ResourceId     = $ResourceId
                        Class          = 'Fatal'
                        Message        = $msg
                        AtUtc          = [datetimeoffset]::UtcNow.ToString('o')
                    })
                    if (-not $RunContext.SkipCounts.ContainsKey('Fatal')) { $RunContext.SkipCounts['Fatal'] = 0 }
                    $RunContext.SkipCounts['Fatal']++
                    return $null
                }
            }
        }
    }
}

function Assert-AzConnection {
    [CmdletBinding()]
    param()
    $context = Get-AzContext -ErrorAction SilentlyContinue
    if (-not $context -or -not $context.Account) {
        Write-AzNetLog -Level Info -Message 'No Azure context detected; prompting Connect-AzAccount.'
        $null = Connect-AzAccount -ErrorAction Stop
        $context = Get-AzContext
    }
    if (-not $context) { throw 'Unable to establish an Azure context.' }
    return $context
}

function Get-AzNetAllSubscription {
    [CmdletBinding()]
    param()
    try {
        return @(Get-AzSubscription -ErrorAction Stop |
            Where-Object { $_.State -eq 'Enabled' } |
            Select-Object -ExpandProperty Id)
    } catch {
        Write-AzNetLog -Level Warn -Message "Subscription enumeration failed: $($_.Exception.Message)"
        return @()
    }
}

function Test-AzNetResourceHasId {
    [CmdletBinding()]
    param([object]$Resource)
    # Guards against cmdlet (or stale cache) entries that surface with a
    # missing or empty .Id. Without this, downstream callers pass '' to
    # the mandatory -ResourceId / -Id parameters on Set-AzNetCacheEntry
    # and Add-AzNetNode, which throws "Cannot bind argument to parameter
    # 'ResourceId' because it is an empty string" and escapes the
    # per-step try/catch, killing the rest of the loop.
    if ($null -eq $Resource) { return $false }
    if (-not ($Resource.PSObject.Properties.Name -contains 'Id')) { return $false }
    return -not [string]::IsNullOrEmpty([string]$Resource.Id)
}

function Resolve-AzNetListInvocation {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$CmdletName,
        [string]$ResourceGroupName
    )

    # Returns a parameter hashtable suitable for splatting into the cmdlet if
    # there is a parameter set we can satisfy without prompting; returns $null
    # otherwise so the caller falls back to ID enumeration.
    $cmd = Get-Command $CmdletName -ErrorAction SilentlyContinue
    if (-not $cmd) { return $null }

    $hasRg = -not [string]::IsNullOrEmpty($ResourceGroupName)
    foreach ($ps in $cmd.ParameterSets) {
        $mandatory = @($ps.Parameters | Where-Object { $_.IsMandatory } | ForEach-Object { $_.Name })
        if ($mandatory.Count -eq 0) { return @{} }
        if ($hasRg -and $mandatory.Count -eq 1 -and $mandatory[0] -eq 'ResourceGroupName') {
            return @{ ResourceGroupName = $ResourceGroupName }
        }
    }
    return $null
}

function Get-AzNetTypedResource {
    [CmdletBinding()]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', 'GetByName', Justification = 'Invoked indirectly via `& $GetByName` on the fallback path; the analyzer does not see scriptblock invocations.')]
    param(
        [Parameter(Mandatory)][string]$SubscriptionId,
        [Parameter(Mandatory)]$RunContext,
        [Parameter(Mandatory)][string]$ResourceType,
        [string]$ResourceGroupName,
        [Parameter(Mandatory)][string]$Step,
        [Parameter(Mandatory)][string]$ListCmdlet,
        [Parameter(Mandatory)][scriptblock]$GetByName
    )

    # Fast path: when the typed list cmdlet exposes a parameter set we can
    # satisfy (no mandatory params, or just -ResourceGroupName when we have
    # one), call it directly so a tenant with N firewalls costs one API hit
    # instead of N+1.
    $bulkArgs = Resolve-AzNetListInvocation -CmdletName $ListCmdlet -ResourceGroupName $ResourceGroupName
    if ($null -ne $bulkArgs) {
        $items = Invoke-AzCall -Step $Step -SubscriptionId $SubscriptionId -RunContext $RunContext -Action {
            @(& $ListCmdlet @bulkArgs -ErrorAction Stop)
        }
        if ($null -ne $items) { return @($items) }
    }

    # Fallback: older Az.Network builds expose only -Name+-RG parameter sets,
    # which prompt interactively when the bulk path can't be used. Enumerate
    # IDs via Get-AzResource (always supports list-by-type) and materialize
    # typed objects per resource via the supplied GetByName scriptblock.
    $listArgs = @{ ResourceType = $ResourceType; ErrorAction = 'Stop' }
    if ($ResourceGroupName) { $listArgs.ResourceGroupName = $ResourceGroupName }

    $resources = Invoke-AzCall -Step "$Step.List" -SubscriptionId $SubscriptionId -RunContext $RunContext -Action {
        @(Get-AzResource @listArgs)
    }
    if (-not $resources) { return @() }

    $result = [System.Collections.Generic.List[object]]::new()
    foreach ($r in $resources) {
        $rg   = $r.ResourceGroupName
        $name = $r.Name
        $obj  = Invoke-AzCall -Step $Step -SubscriptionId $SubscriptionId -ResourceId $r.ResourceId -RunContext $RunContext -Action {
            & $GetByName $name $rg
        }
        if ($obj) { $result.Add($obj) | Out-Null }
    }
    return $result.ToArray()
}

function Set-AzNetContext {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)][string]$SubscriptionId,
        [Parameter(Mandatory)]$RunContext
    )

    # Race-safe path: enumerate the available contexts (read-only, no
    # singleton mutation) and pick the one matching this subscription.
    # Multiple parallel runspaces can run this concurrently without
    # clobbering each other's PSAzureContext, which is what the
    # PSDefaultParameterValues['*-Az*:DefaultProfile'] = $ctx pin needs
    # to actually isolate subscriptions per worker. The previous
    # implementation called Set-AzContext (singleton mutation) and then
    # Get-AzContext (singleton read) - between the two, a parallel
    # worker's own Set-AzContext could overwrite the singleton, and
    # this worker's "context" would silently point at the wrong sub.
    try {
        $getContext = Get-Command Get-AzContext -ErrorAction Stop
        if ($getContext.Parameters.ContainsKey('ListAvailable')) {
            $context = Get-AzContext -ListAvailable -ErrorAction Stop |
                Where-Object { $_ -and $_.Subscription -and $_.Subscription.Id -eq $SubscriptionId } |
                Select-Object -First 1
            if ($context) { return $context }
        }
    } catch {
        # Fall through to the mutex-guarded Set-AzContext path below.
        Write-AzNetLog -Level Verbose -Message 'Get-AzContext -ListAvailable failed' -Data @{ error = $_.Exception.Message }
    }

    # Fallback: lookup did not find the subscription (older Az.Accounts,
    # imported context did not carry it, etc). Mutate the process-wide
    # singleton, but serialize across runspaces with a process-named
    # mutex so concurrent workers cannot race. Capture Set-AzContext's
    # own return value so we never read the singleton after releasing
    # the mutex.
    $mutex = [System.Threading.Mutex]::new($false, "Local\AzNetTopology.SetAzContext.$PID")
    $acquired = $false
    try {
        $acquired = $mutex.WaitOne([timespan]::FromMinutes(2))
        if (-not $acquired) {
            throw "Timed out waiting for Set-AzContext lock for subscription $SubscriptionId."
        }
        $setContextArgs = @{ SubscriptionId = $SubscriptionId; ErrorAction = 'Stop' }
        $setContext = Get-Command Set-AzContext -ErrorAction Stop
        if ($setContext.Parameters.ContainsKey('Scope')) { $setContextArgs.Scope = 'Process' }
        return Set-AzContext @setContextArgs
    } catch {
        Write-AzNetLog -Level Warn -Message "Context switch failed for ${SubscriptionId}: $($_.Exception.Message)"
        [void]$RunContext.Errors.Add([pscustomobject]@{
            SubscriptionId = $SubscriptionId
            Step           = 'SetContext'
            ResourceId     = $null
            Class          = 'Fatal'
            Message        = $_.Exception.Message
            AtUtc          = [datetimeoffset]::UtcNow.ToString('o')
        })
        return $null
    } finally {
        if ($acquired) { $mutex.ReleaseMutex() }
        $mutex.Dispose()
    }
}

# SIG # Begin signature block
# MII2tAYJKoZIhvcNAQcCoII2pTCCNqECAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDX3lqmA5Ju58/q
# cnDTB879Tp5H2Yxn7v3U/k9o0JNTHKCCG0YwggXMMIIDtKADAgECAhBUmNLR1FsZ
# lUgTecgRwIeZMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVu
# dGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAy
# MDAeFw0yMDA0MTYxODM2MTZaFw00NTA0MTYxODQ0NDBaMHcxCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jv
# c29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo
# b3JpdHkgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALORKgeD
# Bmf9np3gx8C3pOZCBH8Ppttf+9Va10Wg+3cL8IDzpm1aTXlT2KCGhFdFIMeiVPvH
# or+Kx24186IVxC9O40qFlkkN/76Z2BT2vCcH7kKbK/ULkgbk/WkTZaiRcvKYhOuD
# PQ7k13ESSCHLDe32R0m3m/nJxxe2hE//uKya13NnSYXjhr03QNAlhtTetcJtYmrV
# qXi8LW9J+eVsFBT9FMfTZRY33stuvF4pjf1imxUs1gXmuYkyM6Nix9fWUmcIxC70
# ViueC4fM7Ke0pqrrBc0ZV6U6CwQnHJFnni1iLS8evtrAIMsEGcoz+4m+mOJyoHI1
# vnnhnINv5G0Xb5DzPQCGdTiO0OBJmrvb0/gwytVXiGhNctO/bX9x2P29Da6SZEi3
# W295JrXNm5UhhNHvDzI9e1eM80UHTHzgXhgONXaLbZ7LNnSrBfjgc10yVpRnlyUK
# xjU9lJfnwUSLgP3B+PR0GeUw9gb7IVc+BhyLaxWGJ0l7gpPKWeh1R+g/OPTHU3mg
# trTiXFHvvV84wRPmeAyVWi7FQFkozA8kwOy6CXcjmTimthzax7ogttc32H83rwjj
# O3HbbnMbfZlysOSGM1l0tRYAe1BtxoYT2v3EOYI9JACaYNq6lMAFUSw0rFCZE4e7
# swWAsk0wAly4JoNdtGNz764jlU9gKL431VulAgMBAAGjVDBSMA4GA1UdDwEB/wQE
# AwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIftJqhSobyhmYBAcnz1AQ
# T2ioojAQBgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0BAQwFAAOCAgEAr2rd5hnn
# LZRDGU7L6VCVZKUDkQKL4jaAOxWiUsIWGbZqWl10QzD0m/9gdAmxIR6QFm3FJI9c
# Zohj9E/MffISTEAQiwGf2qnIrvKVG8+dBetJPnSgaFvlVixlHIJ+U9pW2UYXeZJF
# xBA2CFIpF8svpvJ+1Gkkih6PsHMNzBxKq7Kq7aeRYwFkIqgyuH4yKLNncy2RtNwx
# AQv3Rwqm8ddK7VZgxCwIo3tAsLx0J1KH1r6I3TeKiW5niB31yV2g/rarOoDXGpc8
# FzYiQR6sTdWD5jw4vU8w6VSp07YEwzJ2YbuwGMUrGLPAgNW3lbBeUU0i/OxYqujY
# lLSlLu2S3ucYfCFX3VVj979tzR/SpncocMfiWzpbCNJbTsgAlrPhgzavhgplXHT2
# 6ux6anSg8Evu75SjrFDyh+3XOjCDyft9V77l4/hByuVkrrOj7FjshZrM77nq81YY
# uVxzmq/FdxeDWds3GhhyVKVB0rYjdaNDmuV3fJZ5t0GNv+zcgKCf0Xd1WF81E+Al
# GmcLfc4l+gcK5GEh2NQc5QfGNpn0ltDGFf5Ozdeui53bFv0ExpK91IjmqaOqu/dk
# ODtfzAzQNb50GQOmxapMomE2gj4d8yu8l13bS3g7LfU772Aj6PXsCyM2la+YZr9T
# 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggakMIIEjKADAgECAhMzAABzA2ge
# zvWGpRrVAAAAAHMDMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ
# RCBWZXJpZmllZCBDUyBBT0MgQ0EgMDQwHhcNMjYwNDIzMjIxNzAyWhcNMjYwNDI2
# MjIxNzAyWjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMIVmlyZ2luaWExFzAVBgNV
# BAcTDlZpcmdpbmlhIEJlYWNoMRQwEgYDVQQKEwtTZXRoIE1JbGxlcjEUMBIGA1UE
# AxMLU2V0aCBNSWxsZXIwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDi
# ofa8qOqz+DSBEh09HxJlxCDciC4+34MKu7Kms9T9bA8/QHSqECW3yIQyNru8sw1l
# Ma2Ll+06JZKMlJQqkyfvQ0mVTI01VDwId+jMK234aU9sFv1eBWECr7YGZiWitJFX
# 5G+jOe/gb1weLbEr+zMZDc8JniBf3ZFZqlcJ1ZM6FpmeSd72wLC30jiOO8BAC/Ud
# sDgG0F0pxsYoOFO6TndsNZEAJrq++3fZNKs/6qVKWKTH0gztUhrouICkUAwSoMIN
# 8tXb386pXAgFNbOBeiRRlOho0UKgZhLkJS1vmaa0h+Dtt33pMHMPblwU/1bxG5Fw
# 9t6kl99UE4ttVX6/bHudaRgtutWmI4LjmUqvpdy9gd3+3gk3oBjmCYWZJ7DupwN5
# hwg/yFa1gYvpb/midFn5eIP/b6Xfq/2dQYvXLbFFvzGdzUX4BxrbgzYrZKscFcCf
# Z77e8v5GaYzogpUk28cofAoTQeccIN22Vgsmm9z9Y025rL5GTYEsPDca0dBhEcUC
# AwEAAaOCAdYwggHSMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMD0GA1Ud
# JQQ2MDQGCisGAQQBgjdhAQAGCCsGAQUFBwMDBhwrBgEEAYI3YYHR5Y4pgv7dj0iB
# laOJIoHu469rMB0GA1UdDgQWBBShPhVS/1wDO3h/kmNfjd2bHdNXwjAfBgNVHSME
# GDAWgBRrJUHe+2t8/RiACi1/j3ZdqnM9uDBnBgNVHR8EYDBeMFygWqBYhlZodHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJRCUy
# MFZlcmlmaWVkJTIwQ1MlMjBBT0MlMjBDQSUyMDA0LmNybDB0BggrBgEFBQcBAQRo
# MGYwZAYIKwYBBQUHMAKGWGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv
# Y2VydHMvTWljcm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUyMENTJTIwQU9DJTIwQ0El
# MjAwNC5jcnQwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAN
# BgkqhkiG9w0BAQwFAAOCAgEAWiIv8T27YuG5HzK5ag915ZU/PCqxXAJdW5E4Hn1l
# nsNSyoDv5a1cxKptpJlcGiF9Ff7xA6PcmMpzZI4kou7COcsxp7Eb2ZhXBKcdHgqE
# CCVdhIMzG8MOOxTPDtcdHlfpIb34s5ecmsHlyEv9/kdV71TOc1fY/FPsw6CpdsYK
# +RiC+d5hPEhZvLD8LFn/ttkOltiGcboSmznksFOz+Uy37lNUt2xRuBTXLbYvg220
# tYtCzVCAy8Xv2Y3TWbpqfwXmPFBD/h6YPDzROou9zNM4Rf8Oy5m3C84q9jzkbtGE
# Hvp6Nd7/ipAW3LC+5TzSSXBu88f78eK6Bo37KAFitG/gh2iOKEi/uvlDnNc2FJag
# VDJMM3ZXAAWghMfnrDWj5pVLSXJoa4L9cnxAlg4t4G3vTkR+xq+QbOX1nxzbmP/i
# bFV2fxbhpdJ3OzjjJ6/Ns51MMEBdvnRCI+qIQaUDTa4J2j+qNMwrn7cxaX/4By77
# y62Gzd1Qz50lqSxqCADtUwgEYF78H9dPMtipBzJ0C5tai8e8V9GKLdSzIt90Gx6v
# Gou0SpfbFLF+IdCO8SODPPg4o95xeaZtl95yXpDkBt9RNfwVPdfW3EY/vuQgCmWj
# qqTbPrrZ9gzNE1MevKd/n/L5gSFgHwYA6OfKbCqM0wBXsbNa1w6ErPhXYY/Cei1O
# jJwwggcoMIIFEKADAgECAhMzAAAAFjGSjZICZXuaAAAAAAAWMA0GCSqGSIb3DQEB
# DAUAMGMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xNDAyBgNVBAMTK01pY3Jvc29mdCBJRCBWZXJpZmllZCBDb2RlIFNpZ25pbmcg
# UENBIDIwMjEwHhcNMjYwMzI2MTgxMTI5WhcNMzEwMzI2MTgxMTI5WjBaMQswCQYD
# VQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYDVQQD
# EyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1MgQU9DIENBIDA0MIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAylX6yNvoCTDP9G0OTlSjXbzgEsy21FDL17n/
# lZe2BrqHz2mR1aN4DBxeYp0/hjEqSHHyGfarV1NVBuvK8vLzW0LTi+DZt9In16ai
# NfgcogFiztWE9Fp8xu1zzrqE3nlrDWb+RZo8QrEXgWb8s8swsl2W7tREHycVkx+H
# m1MLQIlva6jH/Xg4/8GIYhHzbXiVd2RXomw9s7Qh6/SYRXXfe125wh4EKEyKnNNl
# +cZUSrVBgWvvjrRwQY4if7sAZ805KruBY6WY0Hiba5nWvrq9Qk9o35ViAf8qZ+7u
# 1fbb1vcCWyWLfx9hLSdBjjVsSWe0xLvI1j4p3Tjt5czz+1Lc0v5lQ1feB7nFmpbZ
# rK2us0hvAaBCfOyDPEEm+735vzuNRYWJFL/PViI+REtjuJMcojEn3veQjIrwrmK0
# T9oSr8e3oDzK1oAwwZMTC4KymTvYUTVDJvL5N8OW/UqIBzsiVYcchZvGhV3yMYKg
# xeEtIOG4W4Z85Y5kpQi5bpjGXFxRg46RdrTaALt1RhRmLR7U0jVSr2aYAd2+Mp2q
# A5Gz3/loOOdt47eFZ3mrAYGYQtbK2SNjQpwgQX4Iy6tOKahCgFhKIcltitvSkpJB
# 77eVWhNWnN2LfqMojszEue7V8EAySxry4PzlxTtFTb3Mw53XyH12BMQf2m9j7jEs
# HeVSATsCAwEAAaOCAdwwggHYMA4GA1UdDwEB/wQEAwIBhjAQBgkrBgEEAYI3FQEE
# AwIBADAdBgNVHQ4EFgQUayVB3vtrfP0YgAotf492XapzPbgwVAYDVR0gBE0wSzBJ
# BgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
# a2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBi
# AEMAQTASBgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFNlBKbAPD2Ns72nX
# 9c0pnqRIajDmMHAGA1UdHwRpMGcwZaBjoGGGX2h0dHA6Ly93d3cubWljcm9zb2Z0
# LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMElEJTIwVmVyaWZpZWQlMjBDb2Rl
# JTIwU2lnbmluZyUyMFBDQSUyMDIwMjEuY3JsMH0GCCsGAQUFBwEBBHEwbzBtBggr
# BgEFBQcwAoZhaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9N
# aWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ29kZSUyMFNpZ25pbmclMjBQQ0El
# MjAyMDIxLmNydDANBgkqhkiG9w0BAQwFAAOCAgEABtVQXlR01UQZY5XGQ9yIjMcD
# 8jI0MizWhJ1buZjg5toUQSXx/BrASwE5qxwHPBeO45pOQp6VD4iILgm8OmfylY+A
# 7KIqttvDUizC3sBXxjK4u7sDRiyEguXHKfL1HQAwxCLEtnRPkCPTsJA6b917lA+3
# foQIHC1XDDpdQLHxGbbGXp4Rr0mFK5vxbi6tAahBi/RlzOXPh6PavKPlZ/0vhlkD
# dsvoJETtebNJCNOZ1Kav3Tg+K4va4FbOrYqRHdGGahoA/gmTYmmVqw0zkGzT53Hd
# hfajrFGttJomK7qE+T8CQGiPkEIkxNmSXjCTpDqc4U1IKlTGcGYnRFGSgqrnWnkA
# NPFsJ5EDHysh82lPI+PFC3FOIVMLzLL+30rqznvRgHUUAj7xfFnEiuaAx3vFVSTO
# Lb+iigpvdR6i8fSWpgYESOkdkn2N57tuhBs57tKwoP++vc/MVpuD1XAtmWi+lZSl
# ahadTbDfGKjMn+bfm2xlW9PZ6BSnCRv1MMhpcUZkAZX3gVEMef8rZc2c7BJ4ayRf
# X0wH43vI9znV+ZRJ3j0xUC0Zb82RQalF5yHkCr93x0IwvZtn6P2dNQyCP6qd3fC4
# RlVFtAQhtOH0cByTR/Iqqghv6qHzL/pMptgMQQ5x8zYEYy+tCThYgYIrq7y4WEDY
# QfeSlqIxQOrIUJ4IJDEwggeeMIIFhqADAgECAhMzAAAAB4ejNKN7pY4cAAAAAAAH
# MA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3Nv
# ZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVudGl0eSBWZXJp
# ZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAyMDAeFw0yMTA0
# MDEyMDA1MjBaFw0zNjA0MDEyMDE1MjBaMGMxCzAJBgNVBAYTAlVTMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xNDAyBgNVBAMTK01pY3Jvc29mdCBJRCBW
# ZXJpZmllZCBDb2RlIFNpZ25pbmcgUENBIDIwMjEwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCy8MCvGYgo4t1UekxJbGkIVQm0Uv96SvjB6yUo92cXdylN
# 65Xy96q2YpWCiTas7QPTkGnK9QMKDXB2ygS27EAIQZyAd+M8X+dmw6SDtzSZXyGk
# xP8a8Hi6EO9Zcwh5A+wOALNQbNO+iLvpgOnEM7GGB/wm5dYnMEOguua1OFfTUITV
# MIK8faxkP/4fPdEPCXYyy8NJ1fmskNhW5HduNqPZB/NkWbB9xxMqowAeWvPgHtpz
# yD3PLGVOmRO4ka0WcsEZqyg6efk3JiV/TEX39uNVGjgbODZhzspHvKFNU2K5MYfm
# Hh4H1qObU4JKEjKGsqqA6RziybPqhvE74fEp4n1tiY9/ootdU0vPxRp4BGjQFq28
# nzawuvaCqUUF2PWxh+o5/TRCb/cHhcYU8Mr8fTiS15kRmwFFzdVPZ3+JV3s5MulI
# f3II5FXeghlAH9CvicPhhP+VaSFW3Da/azROdEm5sv+EUwhBrzqtxoYyE2wmuHKw
# s00x4GGIx7NTWznOm6x/niqVi7a/mxnnMvQq8EMse0vwX2CfqM7Le/smbRtsEeOt
# bnJBbtLfoAsC3TdAOnBbUkbUfG78VRclsE7YDDBUbgWt75lDk53yi7C3n0WkHFU4
# EZ83i83abd9nHWCqfnYa9qIHPqjOiuAgSOf4+FRcguEBXlD9mAInS7b6V0UaNwID
# AQABo4ICNTCCAjEwDgYDVR0PAQH/BAQDAgGGMBAGCSsGAQQBgjcVAQQDAgEAMB0G
# A1UdDgQWBBTZQSmwDw9jbO9p1/XNKZ6kSGow5jBUBgNVHSAETTBLMEkGBFUdIAAw
# QTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9E
# b2NzL1JlcG9zaXRvcnkuaHRtMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMA8G
# A1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUyH7SaoUqG8oZmAQHJ89QEE9oqKIw
# gYQGA1UdHwR9MHsweaB3oHWGc2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv
# cHMvY3JsL01pY3Jvc29mdCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIwUm9v
# dCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAyMC5jcmwwgcMGCCsGAQUF
# BwEBBIG2MIGzMIGBBggrBgEFBQcwAoZ1aHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBJZGVudGl0eSUyMFZlcmlmaWNhdGlv
# biUyMFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMjAuY3J0MC0G
# CCsGAQUFBzABhiFodHRwOi8vb25lb2NzcC5taWNyb3NvZnQuY29tL29jc3AwDQYJ
# KoZIhvcNAQEMBQADggIBAH8lKp7+1Kvq3WYK21cjTLpebJDjW4ZbOX3HD5ZiG84v
# jsFXT0OB+eb+1TiJ55ns0BHluC6itMI2vnwc5wDW1ywdCq3TAmx0KWy7xulAP179
# qX6VSBNQkRXzReFyjvF2BGt6FvKFR/imR4CEESMAG8hSkPYso+GjlngM8JPn/ROU
# rTaeU/BRu/1RFESFVgK2wMz7fU4VTd8NXwGZBe/mFPZG6tWwkdmA/jLbp0kNUX7e
# lxu2+HtHo0QO5gdiKF+YTYd1BGrmNG8sTURvn09jAhIUJfYNotn7OlThtfQjXqe0
# qrimgY4Vpoq2MgDW9ESUi1o4pzC1zTgIGtdJ/IvY6nqa80jFOTg5qzAiRNdsUvzV
# koYP7bi4wLCj+ks2GftUct+fGUxXMdBUv5sdr0qFPLPB0b8vq516slCfRwaktAxK
# 1S40MCvFbbAXXpAZnU20FaAoDwqq/jwzwd8Wo2J83r7O3onQbDO9TyDStgaBNlHz
# MMQgl95nHBYMelLEHkUnVVVTUsgC0Huj09duNfMaJ9ogxhPNThgq3i8w3DAGZ61A
# MeF0C1M+mU5eucj1Ijod5O2MMPeJQ3/vKBtqGZg4eTtUHt/BPjN74SsJsyHqAdXV
# S5c+ItyKWg3Eforhox9k3WgtWTpgV4gkSiS4+A09roSdOI4vrRw+p+fL4WrxSK5n
# MYIaxDCCGsACAQEwcTBaMQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMSswKQYDVQQDEyJNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ1Mg
# QU9DIENBIDA0AhMzAABzA2gezvWGpRrVAAAAAHMDMA0GCWCGSAFlAwQCAQUAoIGQ
# MBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgor
# BgEEAYI3AgEVMCQGCisGAQQBgjcCAQwxFjAUoA6ADABTAEgAQQAyADUANqECgAAw
# LwYJKoZIhvcNAQkEMSIEIKoQ/P7HmE7oTuk2N/tqNqx8SN+e4LoeWBS0UHUX8QO6
# MA0GCSqGSIb3DQEBAQUABIIBgI5WYOvqQgh4JLtysDcxPQQm+PwLi5tngE5nSDlZ
# 8xU9bh/h+ECuj2Me7LBOZgRwVKC0pj0tI3La4yXyb6oq8F8xSwSRaikk1LonqGRh
# 9hO/hJ7QI3ushEq7hkwLosuxqTMC6RijPSmqmkqTkJK+ptBQIUfDmd+hG4zfWN0Q
# XILG/jMTzEnmAqYp8MPn7s/Xlj2nRbrJLmZRJ+4YIswB+nIP+CmVU6qTumsZJrzy
# Z5+lFT3KDKs9APz7/WuhRJ/eDCcN0IxsYtFdeBAcaiC+U8pAE0XWFR1PniZN8BFg
# cfPGdpIIhxwejY+4GodF4zm5EGHfD+co8uYvSrRIyS/8wQTNvFng6FruP0ajNZp3
# sHe25mLWh2jHQS6dfqt0hKfymeM0NIoZ3lSvI4qepwGP/M2Uc7VhDTlwlkRWAvRR
# WUufk9s8Q5qEbkDhhstyXdTJ28+cz9+Kpxbp1rt0Hq4IGftAqqNwtVNC4X5xGU68
# gtUQwFH+RrpbO0KSMFGITGgXL6GCGBEwghgNBgorBgEEAYI3AwMBMYIX/TCCF/kG
# CSqGSIb3DQEHAqCCF+owghfmAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFiBgsqhkiG
# 9w0BCRABBKCCAVEEggFNMIIBSQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFlAwQC
# AQUABCAeAAFpkOUzEm3XKbBT+AZbd2jQprsH4ApFW8MiNWhl2wIGaeiA8e9qGBMy
# MDI2MDQyNDIyMTg1NS45NTNaMASAAgH0oIHhpIHeMIHbMQswCQYDVQQGEwJVUzET
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmlj
# YSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046N0QwMC0wNUUw
# LUQ5NDcxNTAzBgNVBAMTLE1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWUgU3RhbXBp
# bmcgQXV0aG9yaXR5oIIPITCCB4IwggVqoAMCAQICEzMAAAAF5c8P/2YuyYcAAAAA
# AAUwDQYJKoZIhvcNAQEMBQAwdzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jv
# c29mdCBDb3Jwb3JhdGlvbjFIMEYGA1UEAxM/TWljcm9zb2Z0IElkZW50aXR5IFZl
# cmlmaWNhdGlvbiBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDIwMB4XDTIw
# MTExOTIwMzIzMVoXDTM1MTExOTIwNDIzMVowYTELMAkGA1UEBhMCVVMxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1
# YmxpYyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCefOdSY/3gxZ8FfWO1BiKjHB7X55cz0RMFvWVGR3eRwV1w
# b3+yq0OXDEqhUhxqoNv6iYWKjkMcLhEFxvJAeNcLAyT+XdM5i2CgGPGcb95WJLiw
# 7HzLiBKrxmDj1EQB/mG5eEiRBEp7dDGzxKCnTYocDOcRr9KxqHydajmEkzXHOeRG
# wU+7qt8Md5l4bVZrXAhK+WSk5CihNQsWbzT1nRliVDwunuLkX1hyIWXIArCfrKM3
# +RHh+Sq5RZ8aYyik2r8HxT+l2hmRllBvE2Wok6IEaAJanHr24qoqFM9WLeBUSudz
# +qL51HwDYyIDPSQ3SeHtKog0ZubDk4hELQSxnfVYXdTGncaBnB60QrEuazvcob9n
# 4yR65pUNBCF5qeA4QwYnilBkfnmeAjRN3LVuLr0g0FXkqfYdUmj1fFFhH8k8YBoz
# rEaXnsSL3kdTD01X+4LfIWOuFzTzuoslBrBILfHNj8RfOxPgjuwNvE6YzauXi4or
# p4Sm6tF245DaFOSYbWFK5ZgG6cUY2/bUq3g3bQAqZt65KcaewEJ3ZyNEobv35Nf6
# xN6FrA6jF9447+NHvCjeWLCQZ3M8lgeCcnnhTFtyQX3XgCoc6IRXvFOcPVrr3D9R
# PHCMS6Ckg8wggTrtIVnY8yjbvGOUsAdZbeXUIQAWMs0d3cRDv09SvwVRd61evQID
# AQABo4ICGzCCAhcwDgYDVR0PAQH/BAQDAgGGMBAGCSsGAQQBgjcVAQQDAgEAMB0G
# A1UdDgQWBBRraSg6NS9IY0DPe9ivSek+2T3bITBUBgNVHSAETTBLMEkGBFUdIAAw
# QTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9E
# b2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsGAQQB
# gjcUAgQMHgoAUwB1AGIAQwBBMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU
# yH7SaoUqG8oZmAQHJ89QEE9oqKIwgYQGA1UdHwR9MHsweaB3oHWGc2h0dHA6Ly93
# d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMElkZW50aXR5
# JTIwVmVyaWZpY2F0aW9uJTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5
# JTIwMjAyMC5jcmwwgZQGCCsGAQUFBwEBBIGHMIGEMIGBBggrBgEFBQcwAoZ1aHR0
# cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBJ
# ZGVudGl0eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1
# dGhvcml0eSUyMDIwMjAuY3J0MA0GCSqGSIb3DQEBDAUAA4ICAQBfiHbHfm21WhV1
# 50x4aPpO4dhEmSUVpbixNDmv6TvuIHv1xIs174bNGO/ilWMm+Jx5boAXrJxagRhH
# QtiFprSjMktTliL4sKZyt2i+SXncM23gRezzsoOiBhv14YSd1Klnlkzvgs29XNjT
# +c8hIfPRe9rvVCMPiH7zPZcw5nNjthDQ+zD563I1nUJ6y59TbXWsuyUsqw7wXZoG
# zZwijWT5oc6GvD3HDokJY401uhnj3ubBhbkR83RbfMvmzdp3he2bvIUztSOuFzRq
# rLfEvsPkVHYnvH1wtYyrt5vShiKheGpXa2AWpsod4OJyT4/y0dggWi8g/tgbhmQl
# ZqDUf3UqUQsZaLdIu/XSjgoZqDjamzCPJtOLi2hBwL+KsCh0Nbwc21f5xvPSwym0
# Ukr4o5sCcMUcSy6TEP7uMV8RX0eH/4JLEpGyae6Ki8JYg5v4fsNGif1OXHJ2IWG+
# 7zyjTDfkmQ1snFOTgyEX8qBpefQbF0fx6URrYiarjmBprwP6ZObwtZXJ23jK3Fg/
# 9uqM3j0P01nzVygTppBabzxPAh/hHhhls6kwo3QLJ6No803jUsZcd4JQxiYHHc+Q
# /wAMcPUnYKv/q2O444LO1+n6j01z5mggCSlRwD9faBIySAcA9S8h22hIAcRQqIGE
# jolCK9F6nK9ZyX4lhthsGHumaABdWzCCB5cwggV/oAMCAQICEzMAAABV2d1pJij5
# +OIAAAAAAFUwDQYJKoZIhvcNAQEMBQAwYTELMAkGA1UEBhMCVVMxHjAcBgNVBAoT
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1Ymxp
# YyBSU0EgVGltZXN0YW1waW5nIENBIDIwMjAwHhcNMjUxMDIzMjA0NjQ5WhcNMjYx
# MDIyMjA0NjQ5WjCB2zELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UE
# CxMeblNoaWVsZCBUU1MgRVNOOjdEMDAtMDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNy
# b3NvZnQgUHVibGljIFJTQSBUaW1lIFN0YW1waW5nIEF1dGhvcml0eTCCAiIwDQYJ
# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL25H5IeWUiz9DAlFmn2sPymaFWbvYkM
# fK+ScIWb3a1IvOlIwghUDjY0Gp6yMRhfYURiGS0GedIB6ywvuH6VBCX3+bdOFcAc
# lgtv21jrpOjZmk4fSaT2Q3BszUfeUJa8o3xI7ZfoMY9dszTxHQAz6ZVX87fHGEVh
# QcfxW33IdPJOj/ae419qtYxT21MVmCfsTshgtWioQxmOW/vMC9/b+qgtBxSMf798
# vm3qfmhF6KCvFaHlivrM32hY16PGE3L0PFC+LM7vRxU7mTb+r76CeybvqOWk4+db
# KYftPhV1t/E5S/6wwXeYmu/Y7JC7Tnh2w45G5Y4pcM3oHMb/YuPRdOWa0v+RC2Qg
# mNVWqjuxDiylWscXQDuaMtb29AcdGUVV9ZsRY2M2sthAtOdZOshiR5ufMtaHtiCk
# Wv0jNfgUxrHurxzYuUNneWZ6EfQDgFAw8CSCKkSOK2c9jEop4ddVq10xvbqxdrqM
# neVXvvIcXrPQAXj9j2ECpV2EwMb3Wnmpw00P78JpzPsk3Fs61ZvOGd/F1RcOBu6f
# 2TWdp7HL7+rq7tgHr13MldbfIWu4lpoYYE1gTQa1Yrg5XN4j7zs9klT2z3qocmPz
# V8DWQgIHNh+aTs7bujMEMQyI7Xt1zPxZCgcR6H0tmmzU/9BxvsWbRalCQ2sYGyWu
# pTdc4e7KY7kPAgMBAAGjggHLMIIBxzAdBgNVHQ4EFgQUVgRfEG3cCAPwyL+pyRbK
# wdesZbYwHwYDVR0jBBgwFoAUa2koOjUvSGNAz3vYr0npPtk92yEwbAYDVR0fBGUw
# YzBhoF+gXYZbaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWlj
# cm9zb2Z0JTIwUHVibGljJTIwUlNBJTIwVGltZXN0YW1waW5nJTIwQ0ElMjAyMDIw
# LmNybDB5BggrBgEFBQcBAQRtMGswaQYIKwYBBQUHMAKGXWh0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwUHVibGljJTIwUlNB
# JTIwVGltZXN0YW1waW5nJTIwQ0ElMjAyMDIwLmNydDAMBgNVHRMBAf8EAjAAMBYG
# A1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDBmBgNVHSAEXzBd
# MFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jv
# c29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wCAYGZ4EMAQQCMA0G
# CSqGSIb3DQEBDAUAA4ICAQBSHuGSVHvalCnFnlsqXIQefH1xP2SFr9g+Vz+f5P7Q
# eywjfQb5jUlSmd1XnJUDPe/MHxL7r3TEElL+mNtG6CDPAytStSFPXD9tTBtBMYh8
# Wqo64pH9qm361yIqeBH979mzWCkMQsTd0nM6dUl9B+7qiti+ToXwxIl39eYqLuYY
# fhD2mqqePXMzUKSQzkf73yYIVHP6nLJQz4aAmaWcfG9jg78sBkDV8KpW7JgktuLh
# phJEN1B+SVHjenPdcmrFXIUu/K4jK5ukfWaQIjuaXzSjBlNjC5tQN6adPfA3GxUw
# HPeR4ekL5If/9vBf13tmzBW+gy+0sNGTveb9IL9GU8iX8UvywsX62nhCCPRUhTig
# DBKdczRUrNrntBhowbfchBDFML8avRMRc9Gmc2JvIryX336SFQ51//q1UU2HMSJE
# MhWLJSIWJVhfUowsOa+PampIzETYfFvTu2mqKJUlWZXkGYxrdCvCczJcqeoadpW1
# ul6kcdnDh228SQ8ZhDc6IRlM4iNd5SNoNgX+aom3wuGyjUaSaPZWxPB1G2NKiYhP
# Lt0lPHg0Gskj1zhISY8UQkMMDr3o2JgRuT+wnJEDQUp55ddvhSkSoD6I9DL/s+Tj
# IY/c9jLaW5xywJHqdKHUApRMsghv7kebSua1upmR+TquelFktDSOjVdSRkuya4uo
# xTGCB0Mwggc/AgEBMHgwYTELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGlt
# ZXN0YW1waW5nIENBIDIwMjACEzMAAABV2d1pJij5+OIAAAAAAFUwDQYJYIZIAWUD
# BAIBBQCgggScMBEGCyqGSIb3DQEJEAIPMQIFADAaBgkqhkiG9w0BCQMxDQYLKoZI
# hvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI2MDQyNDIyMTg1NVowLwYJKoZIhvcN
# AQkEMSIEICEDudfhy0TA+wuqODYNhwSFw/2mnx7IGd3LiEuM4VwPMIG5BgsqhkiG
# 9w0BCRACLzGBqTCBpjCBozCBoAQg2Lk8l2SGYru/ff7+D2qrJnkswcYdK6pGKu7G
# GGr4/s0wfDBlpGMwYTELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZXN0
# YW1waW5nIENBIDIwMjACEzMAAABV2d1pJij5+OIAAAAAAFUwggNeBgsqhkiG9w0B
# CRACEjGCA00wggNJoYIDRTCCA0EwggIpAgEBMIIBCaGB4aSB3jCB2zELMAkGA1UE
# BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
# BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0
# IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjdE
# MDAtMDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1l
# IFN0YW1waW5nIEF1dGhvcml0eaIjCgEBMAcGBSsOAwIaAxUAHTtUAYJlv7bgWVeR
# Bo4X7FeHDeqgZzBlpGMwYTELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGlt
# ZXN0YW1waW5nIENBIDIwMjAwDQYJKoZIhvcNAQELBQACBQDtlkswMCIYDzIwMjYw
# NDI0MjAwNDAwWhgPMjAyNjA0MjUyMDA0MDBaMHQwOgYKKwYBBAGEWQoEATEsMCow
# CgIFAO2WSzACAQAwBwIBAAICB2IwBwIBAAICEqEwCgIFAO2XnLACAQAwNgYKKwYB
# BAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGG
# oDANBgkqhkiG9w0BAQsFAAOCAQEAA8nVF5Nz8seuaTpJXuag0WJ2FElwsIo9DPh9
# Xq//OKRfgoV5Y4iFWkhMVd+0ZD3NHpWFxWP7Ju1pkNugUnrMVnmyIbbeb18DbDa1
# wcoae1PCu80Bq/8bKdX/IeAGAWGASx6CueYu7+OQYa5BEx9tWd1Jk4xGDxKawKJb
# FJTCuWPUY4upG/j+Z4JUCH9kfrHdBcTuAdLqPCfPKgBTzZGZvQxo29QK6BIfM2+b
# 3PkX28Xrw3ON6ZCFoN1na5hMmRlFOxb88PS+MJzLEFcoVzpbixxI5KcnQ/c0AGwe
# uVlUmHRfhDG2ADHfp32vScNhgU1n06lq6v7Zk4V1afL+GtfjfzANBgkqhkiG9w0B
# AQEFAASCAgCxPPayXIe1iBksmUHcp3JFs+CBeg3mpRYlItaA6g/jhs5rsvxDxBaD
# hbIKxou8zl9/nSBHvsifk9kRvz33Nf23G5FSkO/A28hsUujQbw1rwXefo81TiDiX
# BibKShtbEGQGuifpTzDN7zhyKl1PSTKKLy/U8j1L2mBy8nU47aEnM3eTgSH7+V4A
# gEpsa16sHvs0PHkwn/RLlg4PKrOWCAju1IxdiZ1AccYCCAK9AxgyBcFW6L+/tmcx
# S8cEfLSjXNBhl0uLWeFJZNqRYu9suI+CWKA2uGUZVfiPWegQCQ37Re+jbjYi27yD
# pASyQolvD4IjAumT3hyIAm61kDBWAN5+2zzltI46XtT+Y4xS6hNQqXZyGpVmQDNz
# Izf7qVSgUzqKMALMMg3tVztNC5y7WuR4fvJqYFij9RMg5rP81c88qDMFBGPmpnpb
# LSBKVhrA2s76eOViuAbasBMHPWnajwhS14+64zOGkmvmkhJ5mXXbkazo8efH/5wh
# QinUeuaANNEALgVMF1TPwGhovXFEJ2FKUU/HyoeleQN1dwY6qBt6tMb4EWcOsXNg
# xz/CZRtASumdVuOTOpm/WDRhgi+sWO55g2It3q1DthY1pY9fRYtDbsAcH97Y9LLz
# 74DtyxZTS2uwTZDKZryHPRe/UUx8f7exgGEqHIgJXWQZpJvkhY7Pxg==
# SIG # End signature block