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
# MIIhdAYJKoZIhvcNAQcCoIIhZTCCIWECAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD+VHbMK+IQy+NN
# T0LuFNOEmc8ZfVkJ0Rxl5G97yAuYKqCCGpQwggeNMIIFdaADAgECAhBAAYkJtMec
# EjtNtgBsSCkGMA0GCSqGSIb3DQEBCwUAMEgxCzAJBgNVBAYTAlVTMRIwEAYDVQQK
# EwlJZGVuVHJ1c3QxJTAjBgNVBAMTHFRydXN0SUQgRVYgQ29kZSBTaWduaW5nIENB
# IDQwHhcNMjMwNjMwMDAyOTQ5WhcNMjYwNjI5MDAyODQ5WjCB7zELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcTCFNhbiBKb3NlMRAwDgYD
# VQQFEwc0NjgyNDc4MRMwEQYLKwYBBAGCNzwCAQMTAlVTMRswGQYLKwYBBAGCNzwC
# AQITCkNhbGlmb3JuaWExHTAbBgNVBA8TFFByaXZhdGUgT3JnYW5pemF0aW9uMRsw
# GQYDVQQKExJDaXNjbyBTeXN0ZW1zIEluYy4xGzAZBgNVBAsTEkNpc2NvIFN5c3Rl
# bXMgSW5jLjEbMBkGA1UEAxMSQ2lzY28gU3lzdGVtcyBJbmMuMIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAy5xBW8oNHs29o8ajhoPZo8Vbch/Hglt6ZIIV
# ELZvBzPFPH+GQEwIIPkJ7QmfI0vWdXv79h14SAxdyNdO7nmNn64zc28hbtPLoHyr
# EohZWg+f7O7sgpeFMPIXXsn5miH3WCLXbTyjQhkmYv7uLQ7jIjaumixXjytkpFjq
# v2jIpO1SS7b6cUWOUn18HyAg4vtpmEaNS9dsU74y+KEqVxxZlajBBkpd4snDVEJm
# T9uX4HisduRhVQPoBOfh5Zm7GS0vkqNNbK2QCKC8oyfvA2w6QHTB5GEllMjLUK8C
# wPHsZCf3g3oC2CoWesP/Q+Ib4TMRtutaqp9gnTMBHh6hKO+ny/S7Tw+8Le54Lflx
# hODh3u5zO3C4iCBkMFQeMDUWvPS31OU34Y1kL0mhrJ7Bvw8IfwooVLIB8BsVJleV
# ptnkylQTzaFF5P7cbytn7AYEzCldbTb+o1AE15P60TVmk4YFTK87vK+7rPUMwDtc
# mUbL1jQ1I3fa0Xc6g9FDECq9flxlERm72GytDpSt49n81M/D9C+wpN3hgGY+uPh2
# Qj2umO8EaSnvwmUhe2lpdkgZat/DErGsTKIUJ1updY/8OxjcIavhJx6W+t28uijA
# tMKO2VvAQBh8HUT6APMMlk1+tTvVTLGIrKdbvBVXnV9QsMjM7r3zJPqtIS4Gjdix
# mKHUlN8CAwEAAaOCAckwggHFMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgbA
# MIGOBggrBgEFBQcBAQSBgTB/MDAGCCsGAQUFBzABhiRodHRwOi8vY29tbWVyY2lh
# bC5vY3NwLmlkZW50cnVzdC5jb20wSwYIKwYBBQUHMAKGP2h0dHA6Ly92YWxpZGF0
# aW9uLmlkZW50cnVzdC5jb20vY2VydHMvdHJ1c3RpZGV2Y29kZXNpZ25pbmc0LnA3
# YzAfBgNVHSMEGDAWgBT+BaSGWZo/NAFajQheG9t1ebnhxjBvBgNVHSAEaDBmMAcG
# BWeBDAEDMFsGC2CGSAGG+S8ABg4BMEwwSgYIKwYBBQUHAgEWPmh0dHBzOi8vc2Vj
# dXJlLmlkZW50cnVzdC5jb20vY2VydGlmaWNhdGVzL3BvbGljeS90cy9pbmRleC5o
# dG1sME4GA1UdHwRHMEUwQ6BBoD+GPWh0dHA6Ly92YWxpZGF0aW9uLmlkZW50cnVz
# dC5jb20vY3JsL3RydXN0aWRldmNvZGVzaWduaW5nNC5jcmwwHQYDVR0OBBYEFKrf
# vaFZgfyRARnHauLZbMwOsKXsMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3
# DQEBCwUAA4ICAQCpq0LlFMbsDbXiQUcCGv90QV3xaaBGmT5tzfMX875z40qzAVcp
# NIZlxFm52PszxsXgx1NyX5BH1KuksUdb0lvo20JXj+C4OjRRj2e9cb4J2oB8MyCB
# gyeZo1sMHuJzXM6Jiu4xstRiKg26oSRPZNydZOymWA0n+DJMZGQunAJPthn4sf2w
# OyC0B/CeR0EO6LAe/I4hWStje8NDkBU/jOzSptAkUGoepZrmV6qhBcqV7KPd/wi0
# 79fyBgY8nQayFeMdLqj40omm9cziW2N0atKhsV9KRc81adj08pyFqmlPqVpnIfTy
# 1aC8aOmZR3+4sQgzw4UWCFA4wo808eH2eiR0+ryak8pks1ruHLmymVRj9JxPMOcQ
# LT6nrRDfkm2sZD0kPpHNRMI1bUtdv0n9aJ9+4YN/aj/DXN3XHVeFF+UVnvI2t68U
# WEbbar0NLuu7/KaeztWyezw4neotKSM+tTDk1sxOXFwd7FpXoZJdKzZSVbLI7ft0
# rLsI2L3xR8wCB2yJjH7tvFv19w9pjzTlv2PylLH79V28VVRyLhAigYeurwhRuc84
# s8cKwoXS53KMWuY8Bb8IaSGG5TpZu+Hnnu4HYKBYvBvOJmOGovDHiHD0+992Wja2
# wBEi0t+DhlFHRfcD8AHMPi4Xy4MKpIGZVGCmF+jic3tmqj854gc0X5tsfTCCBY0w
# ggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZIhvcNAQEMBQAwZTELMAkG
# A1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRp
# Z2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENB
# MB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVowYjELMAkGA1UEBhMCVVMx
# FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv
# bTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MIICIjANBgkqhkiG
# 9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjwwIjBpM+zCpyUuySE98orY
# WcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J58soR0uRf1gU8Ug9SH8ae
# FaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMHhOZ0O21x4i0MG+4g1ckg
# HWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6Zu53yEioZldXn1RYjgwr
# t0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQecN4x7axxLVqGDgDEI3Y
# 1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4bA3VdeGbZOjFEmjNAvwjX
# WkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9WV1CdoeJl2l6SPDgohIb
# Zpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCUtNJhbesz2cXfSwQAzH0c
# lcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvoZKYz0YkH4b235kOkGLim
# dwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/JvNNBERJb5RBQ6zHFynIW
# IgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCPorF+CiaZ9eRpL5gdLfXZ
# qbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOzX
# 44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3z
# bcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGG
# GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2Nh
# Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDBF
# BgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG
# 9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cHvZqsoYcs7IVeqRq7IviH
# GmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8UgPITtAq3votVs/59Pes
# MHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTnf+hZqPC/Lwum6fI0POz3
# A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxUjG/voVA9/HYJaISfb8rb
# II01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8jLfR+cWojayL/ErhULSd+
# 2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDCCBq4wggSWoAMCAQICEAc2N7ck
# VHzYR6z9KGYqXlswDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNV
# BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8G
# A1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTIyMDMyMzAwMDAwMFoX
# DTM3MDMyMjIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0
# LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hB
# MjU2IFRpbWVTdGFtcGluZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
# ggIBAMaGNQZJs8E9cklRVcclA8TykTepl1Gh1tKD0Z5Mom2gsMyD+Vr2EaFEFUJf
# pIjzaPp985yJC3+dH54PMx9QEwsmc5Zt+FeoAn39Q7SE2hHxc7Gz7iuAhIoiGN/r
# 2j3EF3+rGSs+QtxnjupRPfDWVtTnKC3r07G1decfBmWNlCnT2exp39mQh0YAe9tE
# QYncfGpXevA3eZ9drMvohGS0UvJ2R/dhgxndX7RUCyFobjchu0CsX7LeSn3O9TkS
# Z+8OpWNs5KbFHc02DVzV5huowWR0QKfAcsW6Th+xtVhNef7Xj3OTrCw54qVI1vCw
# MROpVymWJy71h6aPTnYVVSZwmCZ/oBpHIEPjQ2OAe3VuJyWQmDo4EbP29p7mO1vs
# gd4iFNmCKseSv6De4z6ic/rnH1pslPJSlRErWHRAKKtzQ87fSqEcazjFKfPKqpZz
# QmiftkaznTqj1QPgv/CiPMpC3BhIfxQ0z9JMq++bPf4OuGQq+nUoJEHtQr8FnGZJ
# UlD0UfM2SU2LINIsVzV5K6jzRWC8I41Y99xh3pP+OcD5sjClTNfpmEpYPtMDiP6z
# j9NeS3YSUZPJjAw7W4oiqMEmCPkUEBIDfV8ju2TjY+Cm4T72wnSyPx4JduyrXUZ1
# 4mCjWAkBKAAOhFTuzuldyF4wEr1GnrXTdrnSDmuZDNIztM2xAgMBAAGjggFdMIIB
# WTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS6FtltTYUvcyl2mi91jGog
# j57IbzAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8E
# BAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsG
# AQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0
# dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQu
# Y3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E
# aWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsG
# CWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAgEAfVmOwJO2b5ipRCIBfmbW2CFC
# 4bAYLhBNE88wU86/GPvHUF3iSyn7cIoNqilp/GnBzx0H6T5gyNgL5Vxb122H+oQg
# JTQxZ822EpZvxFBMYh0MCIKoFr2pVs8Vc40BIiXOlWk/R3f7cnQU1/+rT4osequF
# zUNf7WC2qk+RZp4snuCKrOX9jLxkJodskr2dfNBwCnzvqLx1T7pa96kQsl3p/yhU
# ifDVinF2ZdrM8HKjI/rAJ4JErpknG6skHibBt94q6/aesXmZgaNWhqsKRcnfxI2g
# 55j7+6adcq/Ex8HBanHZxhOACcS2n82HhyS7T6NJuXdmkfFynOlLAlKnN36TU6w7
# HQhJD5TNOXrd/yVjmScsPT9rp/Fmw0HNT7ZAmyEhQNC3EyTN3B14OuSereU0cZLX
# JmvkOHOrpgFPvT87eK1MrfvElXvtCl8zOYdBeHo46Zzh3SP9HSjTx/no8Zhf+yvY
# fvJGnXUsHicsJttvFXseGYs2uJPU5vIXmVnKcPA3v5gA3yAWTyf7YGcWoWa63VXA
# OimGsJigK+2VQbc61RWYMbRiCQ8KvYHZE/6/pNHzV9m8BPqC3jLfBInwAM1dwvnQ
# I38AC+R2AibZ8GV2QqYphwlHK+Z/GqSFD/yYlvZVVCsfgPrA8g4r5db7qS9EFUrn
# Ew4d2zc4GqEr9u3WfPwwgga8MIIEpKADAgECAhALrma8Wrp/lYfG+ekE4zMEMA0G
# CSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1
# NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjQwOTI2MDAwMDAwWhcNMzUxMTI1MjM1OTU5
# WjBCMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNlcnQxIDAeBgNVBAMTF0Rp
# Z2lDZXJ0IFRpbWVzdGFtcCAyMDI0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAvmpzn/aVIauWMLpbbeZZo7Xo/ZEfGMSIO2qZ46XB/QowIEMSvgjEdEZ3
# v4vrrTHleW1JWGErrjOL0J4L0HqVR1czSzvUQ5xF7z4IQmn7dHY7yijvoQ7ujm0u
# 6yXF2v1CrzZopykD07/9fpAT4BxpT9vJoJqAsP8YuhRvflJ9YeHjes4fduksTHul
# ntq9WelRWY++TFPxzZrbILRYynyEy7rS1lHQKFpXvo2GePfsMRhNf1F41nyEg5h7
# iOXv+vjX0K8RhUisfqw3TTLHj1uhS66YX2LZPxS4oaf33rp9HlfqSBePejlYeEdU
# 740GKQM7SaVSH3TbBL8R6HwX9QVpGnXPlKdE4fBIn5BBFnV+KwPxRNUNK6lYk2y1
# WSKour4hJN0SMkoaNV8hyyADiX1xuTxKaXN12HgR+8WulU2d6zhzXomJ2PleI9V2
# yfmfXSPGYanGgxzqI+ShoOGLomMd3mJt92nm7Mheng/TBeSA2z4I78JpwGpTRHiT
# 7yHqBiV2ngUIyCtd0pZ8zg3S7bk4QC4RrcnKJ3FbjyPAGogmoiZ33c1HG93Vp6lJ
# 415ERcC7bFQMRbxqrMVANiav1k425zYyFMyLNyE1QulQSgDpW9rtvVcIH7WvG9sq
# Yup9j8z9J1XqbBZPJ5XLln8mS8wWmdDLnBHXgYly/p1DhoQo5fkCAwEAAaOCAYsw
# ggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoG
# CCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAfBgNV
# HSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4EFgQUn1csA3cOKBWQ
# ZqVjXu5Pkh92oFswWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybDMuZGlnaWNl
# cnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGlu
# Z0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
# Y3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDovL2NhY2VydHMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFt
# cGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAPa0eH3aZW+M4hBJH2UOR9hHb
# m04IHdEoT8/T3HuBSyZeq3jSi5GXeWP7xCKhVireKCnCs+8GZl2uVYFvQe+pPTSc
# VJeCZSsMo1JCoZN2mMew/L4tpqVNbSpWO9QGFwfMEy60HofN6V51sMLMXNTLfhVq
# s+e8haupWiArSozyAmGH/6oMQAh078qRh6wvJNU6gnh5OruCP1QUAvVSu4kqVOcJ
# VozZR5RRb/zPd++PGE3qF1P3xWvYViUJLsxtvge/mzA75oBfFZSbdakHJe2BVDGI
# GVNVjOp8sNt70+kEoMF+T6tptMUNlehSR7vM+C13v9+9ZOUKzfRUAYSyyEmYtsnp
# ltD/GWX8eM70ls1V6QG/ZOB6b6Yum1HvIiulqJ1Elesj5TMHq8CWT/xrW7twipXT
# J5/i5pkU5E16RSBAdOp12aw8IQhhA/vEbFkEiF2abhuFixUDobZaA0VhqAsMHOma
# T3XThZDNi5U2zHKhUs5uHHdG6BoQau75KiNbh0c+hatSF+02kULkftARjsyEpHKs
# F7u5zKRbt5oK5YGwFvgc4pEVUNytmB3BpIiowOIIuDgP5M9WArHYSAR16gc0dP2X
# dkMEP5eBsX7bf/MGN4K3HP50v/01ZHo/Z5lGLvNwQ7XHBx1yomzLP8lx4Q1zZKDy
# Hcp4VQJLu2kWTsKsOqQxggY2MIIGMgIBATBcMEgxCzAJBgNVBAYTAlVTMRIwEAYD
# VQQKEwlJZGVuVHJ1c3QxJTAjBgNVBAMTHFRydXN0SUQgRVYgQ29kZSBTaWduaW5n
# IENBIDQCEEABiQm0x5wSO022AGxIKQYwDQYJYIZIAWUDBAIBBQCggYgwGQYJKoZI
# hvcNAQkDMQwGCisGAQQBgjcCAQQwHAYJKoZIhvcNAQkFMQ8XDTI0MTIyMDA3MzMy
# MlowHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIE
# IExRGWPKydv2XVOr4WpqUAKB0R3v/lMJfFPkfLcT1gyOMA0GCSqGSIb3DQEBAQUA
# BIICAAG5aVdl6RylYIaHd1DaHvlpJgKxDlivK2UrHSvaFJAy1JzF+YwZMrVktS/J
# wfSKOe/iEuprUjT90HpG0QXHNUHOusf/3jPB5CvKNQ1CY/MzQWc+fAPsnFhD1mb+
# yXPGDAzGY8n8enxuIsjKPCIBxNJgj8WZP9alqOeGQwKt9i5xQvZGRhaAD4rsxuTK
# 3t+xbqYXEUbQk4NuQCGLUISU3ix5OFaQnCqEcdcg/cXGLwWhfS8GgMXDdKR7vlZo
# iUjE2zGoJkvekyRBKuUpaWpfISHv3KTr2w9Uq4YNifJaYOVjciMzvu1KPLGoYjlx
# Qiaww/4nmGZRcMMpwuZU94e95xaM/PfHPIZ6+o0NzU7Z+i6JrjQolb5JZa5DZW+8
# RFlzvGYbg3UzeylHANlBhSYOYj2QFu7Y5leHY4e+Z/oWCIQuK7SZG/jpyFjNSc+D
# /mn5KUdVdQ5DoHfvq2VYC0QwN1ZIICXdt0uKha/Ir1qsL+PldsVOHfBxxUGl/hm+
# hN7Ok4eJxEs0MkKsKNk35Cl6l7g2/gk9zzUeqr7n3l3WMXgZyzUCek9xXfBgqJHc
# 8fRrMshd6SWMGSoaK+6Cd698pmfxEyVEw+1UQpeE+C6BWnBhdjunSM/POkLGhoOA
# XBT8BT+4784eWxhMvurv1/hHoTzx5vuN7grKhoh9SvLmso/coYIDIDCCAxwGCSqG
# SIb3DQEJBjGCAw0wggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRp
# Z2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQw
# OTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQQIQC65mvFq6f5WHxvnpBOMzBDANBglg
# hkgBZQMEAgEFAKBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcN
# AQkFMQ8XDTI0MTIyMDA3MzMyMlowLwYJKoZIhvcNAQkEMSIEIHP/++7QusvswuE5
# +zbKeglWANzpoa5y2/02E2uNneKaMA0GCSqGSIb3DQEBAQUABIICAHB3EbNQisyd
# t/1zJ0ae3attJPCDwDq3fhcu0TEPPNoU6LL0kU3jM2spoaCiyX9aAb8ggo9hyUjt
# fYfKteYkQBCyXSahwSoNzvyD+tZ8YkPlnhs3Ee824iVIukWzVK5yBDG/xoqu/n3O
# W+qio8UEFGlXzOK6nnd/npMWKjspb+Bic9VYToUXqz1kLvW7robBSlPY00GUXVvx
# im8DdAwv109vpkC8jqZlmR39fnQo8kqHgoNt5Bg84wDZnMNfMn6qn8/ZdvZXJyDc
# PLLCQ1UnCDfGt9Ohda3Lf4LEYGrBs655FTEwIYX5yJ/YKPg7C3a2NmC5Ofblac9g
# tu7hyKpqNc34GULTok4qTl9GPR4xxvXTQEwSkuHW57wNAZ4H2viLd087LxjzvR5R
# Us+D+m0d9+QBbW7+HhLS21cg+yxWOii9dTt8Vwhg5Oo2ivrj5z6dAvwG0MYVacpM
# oam97vJ2Zw/kbG7Cw7VmHciZ7gbXEcL2o/KKnTKnNrcAhCrWeB2iCtc4KUn+g9Dc
# kI8Urygf6gj8NECYnZwNyu0baF0vUNjQvAH50S7/RvdkGgqQtJCQaubX5RS+BhEK
# Jf9gnDCkObaY7J+p8IMTn5SAmFAPHkXGB97VcdsKRUDGrgcm9HrYxKEyYq2NsTam
# AmgPf1bVwq/DQMzxbngVJtx0FguIrpr/
# SIG # End signature block