Samples/BareMetalProvisioningUsingVMedia.ps1

param(
[parameter(Mandatory=${true})][String]$Ucs,
    [parameter(Mandatory=${true})][String]$UcsOrg,
    [parameter(Mandatory=${true})][String]$UcsSpTemplate,
    [parameter(Mandatory=${true})][String]$UcsBladeDn,
    [parameter(Mandatory=${true})][string]$Hostname
)

# Global Variables
$ImageFileName = 'VMware-ESXi-6.7.0-9484548-Custom-Cisco-6.7.0.2.iso'
$ImagePath = '/'
$RemoteIpAddress = '10.105.219.102'
$UserId = 'root'
$Password = 'Tpi12345'
$RemotePort = '80'
$DeviceType = 'cdd'
$Protocol = 'http'
$BootPolicyName = 'TestBootPolicy'
$vMediaPolicyName = 'TestvMediaPolicy'

$Global:LogFile = ".\AutomateUCSLog.log"
if ([System.IO.File]::Exists($Global:LogFile) -eq $false) {
    $null = New-Item -Path $Global:LogFile -ItemType File -Force
}

function Write-InfoLog {
    [CmdletBinding()]
    param ( 
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [String] $Message
    )

    "Info: $(Get-Date -Format g): $Message" | Out-File $Global:LogFile -Append
    Write-Host "Info: $Message"
}

function Write-ErrorLog {
    [CmdletBinding()] 
    param ( 
        [Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
        [object] $Message
    )
        
    "Error: $(Get-Date -Format g):" | Out-File $Global:LogFile -Append
    $Message | Out-File $LogFile -Append 
    Write-Host "Error: $($Message)" -ForegroundColor Red
}

function Start-Countdown{

    Param(
        [INT]$Seconds = (Read-Host "Enter seconds to countdown from")
    )

    while ($seconds -ge 1){
        Write-Progress -Activity "Sleep Timer Countdown" -SecondsRemaining $Seconds -Status "Time Remaining"
        Start-Sleep -Seconds 1
    $Seconds --
    }
}

function VerifyPowershellVersion {
    try {
        Write-InfoLog "Checking for proper PowerShell version"
        $PSVersion = $psversiontable.psversion
        $PSMinimum = $PSVersion.Major
        Write-InfoLog "You are running PowerShell version $PSVersion"
        if ($PSMinimum -ge "3") {
            Write-InfoLog "Your version of PowerShell is valid for this script."
            
        }
        else {
            Write-ErrorLog "This script requires PowerShell version 3 or above. Please update your system and try again."
            Write-InfoLog "Exiting..."
            exit
        }
    }
    catch {
        throw;
    }
}

function LoadUCSMModule {
    try {
        #Load the UCSM PowerTool
        Write-InfoLog "Checking Cisco Powertool UCSM Module"
        $Modules = Get-Module
        if ( -not ($Modules -like "Cisco.UCSManager")) {
            Write-InfoLog "Importing Module: Cisco Powertool UCSM Module"
            Import-Module Cisco.UCSManager
            $Modules = Get-Module
            if ( -not ($Modules -like "Cisco.UCSManager")) {
                
                Write-ErrorLog "Cisco Powertool UCSM Module did not load. Please use command : Install-Module -Name Cisco.UCSManager"
                Write-InfoLog "Exiting..."
                exit
            }
            else {
                $PTVersion = (Get-Module Cisco.UCSManager).Version
                Write-InfoLog "Cisco Powertool UCSM module version $PTVersion is now Loaded"
            }
        }
        else {
            $PTVersion = (Get-Module Cisco.UCSManager).Version
            Write-InfoLog "Cisco Powertool UCSM module version $PTVersion is already Loaded"
        }
    }
    catch {
        throw;
    }
}

function ConfigureMultipleUCS {
    try {
        $MultipleConnection = Set-UcsPowerToolConfiguration -SupportMultipleDefaultUcs $true -Force -ErrorAction stop
    }
    catch {
        throw;
    }
}

function CreateVMediaPolicy {
    param(    
        [Parameter(mandatory = $true)]
        [string]$ImageFileName,
        [Parameter(mandatory = $true)]
        [string]$ImagePath,
        [Parameter(mandatory = $true)]
        [string]$RemoteIpAddress,
        [Parameter(mandatory = $true)]
        [string]$UserId,
        [Parameter(mandatory = $true)]
        [string]$Password,
        [Parameter(mandatory = $true)]
        [string]$RemotePort,
        [Parameter(mandatory = $true)]
        [string]$DeviceType,
        [Parameter(mandatory = $true)]
        [string]$Protocol,
        [Parameter(mandatory = $true)]
        [Cisco.Ucs.Common.BaseHandle[]] $Ucs,
        [Parameter(mandatory = $true)]
        [Cisco.Ucsm.UcsmManagedObject]$TargetOrg,
        [Parameter(mandatory = $true)]
        [string]$vMediaPolicyName
    )
    try {
        
        Write-InfoLog "Creating VMedia Policy : $vMediaPolicyName" 
        
        Start-UcsTransaction -Ucs $Ucs
        
        $VMediaPolicy = $TargetOrg | Add-UcsVmediaPolicy -ModifyPresent  -Descr '' -Name $vMediaPolicyName -PolicyOwner 'local' -RetryOnMountFail 'yes' -Ucs $Ucs

        Write-InfoLog "ImageFileName: $ImageFileName ImagePath: $ImagePath RemoteIpAddress: $RemoteIpAddress UserId: $UserId Password: $Password RemotePort: $RemotePort DeviceType: $DeviceType Protocol: $Protocol"
        
        $VmediaMountEntry = $VMediaPolicy | Add-UcsVmediaMountEntry -ModifyPresent -AuthOption 'none' -Description '' -DeviceType $DeviceType -ImageFileName $ImageFileName -ImagePath $ImagePath -ImageNameVariable 'none' -MappingName 'cdd-http-VMedia' -MountProtocol $Protocol -Password $Password -RemapOnEject 'no' -RemoteIpAddress $RemoteIpAddress -RemotePort $RemotePort -UserId $UserId -Writable 'no'    -Ucs $Ucs
        
        Complete-UcsTransaction -Ucs $Ucs
        
        Write-InfoLog "Successfully created VMedia Policy : $vMediaPolicyName"         
        
        
    }
    catch {
        Write-ErrorLog "Failed to Create VMedia Policy : $vMediaPolicyName" 
        Write-InfoLog "Disconnecting UCS"
        $Ucs = Disconnect-Ucs
        throw;
    }
}

function ModifyBootOrder
{
    param(    
        [Parameter(mandatory = $true)]
        [string]$BootPolicyName,
        [Parameter(mandatory = $true)]
        [Cisco.Ucs.Common.BaseHandle[]] $Ucs,
        [Parameter(mandatory = $true)]
        [Cisco.Ucsm.UcsmManagedObject]$TargetOrg
    )
    try {
        
        Write-InfoLog "Modifying boot order" 
        
        Start-UcsTransaction -Ucs $Ucs
        $mo = $TargetOrg | Add-UcsBootPolicy -ModifyPresent -Name $BootPolicyName -Ucs $Ucs
        #CIMC mounted vMedia : CD/DVD
        $mo_1 = $mo | Add-UcsLsbootVirtualMedia -ModifyPresent -Access "read-only-remote-cimc" -LunId "0" -Order 1 -Ucs $Ucs
        #Local Device : Local CD/DVD
        $mo_2 = $mo | Add-UcsLsbootVirtualMedia -ModifyPresent -Access "read-only-local" -LunId "0" -Order 2 -Ucs $Ucs
        Complete-UcsTransaction -Ucs $Ucs
        
        Write-InfoLog "Modifying boot order completed" 
    }
    catch {
        Write-ErrorLog "Failed to modify boot order of boot policy : $BootPolicyName" 
        Write-InfoLog "Disconnecting UCS"
        $Ucs = Disconnect-Ucs
        throw;
    }
}             

function ModifyBootPolicyOfServiceProfile
{
    param(    
        [Parameter(mandatory = $true)]
        [string]$BootPolicyName,
        [Parameter(mandatory = $true)]
        [string]$SPName,
        [Parameter(mandatory = $true)]
        [Cisco.Ucs.Common.BaseHandle[]] $Ucs,
        [Parameter(mandatory = $true)]
        [Cisco.Ucsm.UcsmManagedObject]$TargetOrg,
        [Parameter(mandatory = $true)]
        [string]$vMediaPolicyName
    )
    try {
        
        Write-InfoLog "Updating Service Profile template : $SPName with Boot Policy : $BootPolicyName and vMedia Policy: $vMediaPolicyName" 
        
        $CheckBootPolicy = (Get-UcsBootPolicy -Name $BootPolicyName -Ucs $Ucs | measure).Count
        
        if ($CheckBootPolicy -eq 1) {
            $SP = $TargetOrg | Add-UcsServiceProfile -Name $SPName -ModifyPresent -BootPolicyName $BootPolicyName -VmediaPolicyName $vMediaPolicyName -Ucs $Ucs
            Write-InfoLog "Updating Service Profile template completed" 
        }
        else
        {
            Write-ErrorLog "Boot policy : $BootPolicyName not found" 
        }
        
    }
    catch {
        Write-ErrorLog "Failed to update Service Profile template" 
        Write-InfoLog "Disconnecting UCS"
        $Ucs = Disconnect-Ucs
        throw;
    }
    
}

#####################**************************************#####################

try {
    
    VerifyPowershellVersion

    LoadUCSMModule

    ConfigureMultipleUCS

    # Get UCS PS Connection
    Write-InfoLog "UCS: Checking for current UCS Connection for UCS Domain: '$($ucs)'"
    $UcsConn = Get-UcsPSSession | where { $_.Name -eq $Ucs }
    if ( ($UcsConn).Name -ne $Ucs ) {
        Write-InfoLog "UCS: UCS Connection: '$($ucs)' is not connected"
        Write-InfoLog "UCS: Enter UCS Credentials"
        $cred = Get-Credential
        $UcsConn = connect-ucs $Ucs -Credential $cred
    }

    # Get UCS org in connected UCS session
    Write-InfoLog "UCS: Checking for UCS Org: '$($UcsOrg)' on UCS Domain: '$($ucs)'"
    $TargetOrg = Get-UcsOrg -Name $UcsOrg
    if ( $TargetOrg -eq $null ) {
        Write-InfoLog "UCS: UCS Organization: '$($TargetOrg)' is not present"
        exit
    }
    
     # Get UCS Blade on connected UCS session, check availability of UCS Blade
    Write-InfoLog "UCS: Checking availability on UCS Blade: '$($UcsBladeDn)' on UCS Domain: '$($ucs)'"
    $TargetBlade = Get-UcsBlade -dn $UcsBladeDn 
    if ( $TargetBlade -eq $null ) {
        Write-InfoLog "UCS: UCS Blade: '$($TargetBlade.Dn)' is not present"
        exit
    } elseif ( ($TargetBlade).Association -ne "none" -and ($TargetBlade).Availability -ne "available" ) {
        Write-InfoLog "UCS: UCS Blade: '$($TargetBlade.Dn)' is not available"
        exit
    }
    
    # Check to see if SP is already created on connected UCS Session
    Write-InfoLog "UCS: Checking to see if SP: '$($hostname)' exists on UCS Domain: '$($ucs)'"
    $SpToCreate = $TargetOrg | Get-UcsServiceProfile -Name $Hostname -LimitScope
    if ( $SpToCreate -ne $null ) {
        Write-InfoLog "UCS: UCS Service Profile: '$($Hostname)' is already created"
        exit
    }

    # Get UCS SP template on connected UCS session
    Write-InfoLog "UCS: Checking for UCS Service Profile: '$($UcsSpTemplate)' on UCS Domain: '$($ucs)'"
    $TargetSpTemplate = $TargetOrg | Get-UcsServiceProfile -Name $UcsSpTemplate -ucs $UcsConn -LimitScope
    if ( $TargetSpTemplate -eq $null ) {
        Write-InfoLog "UCS: UCS Service Profile Template: '$($TargetSpTemplate.Dn)' is not present"
        exit
    } elseif ( ($TargetSpTemplate).Type -notlike "*-template*" ) {
        Write-InfoLog "UCS: UCS Service Profile: '$($TargetSpTemplate.Dn)' is not a service profile template"
        exit
    }  
    
    #Create vMedia Policy
    $VMediaPolicy = CreateVMediaPolicy -vMediaPolicyName $vMediaPolicyName -ImageFileName $ImageFileName -ImagePath $ImagePath -RemoteIpAddress $RemoteIpAddress -UserId $UserId -Password $Password -RemotePort $RemotePort -DeviceType $DeviceType -Protocol $Protocol -Ucs $UcsConn -TargetOrg $TargetOrg
    
    #Modify Boot order using boot policy
    $BootOrder = ModifyBootOrder -BootPolicyName $BootPolicyName -Ucs $UcsConn -TargetOrg $TargetOrg
        
    #Associate boot policy to ServiceProfile Template
    $AssociateBootPolicy = ModifyBootPolicyOfServiceProfile  -BootPolicyName $BootPolicyName -vMediaPolicyName $vMediaPolicyName -SPName $TargetSpTemplate.name -Ucs $UcsConn -TargetOrg $TargetOrg
    

    # Create New UCS SP from Template
    Write-InfoLog "UCS: Creating new SP: '$($hostname)' from UCS SP Template: '$($TargetSpTemplate.Dn)' on UCS Domain: '$($ucs)'"
    $NewSp = Add-UcsServiceProfile -org $TargetOrg -Ucs $UcsConn -SrcTemplName ($TargetSpTemplate).Name -Name $Hostname 
    $devnull = $NewSp | Set-UcsServerPower -ucs $UcsConn -State "down" -Force
    
    
    # Associate Service Profile to Blade
       Write-InfoLog "UCS: Associating new UCS SP: '$($NewSp.Name)' to UCS Blade: '$($TargetBlade.Dn)' on UCS Domain: '$($Ucs)'"
    $devnull = Associate-UcsServiceProfile -ucs $UcsConn -ServiceProfile $NewSp.name -Blade $TargetBlade -Force


    # Monitor UCS SP Associate for completion
    Write-InfoLog "UCS: Waiting for UCS SP: '$($NewSp.name)' to complete SP association process on UCS Domain: '$($Ucs)'"
    Write-InfoLog "Sleeping 3 minutes"
    Start-Countdown -seconds 180

    $i = 0

        do {
            if ( (Get-UcsServiceProfile -Dn $NewSp.Dn).AssocState -ieq "associated" )
            {
                break
            } else {
                Write-InfoLog "Sleeping 30 seconds"
                Start-Countdown -seconds 30
                $i++
                Write-InfoLog "UCS: RETRY $($i): Checking for UCS SP: '$($NewSp.name)' to complete SP association process on UCS Domain: '$($Ucs)'"
                
            }        
        } until ( (Get-UcsServiceProfile -Dn $NewSp.Dn).AssocState -ieq "associated" -or $i -eq 24 )

    if ( $i -eq 24 ) {
        Write-InfoLog "UCS: Association process of UCS SP: '$($NewSp.name)' failed on UCS Domain: '$($Ucs)'"    
        exit
    } 
    
       Write-InfoLog "UCS: Association process of UCS SP: '$($NewSp.name)' completed on UCS Domain: '$($Ucs)'"    
    
    
    # Set SP Power State to Up
    Write-Host "UCS: Setting Desired Power State to 'up' of Service Profile: '$($NewSp.name)' on UCS Domain: '$($Ucs)'"
    $PowerSpOn = $NewSp | Set-UcsServerPower -ucs $UcsConn -State "up" -Force
    
    # Reset Blade server
    if ( $TargetBlade -ne $null ) {
        Write-InfoLog "Resetting Blade Server : $UcsBladeDn"
        $ResetBlade = $TargetBlade | Reset-UcsServer -Force
    }
}
catch {
    Write-ErrorLog "Failed Automate UCS" 
    Write-InfoLog "Disconnecting UCS"
    $Ucs = Disconnect-Ucs
    throw;
}



# SIG # Begin signature block
# MIIdZgYJKoZIhvcNAQcCoIIdVzCCHVMCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD+VHbMK+IQy+NN
# T0LuFNOEmc8ZfVkJ0Rxl5G97yAuYKqCCDIYwggXCMIIEqqADAgECAhAGs5ehxvr3
# 3+zjzsf3AEZXMA0GCSqGSIb3DQEBCwUAMGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xKzApBgNV
# BAMTIkRpZ2lDZXJ0IEVWIENvZGUgU2lnbmluZyBDQSAoU0hBMikwHhcNMjAxMDIx
# MDAwMDAwWhcNMjMxMDI1MjM1OTU5WjCB1TETMBEGCysGAQQBgjc8AgEDEwJVUzEb
# MBkGCysGAQQBgjc8AgECEwpDYWxpZm9ybmlhMR0wGwYDVQQPDBRQcml2YXRlIE9y
# Z2FuaXphdGlvbjERMA8GA1UEBRMIQzExODM0NzcxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpDYWxpZm9ybmlhMREwDwYDVQQHEwhTYW4gSm9zZTEcMBoGA1UEChMTQ0lT
# Q08gU1lTVEVNUywgSU5DLjEcMBoGA1UEAxMTQ0lTQ08gU1lTVEVNUywgSU5DLjCC
# ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM4a4NqYk3Y87GtsF/vMeyKX
# mI/feQ6EfLH5mxedhBTki+8Lviz9zbN16EJfk0cT1rWI+bBHo2p49bhRMkdL3MkP
# fJQH4ts4OZDrCHDtlQ60RIxxK43/C/ZapYuMO8KhNXE613vXOBHBxqK5IGnH+LIV
# thl6bqM+FidqmIo/tj8Nijx52Ddu2RvA0cT/eS2hDZ/HZvXBddg26zjyySJr4NqZ
# 4rRJkUqh5jSEGUsl58vCK+kE9iWzeP8W1oJZE29EmOVOG309gltGaN1mN+v2kkKk
# sFa56p3YPDlYcbWRqRGsyffZNit5qh55ZJY3EFSndrVGdPR6CaZwMJXRnT8Zfg0C
# AwEAAaOCAfQwggHwMB8GA1UdIwQYMBaAFI/ofvBtMmoABSPHcJdqOpD/a+rUMB0G
# A1UdDgQWBBRAgSdqGJHDn1gp1w9Evrwh0VEUJjAxBgNVHREEKjAooCYGCCsGAQUF
# BwgDoBowGAwWVVMtQ0FMSUZPUk5JQS1DMTE4MzQ3NzAOBgNVHQ8BAf8EBAMCB4Aw
# EwYDVR0lBAwwCgYIKwYBBQUHAwMwewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2Ny
# bDMuZGlnaWNlcnQuY29tL0VWQ29kZVNpZ25pbmdTSEEyLWcxLmNybDA3oDWgM4Yx
# aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0VWQ29kZVNpZ25pbmdTSEEyLWcxLmNy
# bDBLBgNVHSAERDBCMDcGCWCGSAGG/WwDAjAqMCgGCCsGAQUFBwIBFhxodHRwczov
# L3d3dy5kaWdpY2VydC5jb20vQ1BTMAcGBWeBDAEDMH4GCCsGAQUFBwEBBHIwcDAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEgGCCsGAQUFBzAC
# hjxodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRFVkNvZGVTaWdu
# aW5nQ0EtU0hBMi5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEA
# VgLs7po2IfnfWflRgmBLQMmyUJcbSDxriBNMfkV4N46mcnyE0ZUpz8NPplBtC4Je
# EnXRGpJ73xGqsAzWcBZRkK+0bQ1Lt5LCtWagcBwGbnqnw+3u1wvkXVnvGH1FvDhJ
# BLtwN28mof498HDiyBTBtVAhW6vFxz/1LiD1Ax4D+r60FX1OHKTqZBUrKHSy1tpB
# KCARqbclQmCEkYI++IbrIFOoFh22UE3giyB2rDVRZcIYnl5xQIJgSewf4+3UmdCX
# zmDFZSJo8NiBJtzeFI5giBJxg9z0TYrw0KHyj5Nn/iQI55SxNIVPhInXJQ5GW4GF
# ekulx5a1IaJyMBEKO57BojCCBrwwggWkoAMCAQICEAPxtOFfOoLxFJZ4s9fYR1ww
# DQYJKoZIhvcNAQELBQAwbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0
# IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNl
# cnQgSGlnaCBBc3N1cmFuY2UgRVYgUm9vdCBDQTAeFw0xMjA0MTgxMjAwMDBaFw0y
# NzA0MTgxMjAwMDBaMGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xKzApBgNVBAMTIkRpZ2lDZXJ0
# IEVWIENvZGUgU2lnbmluZyBDQSAoU0hBMikwggEiMA0GCSqGSIb3DQEBAQUAA4IB
# DwAwggEKAoIBAQCnU/oPsrUT8WTPhID8roA10bbXx6MsrBosrPGErDo1EjqSkbpX
# 5MTJ8y+oSDy31m7clyK6UXlhr0MvDbebtEkxrkRYPqShlqeHTyN+w2xlJJBVPqHK
# I3zFQunEemJFm33eY3TLnmMl+ISamq1FT659H8gTy3WbyeHhivgLDJj0yj7QRap6
# HqVYkzY0visuKzFYZrQyEJ+d8FKh7+g+03byQFrc+mo9G0utdrCMXO42uoPqMKhM
# 3vELKlhBiK4AiasD0RaCICJ2615UOBJi4dJwJNvtH3DSZAmALeK2nc4f8rsh82zb
# 2LMZe4pQn+/sNgpcmrdK0wigOXn93b89OgklAgMBAAGjggNYMIIDVDASBgNVHRMB
# Af8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcD
# AzB/BggrBgEFBQcBAQRzMHEwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj
# ZXJ0LmNvbTBJBggrBgEFBQcwAoY9aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29t
# L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNydDCBjwYDVR0fBIGHMIGE
# MECgPqA8hjpodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNz
# dXJhbmNlRVZSb290Q0EuY3JsMECgPqA8hjpodHRwOi8vY3JsNC5kaWdpY2VydC5j
# b20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3JsMIIBxAYDVR0gBIIB
# uzCCAbcwggGzBglghkgBhv1sAwIwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3
# LmRpZ2ljZXJ0LmNvbS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUH
# AgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQBy
# AHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBj
# AGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAg
# AEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQ
# AGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBt
# AGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBj
# AG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBl
# AHIAZQBuAGMAZQAuMB0GA1UdDgQWBBSP6H7wbTJqAAUjx3CXajqQ/2vq1DAfBgNV
# HSMEGDAWgBSxPsNpA/i/RwHUmCYaCALvY2QrwzANBgkqhkiG9w0BAQsFAAOCAQEA
# GTNKDIEzN9utNsnkyTq7tRsueqLi9ENCF56/TqFN4bHb6YHdnwHy5IjV6f4J/SHB
# 7F2A0vDWwUPC/ncr2/nXkTPObNWyGTvmLtbJk0+IQI7N4fV+8Q/GWVZy6OtqQb0c
# 1UbVfEnKZjgVwb/gkXB3h9zJjTHJDCmiM+2N4ofNiY0/G//V4BqXi3zabfuoxrI6
# Zmt7AbPN2KY07BIBq5VYpcRTV6hg5ucCEqC5I2SiTbt8gSVkIb7P7kIYQ5e7pTcG
# r03/JqVNYUvsRkG4Zc64eZ4IlguBjIo7j8eZjKMqbphtXmHGlreKuWEtk7jrDgRD
# 1/X+pvBi1JlqpcHB8GSUgDGCEDYwghAyAgEBMIGAMGwxCzAJBgNVBAYTAlVTMRUw
# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
# KzApBgNVBAMTIkRpZ2lDZXJ0IEVWIENvZGUgU2lnbmluZyBDQSAoU0hBMikCEAaz
# l6HG+vff7OPOx/cARlcwDQYJYIZIAWUDBAIBBQCgggEVMBkGCSqGSIb3DQEJAzEM
# BgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqG
# SIb3DQEJBDEiBCBMURljysnb9l1Tq+FqalACgdEd7/5TCXxT5Hy3E9YMjjCBqAYK
# KwYBBAGCNwIBDDGBmTCBlqCBk4CBkABDAG8AbgBmAGkAZwB1AHIAZQAgAGEAbgBk
# ACAAZgBpAHIAbQB3AGEAcgBlACAAdQBwAGQAYQB0AGUAIAB0AGgAZQAgAE4AZQB4
# AHUAcwAgAHMAdwBpAHQAYwBoAGUAcwAgAGEAbgBkACAAVQBDAFMATQAgAGYAbwBy
# ACAAYQB6AHUAcgBlAHMAdABhAGMAazANBgkqhkiG9w0BAQEFAASCAQCNYTFzm9/n
# rt/PEQTt+yhrudPICvy4uXAZXPiQw7+LQxm/1cwnjPPSoBjaWQe2egn5OBS3KEiZ
# Tbnk9RrdwfxTokHCbAG1kbDlmpvgsEFX3iGpLNvbSEGszsauiAy5syXCl42MFZCJ
# 3g7AY19kh2sg2woPuXFX1C7bXK2Y8D/988sUgKShU9TqMpJce3fQWCmxwO3Wubaq
# KxURJ5a37v1TtTU03BDgV/8LJegreUFnhja0L6BtfAk7gRXErQNhMPaBnt/lFVhh
# W0Ah1LWm5aDqMGs1OUYbnzL1u1WJ3YxWPkYrSfsfLCVAE/i4lA1saANZ0oi3+bKU
# 5S76TV7dr6VLoYINbTCCDWkGCisGAQQBgjcDAwExgg1ZMIINVQYJKoZIhvcNAQcC
# oIINRjCCDUICAQMxDzANBglghkgBZQMEAgEFADBnBgsqhkiG9w0BCRABBKBYBFYw
# VAIBAQYJYIZIAYb9bAcBMCEwCQYFKw4DAhoFAAQUq67hKo6Qj2E8VQq0Jr+YmfoP
# ZzECEHZuerS4QKkgXxfQP2kP7z8YDzIwMjEwOTA4MTIyOTQ1WqCCCjcwggT+MIID
# 5qADAgECAhANQkrgvjqI/2BAIc4UAPDdMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNV
# BAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp
# Y2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1l
# c3RhbXBpbmcgQ0EwHhcNMjEwMTAxMDAwMDAwWhcNMzEwMTA2MDAwMDAwWjBIMQsw
# CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xIDAeBgNVBAMTF0Rp
# Z2lDZXJ0IFRpbWVzdGFtcCAyMDIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
# CgKCAQEAwuZhhGfFivUNCKRFymNrUdc6EUK9CnV1TZS0DFC1JhD+HchvkWsMluca
# XEjvROW/m2HNFZFiWrj/ZwucY/02aoH6KfjdK3CF3gIY83htvH35x20JPb5qdofp
# ir34hF0edsnkxnZ2OlPR0dNaNo/Go+EvGzq3YdZz7E5tM4p8XUUtS7FQ5kE6N1aG
# 3JMjjfdQJehk5t3Tjy9XtYcg6w6OLNUj2vRNeEbjA4MxKUpcDDGKSoyIxfcwWvkU
# rxVfbENJCf0mI1P2jWPoGqtbsR0wwptpgrTb/FZUvB+hh6u+elsKIC9LCcmVp42y
# +tZji06lchzun3oBc/gZ1v4NSYS9AQIDAQABo4IBuDCCAbQwDgYDVR0PAQH/BAQD
# AgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwQQYDVR0g
# BDowODA2BglghkgBhv1sBwEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdp
# Y2VydC5jb20vQ1BTMB8GA1UdIwQYMBaAFPS24SAd/imu0uRhpbKiJbLIFzVuMB0G
# A1UdDgQWBBQ2RIaOpLqwZr68KC0dRDbd42p6vDBxBgNVHR8EajBoMDKgMKAuhixo
# dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDAyoDCg
# LoYsaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmww
# gYUGCCsGAQUFBwEBBHkwdzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl
# cnQuY29tME8GCCsGAQUFBzAChkNodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v
# RGlnaUNlcnRTSEEyQXNzdXJlZElEVGltZXN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3
# DQEBCwUAA4IBAQBIHNy16ZojvOca5yAOjmdG/UJyUXQKI0ejq5LSJcRwWb4UoOUn
# gaVNFBUZB3nw0QTDhtk7vf5EAmZN7WmkD/a4cM9i6PVRSnh5Nnont/PnUp+Tp+1D
# nnvntN1BIon7h6JGA0789P63ZHdjXyNSaYOC+hpT7ZDMjaEXcw3082U5cEvznNZ6
# e9oMvD0y0BvL9WH8dQgAdryBDvjA4VzPxBFy5xtkSdgimnUVQvUtMjiB2vRgorq0
# Uvtc4GEkJU+y38kpqHNDUdq9Y9YfW5v3LhtPEx33Sg1xfpe39D+E68Hjo0mh+s6n
# v1bPull2YYlffqe0jmd4+TaY4cso2luHpoovMIIFMTCCBBmgAwIBAgIQCqEl1tYy
# G35B5AXaNpfCFTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
# VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTYwMTA3MTIwMDAw
# WhcNMzEwMTA3MTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl
# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdp
# Q2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBMIIBIjANBgkqhkiG
# 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvdAy7kvNj3/dqbqCmcU5VChXtiNKxA4HRTNR
# EH3Q+X1NaH7ntqD0jbOI5Je/YyGQmL8TvFfTw+F+CNZqFAA49y4eO+7MpvYyWf5f
# ZT/gm+vjRkcGGlV+Cyd+wKL1oODeIj8O/36V+/OjuiI+GKwR5PCZA207hXwJ0+5d
# yJoLVOOoCXFr4M8iEA91z3FyTgqt30A6XLdR4aF5FMZNJCMwXbzsPGBqrC8HzP3w
# 6kfZiFBe/WZuVmEnKYmEUeaC50ZQ/ZQqLKfkdT66mA+Ef58xFNat1fJky3seBdCE
# GXIX8RcG7z3N1k3vBkL9olMqT4UdxB08r8/arBD13ays6Vb/kwIDAQABo4IBzjCC
# AcowHQYDVR0OBBYEFPS24SAd/imu0uRhpbKiJbLIFzVuMB8GA1UdIwQYMBaAFEXr
# oq/0ksuCMS1Ri6enIZ3zbcgPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/
# BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHkGCCsGAQUFBwEBBG0wazAkBggr
# BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdo
# dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290
# Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5j
# b20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3Js
# My5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMFAGA1Ud
# IARJMEcwOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k
# aWdpY2VydC5jb20vQ1BTMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAQEA
# cZUS6VGHVmnN793afKpjerN4zwY3QITvS4S/ys8DAv3Fp8MOIEIsr3fzKx8MIVoq
# twU0HWqumfgnoma/Capg33akOpMP+LLR2HwZYuhegiUexLoceywh4tZbLBQ1QwRo
# stt1AuByx5jWPGTlH0gQGF+JOGFNYkYkh2OMkVIsrymJ5Xgf1gsUpYDXEkdws3XV
# k4WTfraSZ/tTYYmo9WuWwPRYaQ18yAGxuSh1t5ljhSKMYcp5lH5Z/IwP42+1ASa2
# bKXuh1Eh5Fhgm7oMLSttosR+u8QlK0cCCHxJrhO24XxCQijGGFbPQTS2Zl22dHv1
# VjMiLyI2skuiSpXY9aaOUjGCAoYwggKCAgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUw
# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
# MTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcg
# Q0ECEA1CSuC+Ooj/YEAhzhQA8N0wDQYJYIZIAWUDBAIBBQCggdEwGgYJKoZIhvcN
# AQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yMTA5MDgxMjI5NDVa
# MCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFOHXgqjhkb7va8oWkbWqtJSmJJvzMC8G
# CSqGSIb3DQEJBDEiBCCm9Hlh05OU4PVrR9N26uujz7MaRLTsqzmy+j/HjN49UDA3
# BgsqhkiG9w0BCRACLzEoMCYwJDAiBCCzEJAGvArZgweRVyngRANBXIPjKSthTyaW
# TI01cez1qTANBgkqhkiG9w0BAQEFAASCAQBU9tmE6mvn5lJV7bmUcv5HbCc50xkA
# m7JCQQxp2vTeKox/MOME03CX5Q015dSqRW5OxXF+Wq4qV+xhXvAyNJXj9MClEiou
# TADMqnA5tESOm9x1OkkqSeK4UCAzFkza6jqMZHpVOh0RA/HE8PF8Utg7hI8a0iUM
# dCVi/6oj1ARpdyxwCQbMO00/Om2FF6e4dKMe+2ItSXWvzrtgaxcYmSEdorbeuWD/
# d6B++3xtk7bK+EBBd0SBShngTmCjdzIJO43mduHRlQpifWzfCRcabnBFbbqQslGP
# EuGt/5k/ApWblg0DRV7gPUWrd+Gd8rYh1vTpUlMsKCxjwzPROPCwBpQC
# SIG # End signature block