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
# MIIjPgYJKoZIhvcNAQcCoIIjLzCCIysCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# 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+pvBi1JlqpcHB8GSUgDGCFg4wghYKAgEBMIGAMGwxCzAJBgNVBAYTAlVTMRUw
# 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
# 5S76TV7dr6VLoYITRTCCE0EGCisGAQQBgjcDAwExghMxMIITLQYJKoZIhvcNAQcC
# oIITHjCCExoCAQMxDzANBglghkgBZQMEAgEFADB5BgsqhkiG9w0BCRABBKBqBGgw
# ZgIBAQYLYIZIAYb5LwAGDQMwMTANBglghkgBZQMEAgEFAAQgO2EjSBRWND2MO3ft
# 3yD/Yd7NMfQilygzj+YnGi8vTq0CEEABh/oh6FmDLgAyKzpUWbsYDzIwMjMwNTA4
# MDY1MjE4WqCCD2QwggekMIIFjKADAgECAhBAAYD9DvXolVgjPR54g1q+MA0GCSqG
# SIb3DQEBCwUAMEUxCzAJBgNVBAYTAlVTMRIwEAYDVQQKEwlJZGVuVHJ1c3QxIjAg
# BgNVBAMTGVRydXN0SUQgVGltZXN0YW1waW5nIENBIDMwHhcNMjIwNTI1MjExMDU3
# WhcNMjMwODI0MjExMDU3WjBJMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRy
# dXN0MSYwJAYDVQQDEx1UcnVzdElEIFRpbWVzdGFtcCBBdXRob3JpdHkgMzCCAiIw
# DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALp7eYoJ+vne9oA1jzw1XoBTTOWq
# vgf2x/gV7sOXhAsCOe8Wy2Rul2R3PT+pGzyDvR/8DWoikVkAYBm0/bnIL6Y/IpOI
# f4fwVgdHHNJqIvYvbV1+PESwLzQ5A5soFLXw9E/otcCCwMaQhTOimABeo7P3lpaL
# rVX9FDLqxYHJ/YYKYAU2JRJG0z5SB2YYwRL5MhRBFTaGM9m9CdU2EK/50YHeYmoT
# kikdcDlBNKJ/qlM1CkNW3Uun2+mBPBtNkqbGcwoX41kmb+Vo6TRiq8zo7hosFlx3
# d7/0gfYmyrNGIjdH/2FrHPKUKbuIYR8WZP6C+kypSNsELZPfFGrBwjnr7jmBIwgi
# AXd52SlTXBpv6+upRRRggeLyNP+GQlhcSntTm1ByRSGIhGiWNEijNM/gYaw1JYxI
# fKgMReuTAdV99augSBY3b91uSVIhZp7hTl2ZHARK+/0IssO1YZ8ivZH3F8s52wAw
# faVA5Np23m+ZqaoC+1IrPCuYX6ZGewltvTq4hcs21IMIMcf84X1lfKqXsK+16uKk
# e2J1YCQlfp+BCONpDYtfdzfUySAFJKfs6SKflb8pgJiIPrHzVPpuSEO2/XJiMrMc
# fInp59bjzhvEayTu+PTTV7PD3FvEEnROnapip3brHmFRTlwBVo8mhl7dEXXoYI3V
# AsDRhDQJdB4xh9sbAgMBAAGjggKKMIIChjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB
# /wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDCBhQYIKwYBBQUHAQEEeTB3
# MDAGCCsGAQUFBzABhiRodHRwOi8vY29tbWVyY2lhbC5vY3NwLmlkZW50cnVzdC5j
# b20wQwYIKwYBBQUHMAKGN2h0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5jb20v
# Y2VydHMvdGltZXN0YW1waW5nMy5wN2MwHwYDVR0jBBgwFoAUyjLwNnzHKtqRtXyH
# ihG9uCJsvwkwggE8BgNVHSAEggEzMIIBLzAIBgZngQwBBAIwDQYLYIZIAYb5LwAG
# DQEwggESBgtghkgBhvkvAAYNAzCCAQEwSgYIKwYBBQUHAgEWPmh0dHBzOi8vc2Vj
# dXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRleC5o
# dG1sMIGyBggrBgEFBQcCAjCBpQyBolRoaXMgY2VydGlmaWNhdGUgaGFzIGJlZW4g
# aXNzdWVkIGluIGFjY29yZGFuY2Ugd2l0aCBJZGVuVHJ1c3QncyBUcnVzdElEIENl
# cnRpZmljYXRlIFBvbGljeSBmb3VuZCBhdCBodHRwczovL3NlY3VyZS5pZGVudHJ1
# c3QuY29tL2NlcnRpZmljYXRlcy9wb2xpY3kvdHMvaW5kZXguaHRtbDBGBgNVHR8E
# PzA9MDugOaA3hjVodHRwOi8vdmFsaWRhdGlvbi5pZGVudHJ1c3QuY29tL2NybC90
# aW1lc3RhbXBpbmczLmNybDAdBgNVHQ4EFgQUrxUhDN/aCm91R5wS0B3oe7g6aTMw
# DQYJKoZIhvcNAQELBQADggIBAAp1wnClUmkKnzDA17s0y2fxHRmg+9x2N0T11Khs
# fkXSJ1iGMt2yE9jDcXJ97dQPoXYy6UDKM7S9LgAOalo6uOMt/o5+cSb7BCbv1AIe
# lIkufAy2kkGMgX9jDR99ixl6wzpkrBo5pU/y1AOs4I1VEjQK3e+tLABo0qpZjqFa
# eGXPFc/zPVPG4whcNhmh3SqImJhCIPd8JMD3hy28yOsjaHVd5GKMNFD7OMWzuSxs
# 4x1Ezk3EeeX4MYUK3YWXowQbtTLBAkwlhIpzj8KGuY+99gsdkKKqa2aMhMrToH3K
# c4S2RueOO7NjPfYni9cfS0J1JO6MYn0KGgsap8tRsDEOfuhREmvZ037i8i98+ajD
# gMtLPksemSVDn4DseD14WfjgIRsTOphWE2hk8E6yVy/xOAETbMnANGHp2AY+YI+r
# ZgmdK7OVsWJgYcSBDhcLC+xZ7EDd8q50slMs2HUSC8RbL5ka5t4eft5CY/Vuf0wm
# AtLdVvpMQVMuZErS/rQ4QkVS3uB+NtVb0lSXbbormtPsV+dzcP1eprZ5ZjxMfrSQ
# 1wNEgx/ChHWExdlE0sdfRDJcZPbWT9Ep5RwLbFyYiHM19DCwfbxX6X6MbB3ohVBG
# /V03BPRsEjs4rLSfS0dMSYoVKv7Y57jQ3md4udgE/Urd947BBKWhY0+YspAtO7NO
# JlrRMIIHuDCCBaCgAwIBAgIQQAF/lJAVu6kSuFeWPUTs7jANBgkqhkiG9w0BAQsF
# ADBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5J
# ZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMjIwMzE2MjEwOTA1WhcN
# MzMwNjEyMjEwOTA1WjBFMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0
# MSIwIAYDVQQDExlUcnVzdElEIFRpbWVzdGFtcGluZyBDQSAzMIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAqGL0RYFG7mL0RgSXLynLNWhEVrhsKhrVL4rS
# G+NAp4v8TbAP2YXsqWB8yZgj9DQ55AECnmQ2Uo/BqQSsI/AOr9ctqZykItmca/nG
# jKezl1kZS2YoNc4Zjj+7QO9iNunclA06fBhI+iQHAam7isQLK3CwXRDLzKkMs7Ti
# sMoGQOSd0M8P6YY/QOGYv/+tCxmfvUz2GjWzQQemgiuLjvGhPwo+hrcNzays9j0G
# 7QtALkJ0KfvJS+guvCvSuEfDzt3BaPIpD2q6GYK+MUiNis3uwwngauyL4r048wdv
# USsf92Kyr6T1pAfjjPyVDNazf/w/BjzA6ewNevFVLNfE0DhQkXMmsNVGBzY5Phhl
# p5fbTwsrD19K0FPgbGO/l/Zp2dheeiCbe09bxbhdeahSBtTVPca4Vu3Ljz+PRZjF
# odq7+lziqqpqqCP/ikEnmK/QkxjCG7AkX384dxg7yb5jjtXOnP5Yv4SXuV4SNNVV
# UBJfbLXyYAf3Q0Dal85ZxNQd0QNPQIsYWv9ttTMVc6sVErdfTBPw355St6bHz91L
# UoDD0S/GjUif8LYhVlZGXlwjYmVZOb2Z7+DAamzjwVrSsrxGCJ66Coy1rKapJuHV
# sfGAW44p2ioIEZT3s6nQJkCt7te4ab1iWzaydZGAYyBao0K7kfK3vSp4AXsE5t5y
# 6dpHYo0CAwEAAaOCAp0wggKZMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/
# BAQDAgGGMIGJBggrBgEFBQcBAQR9MHswMAYIKwYBBQUHMAGGJGh0dHA6Ly9jb21t
# ZXJjaWFsLm9jc3AuaWRlbnRydXN0LmNvbTBHBggrBgEFBQcwAoY7aHR0cDovL3Zh
# bGlkYXRpb24uaWRlbnRydXN0LmNvbS9yb290cy9jb21tZXJjaWFscm9vdGNhMS5w
# N2MwHwYDVR0jBBgwFoAU7UQZwNPwBovupHu+QucmVMiONnYwggFEBgNVHSAEggE7
# MIIBNzAIBgZngQwBBAIwDQYLYIZIAYb5LwAGDQMwggEaBgtghkgBhvkvAAYNATCC
# AQkwSgYIKwYBBQUHAgEWPmh0dHBzOi8vc2VjdXJlLmlkZW50cnVzdC5jb20vY2Vy
# dGlmaWNhdGVzL3BvbGljeS90cy9pbmRleC5odG1sMIG6BggrBgEFBQcCAjCBrQyB
# qlRoaXMgVHJ1c3RJRCBDZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQgaW4gYWNj
# b3JkYW5jZSB3aXRoIElkZW5UcnVzdCdzIFRydXN0SUQgQ2VydGlmaWNhdGUgUG9s
# aWN5IGZvdW5kIGF0IGh0dHBzOi8vc2VjdXJlLmlkZW50cnVzdC5jb20vY2VydGlm
# aWNhdGVzL3BvbGljeS90cy9pbmRleC5odG1sMEoGA1UdHwRDMEEwP6A9oDuGOWh0
# dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVzdC5jb20vY3JsL2NvbW1lcmNpYWxyb290
# Y2ExLmNybDAdBgNVHQ4EFgQUyjLwNnzHKtqRtXyHihG9uCJsvwkwEwYDVR0lBAww
# CgYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggIBACtnO4f6QB6v2yDFeld3Pa1H
# 7Bmby2tSwzQ/5dB5WXmTZHlV433s7BDkpwGzK4fGBuTcx814uPUWWSwcL+f8bpfo
# zBv6p855j/AlKul1EiPMKkMlLtwdiK6sWT2x8qaTm4fMGbcpgUbQnxOo4BnzVUmg
# s3epm9/qXf9GaWXRz4maSWl4z3apD3X/5oMrriGWIiW6ivCq8bmOBUdm0I9quhW9
# Snk2JAaqkVCjs06rqE3rRblyNdrSypGzo5eBT498aCfcvDPJX2/q2PMkLvkKoXtV
# J1g4sEwDQxm2sg8QMEd2GKo+X7TqOeF8An7KOPDq9v0xtSsF4+ufFrl43vl6v4uM
# ey68wOHv6VmaGpCtWk1e6lSq9jLQqRBBg8CMwpw6niVyvkrdh4Tvu+5HLrareZBp
# 98PJ2cQzrHk1SiPcyDxSlhbXRks/TgKXTicUm3pZsKZcTvCXHcqulN1eoQ3z9azM
# IuR7RtdECz2RJUI6Xg//6ZdMMgaDnktMALgAyo9GgGGVimx4E2/aM5r0cm+RCrk9
# 56BTqahEdiGLWjgjq8dAJe4XfLtp6EmGvsw650uBbDA0Mg9nlSCFdGTMFBKlw65o
# 2oJaenMysAvE/VC39ZIEOBfk2IOj2GTYlOgHi0iIBIZf7SqdjhTAtoW7U9TTZj8S
# HRen/EEe1WEcfTawcOhJMYIDHzCCAxsCAQEwWTBFMQswCQYDVQQGEwJVUzESMBAG
# A1UEChMJSWRlblRydXN0MSIwIAYDVQQDExlUcnVzdElEIFRpbWVzdGFtcGluZyBD
# QSAzAhBAAYD9DvXolVgjPR54g1q+MA0GCWCGSAFlAwQCAQUAoIGYMBoGCSqGSIb3
# DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjMwNTA4MDY1MjE4
# WjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBTy71bgeNSndiGNJX4ndDOhrNiLRjAv
# BgkqhkiG9w0BCQQxIgQgpz2r5FkYGgKPzYJNDf9uQ59d8dDAceLrjgidlOhAwngw
# DQYJKoZIhvcNAQEBBQAEggIAf6B4sIQ7fn0r88X4lnk7wmxyqkjZrb/VvekAvydA
# 8NT/PvoemLlBQ2rroC81a8GSkCM3lGUsmxYH7+g40ZbCmSHKfgtnMl8/EU1ENM+l
# UOnBB5MRSakO0QK2UexdBBMlG0MQmujHxkWLpqEASUWtatXG/Z/HFtMwiVPiLHwc
# iHCnEkXBTE2iWXn83P9F6H0UpuW45fZZwTpJwkGzSjvLyo7MndtNd+oDi2GuS4Pb
# xV9wFLwOYnAqgyBKM8A8EZcdBuWEeHp1LuKiBly6pf15fm0WhgpUf9qdFimJSE8h
# 3X50J/Nouo4atWivQ8f2980k3GtQs7GhghvTwYHc0uXvOUsHqy1o0g3W5BpKD2T6
# 5gFDkyP3TRHslpLa+4kpZeAb1sb5qjjs2z7hywK3IVCwRW7k4Pj5ZJlUQLtHVx66
# mD/JPFv4IvqDVwLODYR/0LeBbm436yKBUdc9/FGaztXw6IMmyFsAeD4mrcrvsK94
# mcG4vyqvFq6siMiECRmsuQRhUj8ULchtneWvr/psMn9JIK6iQ6vplz+Bt7Z/M83F
# x7iseC0swj7vRGfXwQpzlSxZK/zRQyToK6L++0bmMubgEy9724lWmKcPHyY4PHLJ
# K+Y1BCRRPE83jyUeYETRuOPMU2Q5yCMfUsnK0w+BmzoWmVkM6z3Go+nazMRR+HMR
# F+4=
# SIG # End signature block