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
# MIIhegYJKoZIhvcNAQcCoIIhazCCIWcCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD+VHbMK+IQy+NN
# T0LuFNOEmc8ZfVkJ0Rxl5G97yAuYKqCCGpowggeNMIIFdaADAgECAhBAAYkJtMec
# 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
# Ew4d2zc4GqEr9u3WfPwwggbCMIIEqqADAgECAhAFRK/zlJ0IOaa/2z9f5WEWMA0G
# CSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1
# NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjMwNzE0MDAwMDAwWhcNMzQxMDEzMjM1OTU5
# WjBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xIDAeBgNV
# BAMTF0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIzMIICIjANBgkqhkiG9w0BAQEFAAOC
# Ag8AMIICCgKCAgEAo1NFhx2DjlusPlSzI+DPn9fl0uddoQ4J3C9Io5d6OyqcZ9xi
# FVjBqZMRp82qsmrdECmKHmJjadNYnDVxvzqX65RQjxwg6seaOy+WZuNp52n+W8PW
# KyAcwZeUtKVQgfLPywemMGjKg0La/H8JJJSkghraarrYO8pd3hkYhftF6g1hbJ3+
# cV7EBpo88MUueQ8bZlLjyNY+X9pD04T10Mf2SC1eRXWWdf7dEKEbg8G45lKVtUfX
# eCk5a+B4WZfjRCtK1ZXO7wgX6oJkTf8j48qG7rSkIWRw69XloNpjsy7pBe6q9iT1
# HbybHLK3X9/w7nZ9MZllR1WdSiQvrCuXvp/k/XtzPjLuUjT71Lvr1KAsNJvj3m5k
# GQc3AZEPHLVRzapMZoOIaGK7vEEbeBlt5NkP4FhB+9ixLOFRr7StFQYU6mIIE9Np
# HnxkTZ0P387RXoyqq1AVybPKvNfEO2hEo6U7Qv1zfe7dCv95NBB+plwKWEwAPoVp
# dceDZNZ1zY8SdlalJPrXxGshuugfNJgvOuprAbD3+yqG7HtSOKmYCaFxsmxxrz64
# b5bV4RAT/mFHCoz+8LbH1cfebCTwv0KCyqBxPZySkwS0aXAnDU+3tTbRyV8IpHCj
# 7ArxES5k4MsiK8rxKBMhSVF+BmbTO77665E42FEHypS34lCh8zrTioPLQHsCAwEA
# AaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB
# /wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwH
# ATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4EFgQUpbbv
# E+fvzdBkodVWqWUxo97V40kwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybDMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVT
# dGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUHMAGGGGh0
# dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDovL2NhY2Vy
# dHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRp
# bWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAgRrW3qCptZgXvHCN
# T4o8aJzYJf/LLOTN6l0ikuyMIgKpuM+AqNnn48XtJoKKcS8Y3U623mzX4WCcK+3t
# PUiOuGu6fF29wmE3aEl3o+uQqhLXJ4Xzjh6S2sJAOJ9dyKAuJXglnSoFeoQpmLZX
# eY/bJlYrsPOnvTcM2Jh2T1a5UsK2nTipgedtQVyMadG5K8TGe8+c+njikxp2oml1
# 01DkRBK+IA2eqUTQ+OVJdwhaIcW0z5iVGlS6ubzBaRm6zxbygzc0brBBJt3eWpdP
# M43UjXd9dUWhpVgmagNF3tlQtVCMr1a9TMXhRsUo063nQwBw3syYnhmJA+rUkTfv
# TVLzyWAhxFZH7doRS4wyw4jmWOK22z75X7BC1o/jF5HRqsBV44a/rCcsQdCaM0qo
# NtS5cpZ+l3k4SF/Kwtw9Mt911jZnWon49qfH5U81PAC9vpwqbHkB3NpE5jreODsH
# XjlY9HxzMVWggBHLFAx+rrz+pOt5Zapo1iLKO+uagjVXKBbLafIymrLS2Dq4sUaG
# a7oX/cR3bBVsrquvczroSUa31X/MtjjA2Owc9bahuEMs305MfR5ocMB3CtQC4Fxg
# uyj/OOVSWtasFyIjTvTs0xf7UGv/B3cfcZdEQcm4RtNsMnxYL2dHZeUbc7aZ+Wss
# BkbvQR7w8F/g29mtkIBEr4AQQYoxggY2MIIGMgIBATBcMEgxCzAJBgNVBAYTAlVT
# MRIwEAYDVQQKEwlJZGVuVHJ1c3QxJTAjBgNVBAMTHFRydXN0SUQgRVYgQ29kZSBT
# aWduaW5nIENBIDQCEEABiQm0x5wSO022AGxIKQYwDQYJYIZIAWUDBAIBBQCggYgw
# GQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYJKoZIhvcNAQkFMQ8XDTI0MDkx
# MTE3MDYwNFowHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcN
# AQkEMSIEIExRGWPKydv2XVOr4WpqUAKB0R3v/lMJfFPkfLcT1gyOMA0GCSqGSIb3
# DQEBAQUABIICAIMs3jhLg1J3vooJn9/HaYycj7juZZ/RTT51+qrQ+cUej+TRDsh/
# x9WUkL72lMs1TMxs0XG4FotDlnVVvHP8IOKAbgf3iRjmd4C6xVy0dtXQpdF86MAa
# 6W1rDC4l2DKf5U7J5SNhYqRIL0NUUToL7lxRfZ94S8qpUiYivIG7uVSxKv0rs5i2
# naagZY/gE1odpbbwOb74Hm5BtPXv20leejR4/vyOIcE8WPhIj6cSBhmvaQIV0ifB
# kNAdb6xzQMTUYQuTXtcq6cgQy19KreZ2P+Jsuf/0O4OW0zHeECA8Ad74+8qfR1XY
# ss0bxhPWDkdaAvpdWkaxVMatr22uMRWZox5Sg5NGP3ck+4LZ+89eOjDmnL6DNdtG
# y5JqkTFdnK/K0ZkAOXShBeb+X0jq5KBUWc1XkySDpnPPLEIneVNBbCSmyevZ2JlP
# GMALJNg1h60X+/z8fgdlUS7QvZgEZG1AOcGDiu4P72E7+sbm56Lm7UxjHhljI3yg
# 1LHR+XJiXYtYKHueHoFZ8Kllqi7vYBDbKwxGKuQ7SZfKLF3N7SNGLGpcnYHOHwK+
# U9W28lOnwxCjbWSqbr5rJpOL8D6gD6clV86gqUAqqLvs6FGR4BUyyH4biyF5UtA7
# f5tMtRWVSH4pdRoXMVBuQLBujihORysaggSniK27qGLs56Tj0N7GGKO7oYIDIDCC
# AxwGCSqGSIb3DQEJBjGCAw0wggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNV
# BAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0
# IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQQIQBUSv85SdCDmmv9s/X+Vh
# FjANBglghkgBZQMEAgEFAKBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJ
# KoZIhvcNAQkFMQ8XDTI0MDkxMTE3MDYwNVowLwYJKoZIhvcNAQkEMSIEIBrtWuDx
# XXYJ1Oa627sOfQFnnflrOMYnKsOU1oN2sxopMA0GCSqGSIb3DQEBAQUABIICAEWz
# mZgL7c7IiyhtVGY1qwvTGfddFECl76R0dL8KbGKeh9A4/MWt58puxjzsS6P0/TTc
# h6EynIppixNJ5I8CDZEdOZ8rkpgGRH9Fp/PSx7VMuFQcUaSFN+HQcm/im3NUfBg7
# 3N1Cb4JMNHKeJV306BYnLF8ZuT5hMq+YIfD1D/zc5GE9BfSlG/eu79rjdw7C2cJE
# B8JKEaYxB3bUmRruCbGFXVrgETU6xeGddLVccjs7WroIJedl/Sk3FM3hMrLZes0M
# q/7RFGbqGdrJ1Rnk5XKfW54+SIxCLGa1oFEr6rImm06/ujzU+adY/nT3wf0byLCf
# it6CDcApJzu5U+yU99AF/8butXBjWNjdNj3+XXRCtsSDTAvgFeiWderXauYQbRvF
# GXLtI/iAe5PXJyjHe3ErRXfmnaPGzLcWygGmHMmcSBVqCglHah1/VOkxRiRK8Z9p
# pN1tz0b+f1SyMBre80/duaT/GLO29Mf1Ro7sttWhK1zRmaHtcARPByZf+rLtVtbL
# 9IHGGoNAPKLfYerjuP5IMFYK7nxleV5rLV826qGb+UUKqmdh9jmbmiQSrhPJbiL0
# 7fWRfCZkKOq70PAFSkBkjUsOWEnNIIk/fElxcH4QCcdgc/XW06u/gfzyJCy4ug20
# OJoepCQBhNKryghbZQTuic7ceNvS0Doh7304DVPQ
# SIG # End signature block