helpers/cisco-wlc/Test-CiscoWLC-Batch.ps1

#Requires -Version 5.1
<#
.SYNOPSIS
    Test the updated Export-CiscoWLCAPDevicesToWUG.ps1 with a small batch of APs.
 
.DESCRIPTION
    Validates that the corrected discovery script works end-to-end with a small
    batch (5-10 APs) before scaling to the full 1728 APs.
 
.NOTES
    - Requires PowerShell 5.1 (Windows PowerShell)
    - Requires WhatsUpGoldPS module (loaded from local repo)
    - Requires WhatsUp Gold connection via Connect-WUGServer
    - Requires WLC AP inventory at C:\Users\jayal\AppData\Local\WhatsUpGoldPS\DiscoveryHelpers\Output\summary\wireless-ap-inventory-summary.json
#>


param(
    [int]$BatchSize = 5,
    [switch]$SkipCleanup
)

$ErrorActionPreference = 'Stop'

# Get repo root and load local WhatsUpGoldPS module
$repoRoot = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$localPsm1 = Join-Path $repoRoot 'WhatsUpGoldPS.psm1'

Write-Host "Batch Test: Cisco WLC AP Discovery" -ForegroundColor Cyan
Write-Host "=====================================" -ForegroundColor Cyan
Write-Host ""

# Load module
Write-Host "Loading WhatsUpGoldPS module from: $localPsm1" -ForegroundColor Yellow
if (-not (Test-Path $localPsm1)) {
    Write-Error "Module file not found: $localPsm1"
    exit 1
}
$moduleName = 'WhatsUpGoldPS'
Get-Module -Name $moduleName -ErrorAction SilentlyContinue | Remove-Module -Force
Import-Module $localPsm1 -Force -Scope Global -ErrorAction Stop
Write-Host "✓ Module loaded" -ForegroundColor Green

# Connect to WUG
Write-Host "Connecting to WhatsUp Gold server..." -ForegroundColor Yellow
Connect-WUGServer -serverUri '192.168.74.74' -Port 9644 -IgnoreSSLErrors -ErrorAction Stop
Write-Host "✓ Connected" -ForegroundColor Green

# Load inventory
$inventoryPath = Join-Path $env:LOCALAPPDATA 'WhatsUpGoldPS\DiscoveryHelpers\Output\summary\wireless-ap-inventory-summary.json'
Write-Host "Loading AP inventory from: $inventoryPath" -ForegroundColor Yellow
if (-not (Test-Path $inventoryPath)) {
    Write-Error "Inventory file not found: $inventoryPath"
}
$inventory = Get-Content -Raw -Path $inventoryPath | ConvertFrom-Json
Write-Host "✓ Inventory loaded: $($inventory.Count) APs total" -ForegroundColor Green

# Select small batch
$batch = @($inventory | Select-Object -First $BatchSize)
Write-Host ""
Write-Host "Test Batch ($($batch.Count) APs):" -ForegroundColor Cyan
foreach ($ap in $batch) {
    Write-Host " - $($ap.APName) (MAC: $($ap.APMac))"
}

# Build device plan for batch
Write-Host ""
Write-Host "Building device plan for batch..." -ForegroundColor Yellow
$devicePlan = @{}
$wlcAddress = '192.168.75.33'

foreach ($ap in $batch) {
    $apKey = if ($ap.APMac) { "AP-$($ap.APMac)" } else { "AP-$($ap.APName)" }
    $displayName = if ($ap.APName -and $ap.APName -ne '') { $ap.APName } else { $ap.APMac }
    
    $devicePlan[$apKey] = @{
        Name           = $displayName
        IP             = $wlcAddress
        WLCAddress     = $wlcAddress
        SNMPInstance   = if ($ap.IndexSuffix) { $ap.IndexSuffix } else { '1' }
        APMac          = $ap.APMac
        Attrs          = @{
            'AP_Name'        = $displayName
            'AP_MAC'         = if ($ap.APMac) { $ap.APMac } else { 'N/A' }
            'AP_Uptime'      = if ($ap.ApUptime) { $ap.ApUptime } else { '' }
            'AP_AdminStatus' = if ($ap.AdminStatus) { $ap.AdminStatus } else { '' }
            'AP_PowerStatus' = if ($ap.PowerStatus) { $ap.PowerStatus } else { '' }
        }
        Items          = @(
            @{
                ItemType = 'ActiveMonitor'
                Name     = 'Cisco WLC AP Admin Status'
            }
        )
    }
}
Write-Host "✓ Device plan built: $($devicePlan.Count) devices" -ForegroundColor Green

# Step 1: Create monitor library entry if needed
Write-Host ""
Write-Host "Step 1: Checking/Creating Monitor Library..." -ForegroundColor Cyan
$monitorName = 'Cisco WLC AP Admin Status'

try {
    $found = @(Get-WUGActiveMonitor -Search $monitorName -ErrorAction SilentlyContinue)
    $existing = $found | Where-Object { $_.TemplateName -eq $monitorName } | Select-Object -First 1
    if (-not $existing) { $existing = $found | Select-Object -First 1 }
    
    if ($existing) {
        $monitorId = if ($existing.PSObject.Properties['TemplateId']) { $existing.TemplateId } else { $existing.id }
        Write-Host "✓ Monitor exists: $monitorName (TemplateId: $monitorId)" -ForegroundColor Green
    }
    else {
        Write-Host "Creating monitor: $monitorName" -ForegroundColor DarkGray
        $monResult = Add-WUGActiveMonitor -Type SNMP `
            -Name $monitorName `
            -SnmpOID '1.3.6.1.4.1.9.9.513.1.1.1.1' `
            -SnmpCheckType 'constant' `
            -SnmpValue '1' `
            -Timeout 10 `
            -ErrorAction Stop
        
        Start-Sleep -Milliseconds 200
        $found = @(Get-WUGActiveMonitor -Search $monitorName -ErrorAction SilentlyContinue)
        $mon = $found | Where-Object { $_.TemplateName -eq $monitorName } | Select-Object -First 1
        if (-not $mon) { $mon = $found | Select-Object -First 1 }
        
        if ($mon -and $mon.TemplateId) {
            $monitorId = $mon.TemplateId
            Write-Host "✓ Monitor created: $monitorName (TemplateId: $monitorId)" -ForegroundColor Green
        }
        else {
            Write-Error "Monitor created but ID not found"
        }
    }
}
catch {
    Write-Error "Failed to handle monitor: $_"
}

# Step 2: Check for existing devices
Write-Host ""
Write-Host "Step 2: Checking for Existing Devices..." -ForegroundColor Cyan
$existingDevices = @{}
$newDevices = @()

foreach ($key in @($devicePlan.Keys)) {
    $dev = $devicePlan[$key]
    try {
        $searchResults = @(Get-WUGDevice -SearchValue $dev.Name -ErrorAction SilentlyContinue)
        $existingDevice = $searchResults | Where-Object {
            $_.displayName -eq $dev.Name -or
            $_.displayName -eq "$($dev.Name) (AP)" -or
            $_.hostName -eq $dev.Name
        } | Select-Object -First 1
        
        if ($existingDevice) {
            $existingDevices[$key] = $existingDevice.id
            Write-Host " ✓ Found existing: $($dev.Name) (ID: $($existingDevice.id))" -ForegroundColor DarkGray
        }
        else {
            $newDevices += $key
        }
    }
    catch {
        Write-Host " ⚠ Search error for $($dev.Name): $_" -ForegroundColor Yellow
        $newDevices += $key
    }
}
Write-Host "✓ Found $($existingDevices.Count) existing, $($newDevices.Count) new" -ForegroundColor Green

# Step 3: Create new devices
Write-Host ""
Write-Host "Step 3: Creating New Devices..." -ForegroundColor Cyan
$createdDevices = @{}

foreach ($key in $newDevices) {
    $dev = $devicePlan[$key]
    $displayName = "$($dev.Name) (AP)"
    $addIP = if ($dev.IP) { $dev.IP } else { '0.0.0.0' }
    
    # Build attributes
    $devAttrs = @()
    foreach ($attrName in $dev.Attrs.Keys) {
        $attrVal = $dev.Attrs[$attrName]
        if ($attrVal) { $devAttrs += @{ name = $attrName; value = "$attrVal" } }
    }
    
    try {
        $splat = @{
            displayName            = $displayName
            DeviceAddress          = $addIP
            Hostname               = $dev.Name
            Brand                  = 'Cisco'
            Note                   = "Cisco WLC AP (batch test)"
            NoDefaultActiveMonitor = $true
        }
        if ($devAttrs.Count -gt 0) { $splat['Attributes'] = $devAttrs }
        
        $devResult = Add-WUGDeviceTemplate @splat
        
        # Extract device ID
        $newDeviceId = $null
        if ($devResult -is [array] -and $devResult.Count -gt 0) {
            $firstElem = $devResult[0]
            if ($firstElem.PSObject.Properties['id']) { $newDeviceId = $firstElem.id }
        }
        elseif ($devResult -and $devResult.PSObject.Properties['id']) {
            $newDeviceId = $devResult.id
        }
        
        if ($newDeviceId) {
            $createdDevices[$key] = $newDeviceId
            Write-Host " ✓ Created: $displayName (ID: $newDeviceId)" -ForegroundColor Green
            
            # Add WLC interface
            try {
                $wlcAddr = $dev.WLCAddress
                $ifaceResult = Add-WUGDeviceInterface -DeviceId $newDeviceId -Address $wlcAddr -HostName "WLC (SNMP Monitoring)" -ErrorAction SilentlyContinue
                Write-Host " ✓ Added interface: $wlcAddr" -ForegroundColor DarkGray
            }
            catch {
                Write-Host " ⚠ Could not add interface: $_" -ForegroundColor Yellow
            }
            
            # Assign monitor
            try {
                $snmpInstance = $dev.SNMPInstance
                $monAssignResult = Add-WUGActiveMonitorToDevice -DeviceId $newDeviceId -MonitorId $monitorId -Argument $snmpInstance -ErrorAction Stop
                Write-Host " ✓ Assigned monitor (instance: $snmpInstance)" -ForegroundColor DarkGray
            }
            catch {
                if ($_.Exception.Message -notmatch 'already|assigned|exists') {
                    Write-Host " ⚠ Monitor assignment error: $_" -ForegroundColor Yellow
                }
            }
        }
        else {
            Write-Host " ✗ Device created but ID not found" -ForegroundColor Red
        }
    }
    catch {
        Write-Host " ✗ Failed to create $displayName`: $_" -ForegroundColor Red
    }
}
Write-Host "✓ Created $($createdDevices.Count) devices" -ForegroundColor Green

# Step 4: Update existing devices
Write-Host ""
Write-Host "Step 4: Updating Existing Devices..." -ForegroundColor Cyan
foreach ($key in $existingDevices.Keys) {
    $deviceId = $existingDevices[$key]
    $dev = $devicePlan[$key]
    
    # Add WLC interface if not present
    try {
        $wlcAddr = $dev.WLCAddress
        $existingInterfaces = @(Get-WUGDeviceInterface -DeviceId $deviceId -ErrorAction SilentlyContinue)
        $wlcIfExists = $existingInterfaces | Where-Object { $_.address -eq $wlcAddr }
        
        if (-not $wlcIfExists) {
            $ifaceResult = Add-WUGDeviceInterface -DeviceId $deviceId -Address $wlcAddr -HostName "WLC (SNMP Monitoring)" -ErrorAction SilentlyContinue
            Write-Host " ✓ Added interface to $($dev.Name): $wlcAddr" -ForegroundColor DarkGray
        }
    }
    catch {
        Write-Host " ⚠ Interface error for $($dev.Name): $_" -ForegroundColor Yellow
    }
    
    # Assign monitor
    try {
        $snmpInstance = $dev.SNMPInstance
        $monAssignResult = Add-WUGActiveMonitorToDevice -DeviceId $deviceId -MonitorId $monitorId -Argument $snmpInstance -ErrorAction Stop
        Write-Host " ✓ Assigned monitor to $($dev.Name) (instance: $snmpInstance)" -ForegroundColor DarkGray
    }
    catch {
        if ($_.Exception.Message -notmatch 'already|assigned|exists') {
            Write-Host " ⚠ Monitor error for $($dev.Name): $_" -ForegroundColor Yellow
        }
    }
}
Write-Host "✓ Updated existing devices" -ForegroundColor Green

# Summary
Write-Host ""
Write-Host "=====================================" -ForegroundColor Cyan
Write-Host "Batch Test Summary" -ForegroundColor Cyan
Write-Host "=====================================" -ForegroundColor Cyan
Write-Host "Total APs: $($batch.Count)" -ForegroundColor White
Write-Host "Created: $($createdDevices.Count)" -ForegroundColor Green
Write-Host "Updated: $($existingDevices.Count)" -ForegroundColor Green
Write-Host "Monitor: $monitorName (TemplateId: $monitorId)" -ForegroundColor White
Write-Host ""

if (($createdDevices.Count + $existingDevices.Count) -eq $batch.Count) {
    Write-Host "✓ Batch test PASSED - all devices processed successfully" -ForegroundColor Green
    Write-Host ""
    Write-Host "Next step: Run Export-CiscoWLCAPDevicesToWUG.ps1 with full 1728 APs" -ForegroundColor Cyan
}
else {
    Write-Host "⚠ Batch test INCOMPLETE - $($batch.Count - $createdDevices.Count - $existingDevices.Count) devices not processed" -ForegroundColor Yellow
}

Write-Host ""
# SIG # Begin signature block
# MIIr+wYJKoZIhvcNAQcCoIIr7DCCK+gCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDHYIv/Ji9nIy2X
# WAtoPDzgFsE0xaSwh6QI9jmXkrrGUqCCJQ0wggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggWNMIIEdaADAgECAhAOmxiO
# +dAt5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYD
# VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAi
# BgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAw
# MDBaFw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp
# Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERp
# Z2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsb
# hA3EMB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iT
# cMKyunWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGb
# NOsFxl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclP
# XuU15zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCr
# VYJBMtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFP
# ObURWBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTv
# kpI6nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWM
# cCxBYKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls
# 5Q5SUUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBR
# a2+xq4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6
# MIIBNjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qY
# rhwPTzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8E
# BAMCAYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5k
# aWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0
# LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDig
# NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v
# dENBLmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCg
# v0NcVec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQT
# SnovLbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh
# 65ZyoUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSw
# uKFWjuyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAO
# QGPFmCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjD
# TZ9ztwGpn1eqXijiuZQwggYaMIIEAqADAgECAhBiHW0MUgGeO5B5FSCJIRwKMA0G
# CSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExp
# bWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBSb290
# IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5NTlaMFQxCzAJBgNVBAYT
# AkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28g
# UHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0GCSqGSIb3DQEBAQUAA4IB
# jwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjIztNsfvxYB5UXeWUzCxEe
# AEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NVDgFigOMYzB2OKhdqfWGV
# oYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/36F09fy1tsB8je/RV0mIk
# 8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05ZwmRmTnAO5/arnY83jeNzh
# P06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm+qxp4VqpB3MV/h53yl41
# aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUedyz8rNyfQJy/aOs5b4s+
# ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz44MPZ1f9+YEQIQty/NQd/
# 2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBMdlyh2n5HirY4jKnFH/9g
# Rvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQYMBaAFDLrkpr/NZZILyhA
# QnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritUpimqF6TNDDAOBgNVHQ8B
# Af8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggrBgEFBQcD
# AzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsGA1UdHwREMEIwQKA+oDyG
# Omh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5n
# Um9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsGAQUFBzAChjpodHRwOi8v
# Y3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ1Jvb3RSNDYu
# cDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG
# 9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURhw1aVcdGRP4Wh60BAscjW
# 4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0ZdOaWTsyNyBBsMLHqafvIh
# rCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajjcw5+w/KeFvPYfLF/ldYp
# mlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNcWbWDRF/3sBp6fWXhz7Dc
# ML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalOhOfCipnx8CaLZeVme5yE
# Lg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJszkyeiaerlphwoKx1uHRz
# NyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z76mKnzAfZxCl/3dq3dUNw
# 4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5JKdGvspbOrTfOXyXvmPL6
# E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHHj95Ejza63zdrEcxWLDX6
# xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2Bev6SivBBOHY+uqiirZt
# g0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/L9Uo2bC5a4CH2RwwggY+
# MIIEpqADAgECAhAHnODk0RR/hc05c892LTfrMA0GCSqGSIb3DQEBDAUAMFQxCzAJ
# BgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNl
# Y3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwHhcNMjYwMjA5MDAwMDAw
# WhcNMjkwNDIxMjM1OTU5WjBVMQswCQYDVQQGEwJVUzEUMBIGA1UECAwLQ29ubmVj
# dGljdXQxFzAVBgNVBAoMDkphc29uIEFsYmVyaW5vMRcwFQYDVQQDDA5KYXNvbiBB
# bGJlcmlubzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPN6aN4B1yYW
# kI5b5TBj3I0VV/peETrHb6EY4BHGxt8Ap+eT+WpEpJyEtRYPxEmNJL3A38Bkg7mw
# zPE3/1NK570ZBCuBjSAn4mSDIgIuXZnvyBO9W1OQs5d67MlJLUAEufl18tOr3ST1
# DeO9gSjQSAE5Nql0QDxPnm93OZBon+Fz3CmE+z3MwAe2h4KdtRAnCqwM+/V7iBdb
# w+JOxolpx+7RVjGyProTENIG3pe/hKvPb501lf8uBAADLdjZr5ip8vIWbf857Yw1
# Bu10nVI7HW3eE8Cl5//d1ribHlzTzQLfttW+k+DaFsKZBBL56l4YAlIVRsrOiE1k
# dHYYx6IGrEA809R7+TZA9DzGqyFiv9qmJAbL4fDwetDeyIq+Oztz1LvEdy8Rcd0J
# BY+J4S0eDEFIA3X0N8VcLeAwabKb9AjulKXwUeqCJLvN79CJ90UTZb2+I+tamj0d
# n+IKMEsJ4v4Ggx72sxFr9+6XziodtTg5Luf2xd6+PhhamOxF2px9LObhBLLEMyRs
# CHZIzVZOFKu9BpHQH7ufGB+Sa80Tli0/6LEyn9+bMYWi2ttn6lLOPThXMiQaooRU
# q6q2u3+F4SaPlxVFLI7OJVMhar6nW6joBvELTJPmANSMjDSRFDfHRCdGbZsL/keE
# LJNy+jZctF6VvxQEjFM8/bazu6qYhrA7AgMBAAGjggGJMIIBhTAfBgNVHSMEGDAW
# gBQPKssghyi47G9IritUpimqF6TNDDAdBgNVHQ4EFgQU6YF0o0D5AVhKHbVocr8G
# aSIBibAwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYI
# KwYBBQUHAwMwSgYDVR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcC
# ARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEkGA1UdHwRCMEAw
# PqA8oDqGOGh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVT
# aWduaW5nQ0FSMzYuY3JsMHkGCCsGAQUFBwEBBG0wazBEBggrBgEFBQcwAoY4aHR0
# cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIz
# Ni5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqG
# SIb3DQEBDAUAA4IBgQAEIsm4xnOd/tZMVrKwi3doAXvCwOA/RYQnFJD7R/bSQRu3
# wXEK4o9SIefye18B/q4fhBkhNAJuEvTQAGfqbbpxow03J5PrDTp1WPCWbXKX8Oz9
# vGWJFyJxRGftkdzZ57JE00synEMS8XCwLO9P32MyR9Z9URrpiLPJ9rQjfHMb1BUd
# vaNayomm7aWLAnD+X7jm6o8sNT5An1cwEAob7obWDM6sX93wphwJNBJAstH9Ozs6
# LwISOX6sKS7CKm9N3Kp8hOUue0ZHAtZdFl6o5u12wy+zzieGEI50fKnN77FfNKFO
# WKlS6OJwlArcbFegB5K89LcE5iNSmaM3VMB2ADV1FEcjGSHw4lTg1Wx+WMAMdl/7
# nbvfFxJ9uu5tNiT54B0s+lZO/HztwXYQUczdsFon3pjsNrsk9ZlalBi5SHkIu+F6
# g7tWiEv3rtVApmJRnLkUr2Xq2a4nbslUCt4jKs5UX4V1nSX8OM++AXoyVGO+iTj7
# z+pl6XE9Gw/Td6WKKKswgga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0G
# CSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTla
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEy
# NTYgMjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHT
# CphBcr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPh
# of6pvF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mA
# xAHeHYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBv
# MgEdgkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps
# 0wjUjsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF
# 83bRVFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXi
# UOeSLsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOM
# CZIVNSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydP
# pOjL6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrU
# G2ZdSoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+
# sdFUeEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0T
# AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYD
# VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG
# A1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV
# HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
# cnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1s
# BwEwDQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WI
# GjB/T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+
# IQhQE7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8M
# yb9rEVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2
# th9y1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjaj
# V/gxdEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2
# Lr3ty9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFze
# GxcytL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG
# 7uEBYTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+N
# Jpud/v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckT
# etiSuEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszW
# kPZPubdcMIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG9w0B
# AQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/
# BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYg
# U0hBMjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1OVow
# YzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQD
# EzJEaWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVyIDIw
# MjUgMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q6q5g
# VrMrV7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPnZ8ZN
# +vo8dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSssp3qo
# me7MrxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09ldQ/
# /nBZZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98oksouT
# MYFOnHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+3qU8
# DD+nigNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsnqcnp
# JeItK/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQPdP5
# 1ho1zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbSLZ49
# kPmk8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojTdS5P
# WPsWeupWs7NpChUk555K096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoKRR7Y
# ufAkprxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAA
# MB0GA1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTvb1NK
# 6eQGfHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYI
# KwYBBQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRwOi8v
# b2NzcC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRzLmRp
# Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZT
# SEEyNTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3JsMy5k
# aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2
# U0hBMjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9
# bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk9iJP
# 2zWLpQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tshgb4O
# 6Lgjg8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9mzskg
# iC3QYIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQBHMU
# BaB5bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+YkDF
# kxUGtMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0cKsb+
# zJNEsuEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY7T/l
# wd6UArb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcbojBcxl
# RcGG0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05oxYy2
# zRWVFjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskKPIJg
# baP5t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjdNXOC
# IUjsarfNZzGCBkQwggZAAgEBMGgwVDELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1Nl
# Y3RpZ28gTGltaXRlZDErMCkGA1UEAxMiU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWdu
# aW5nIENBIFIzNgIQB5zg5NEUf4XNOXPPdi036zANBglghkgBZQMEAgEFAKCBhDAY
# BgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3
# AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEi
# BCD0rejnIBfzqkjqikZIdtqTmTKMYmmqdysxWpsUAz+uRjANBgkqhkiG9w0BAQEF
# AASCAgAkrdzegc0xkAIYWaQgiMySblrdk9MWXkWr/xmaRkX7C14/fO+5IhJV5fYk
# HQJN7eTOOISRM8P5UR9LF2dBezzdU3bg3EAk9L3QmiesvuQB7yQg0XAdVvwvaQyq
# ORIuTN1WCkk74nYfiNEIIUnlm+gWcUi9fztyogf61vjxGDPIu7IA5vDCd8mHTOJj
# UXNel1MQYQu2hhRWkSPmdkwb02MMUCdgnj4A5jIOiaRnNNN5QxATlxheY0v/y1Ov
# vgkQeRFRv+qttaiD0uUFFAeqouNnpqQqIfh6AL+T2oUsNs6QOqgsz6iPj72AHADc
# qkSHIvrYPqlsBWOwIIzY3OxNB4vSWxfjhGAMBehNHIu0r0RmfcXpgElu1sOixg6h
# UlTHhS7qvwuty6u3avh5o+fKDvHSC15U0C5yL5VVrRuOUV9/qiGsYz6cTyUbdP8r
# Nm+7q+x7PN4YqK9ycLDyA4M9CPjPZtF2+LD+TDuJgEJqQY4yatcoYH9Twu/nlBmQ
# shy71GI9agLYHjE6lSKlyXjiLyKO/SEba7gQmYrzGDXIMLHphnTDCslSW/6WMvyD
# PdN3DyCT+giBJg9NJFOOSGvxyFr7GipJv8IxrgZ7BNGU4hXH6UBlYS+++cGskeKE
# MWBZqObHMwENuNSbv0/FCRo1sp6Nx+5Xiocd5sR4FQFNtdIv5aGCAyYwggMiBgkq
# hkiG9w0BCQYxggMTMIIDDwIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5E
# aWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1l
# U3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTECEAqA7xhLjfEFgtHEdqeV
# dGgwDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwG
# CSqGSIb3DQEJBTEPFw0yNjA3MTQwMDM5MjFaMC8GCSqGSIb3DQEJBDEiBCC1a9aL
# pjc3wvStNmaSXSSOsfr1Dxxnck42s9jDnCMupjANBgkqhkiG9w0BAQEFAASCAgAf
# bENsuUe0GmVHn0VyPmQqbsMvAo3ZkUv5tKg3O/cZGslmMVU5M1n9br9N6WGBHjvp
# O2URSlq1FiYk39EOmVvHm1Nvn36klGPXZZ3cIV1cIrWKN1w+5y9/WClsSH/kA7fF
# kIvLfA0Vkm6PDaZeZZmoBTBwjn4P3gPUZHNacm14TjcofKavlbwiW2GPkFCsJr55
# zqyq+kAb6jCMbcZIE3pMmxknO0uLhnSjP6USp3UlhKG+SOg6i1BRaL0YLa2ty5JY
# S2GMKhd/5VyrioEoV6ZofWbqlyso9+LQSPabseDO/9fei+oXQmXpuX+NqqnagL4Q
# ETfdLsqDHII17vcNVvCvJ4CW6M46EAuB3pfWk9Yrn6HqwW949qwcycmjrIdTuRrl
# JTZQcsZB+tsiBDdgHcKu1w74281UdOZjJhhCWkE5rw3IIrj33oc5nSqXATR/B3pH
# ooRILKpiJeiS1YJ/LdngwCun9GipsG+dtiSswYdEwVpKkinZyVTgJV3TCCzv2KSw
# z9ZBWp33b+71iCKWnYmy6G3cLzFMjQVdV1deoy1rzTMNXsi3w5jf/aTwqJ59fzEu
# qHpL8pDEvQ7oya9MY69ccVfT7WuG8E+uxrIeuLxUp4hSHKfMTwvdPtaSGMDiTDUI
# XBf1rYWXZsrkv6sEzSdJmpu64IMDrw9hG80Uyqcw+g==
# SIG # End signature block