Src/Lab.ps1
function Start-Lab { <# .SYNOPSIS Starts all VMs in a lab in a predefined order. .DESCRIPTION The Start-Lab cmdlet starts all nodes defined in a PowerShell DSC configuration document, in a preconfigured order. Unlike the standard Start-VM cmdlet, the Start-Lab cmdlet will read the specified PowerShell DSC configuration document and infer the required start up order. The PowerShell DSC configuration document can define the start/stop order of the virtual machines and the boot delay between each VM power operation. This is defined with the BootOrder and BootDelay properties. The lower the virtual machine's BootOrder index, the earlier it is started (in relation to the other VMs). For example, a VM with a BootOrder index of 10 will be started before a VM with a BootOrder index of 11. All virtual machines receive a BootOrder value of 99 unless specified otherwise. The delay between each power operation is defined with the BootDelay property. This value is specified in seconds and is enforced between starting or stopping a virtual machine. For example, a VM with a BootDelay of 30 will enforce a 30 second delay after being powered on or after the power off command is issued. All VMs receive a BootDelay value of 0 (no delay) unless specified otherwise. .PARAMETER ConfigurationData Specifies a PowerShell DSC configuration data hashtable or a path to an existing PowerShell DSC .psd1 configuration document. .LINK about_ConfigurationData Stop-Lab #> [CmdletBinding()] param ( ## Lab DSC configuration data [Parameter(Mandatory, ValueFromPipeline)] [System.Collections.Hashtable] [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformationAttribute()] $ConfigurationData ) process { $nodes = @(); $ConfigurationData.AllNodes | Where-Object { $_.NodeName -ne '*' } | ForEach-Object { $nodes += [PSCustomObject] (ResolveLabVMProperties -NodeName $_.NodeName -ConfigurationData $ConfigurationData); }; $currentGroupCount = 0; $bootGroups = $nodes | Sort-Object -Property BootOrder | Group-Object -Property BootOrder; $bootGroups | ForEach-Object { $nodeDisplayNames = $_.Group.NodeDisplayName; $nodeDisplayNamesString = $nodeDisplayNames -join ', '; $currentGroupCount++; [System.Int32] $percentComplete = ($currentGroupCount / $bootGroups.Count) * 100; $activity = $localized.ConfiguringNode -f $nodeDisplayNamesString; Write-Progress -Id 42 -Activity $activity -PercentComplete $percentComplete; WriteVerbose ($localized.StartingVirtualMachine -f $nodeDisplayNamesString); Start-VM -Name $nodeDisplayNames; $maxGroupBootDelay = $_.Group.BootDelay | Sort-Object -Descending | Select-Object -First 1; if (($maxGroupBootDelay -gt 0) -and ($currentGroupCount -lt $bootGroups.Count)) { WriteVerbose ($localized.WaitingForVirtualMachine -f $maxGroupBootDelay, $nodeDisplayNamesString); for ($i = 1; $i -le $maxGroupBootDelay; $i++) { [System.Int32] $waitPercentComplete = ($i / $maxGroupBootDelay) * 100; $waitActivity = $localized.WaitingForVirtualMachine -f $maxGroupBootDelay, $nodeDisplayNamesString; Write-Progress -ParentId 42 -Activity $waitActivity -PercentComplete $waitPercentComplete; Start-Sleep -Seconds 1; } Write-Progress -Activity $waitActivity -Completed; } #end if boot delay } #end foreach boot group Write-Progress -Id 42 -Activity $activity -Completed; } #end process } #end function Start-Lab function Stop-Lab { <# .SYNOPSIS Stops all VMs in a lab in a predefined order. .DESCRIPTION The Stop-Lab cmdlet stops all nodes defined in a PowerShell DSC configuration document, in a preconfigured order. Unlike the standard Stop-VM cmdlet, the Stop-Lab cmdlet will read the specified PowerShell DSC configuration document and infer the required shutdown order. The PowerShell DSC configuration document can define the start/stop order of the virtual machines and the boot delay between each VM power operation. This is defined with the BootOrder and BootDelay properties. The higher the virtual machine's BootOrder index, the earlier it is stopped (in relation to the other VMs). For example, a VM with a BootOrder index of 11 will be stopped before a VM with a BootOrder index of 10. All virtual machines receive a BootOrder value of 99 unless specified otherwise. The delay between each power operation is defined with the BootDelay property. This value is specified in seconds and is enforced between starting or stopping a virtual machine. For example, a VM with a BootDelay of 30 will enforce a 30 second delay after being powered on or after the power off command is issued. All VMs receive a BootDelay value of 0 (no delay) unless specified otherwise. .PARAMETER ConfigurationData Specifies a PowerShell DSC configuration data hashtable or a path to an existing PowerShell DSC .psd1 configuration document. .LINK about_ConfigurationData Start-Lab #> [CmdletBinding()] param ( ## Lab DSC configuration data [Parameter(Mandatory, ValueFromPipeline)] [System.Collections.Hashtable] [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformationAttribute()] $ConfigurationData ) process { $nodes = @(); $ConfigurationData.AllNodes | Where-Object { $_.NodeName -ne '*' } | ForEach-Object { $nodes += [PSCustomObject] (ResolveLabVMProperties -NodeName $_.NodeName -ConfigurationData $ConfigurationData); }; $currentGroupCount = 0; $bootGroups = $nodes | Sort-Object -Property BootOrder -Descending | Group-Object -Property BootOrder; $bootGroups | ForEach-Object { $nodeDisplayNames = $_.Group.NodeDisplayName; $nodeDisplayNamesString = $nodeDisplayNames -join ', '; $currentGroupCount++; [System.Int32] $percentComplete = ($currentGroupCount / $bootGroups.Count) * 100; $activity = $localized.ConfiguringNode -f $nodeDisplayNamesString; Write-Progress -Id 42 -Activity $activity -PercentComplete $percentComplete; WriteVerbose ($localized.StoppingVirtualMachine -f $nodeDisplayNamesString); Stop-VM -Name $nodeDisplayNames -Force; } #end foreach boot group Write-Progress -Id 42 -Activity $activity -Completed; } #end process } #end function Stop-Lab function Reset-Lab { <# .SYNOPSIS Reverts all VMs in a lab back to their initial configuration. .DESCRIPTION The Reset-Lab cmdlet will reset all the nodes defined in a PowerShell DSC configuration document, back to their initial state. If virtual machines are powered on, they will automatically be powered off when restoring the snapshot. When virtual machines are created - before they are powered on - a baseline snapshot is created. This snapshot is taken before the Sysprep process has been run and/or any PowerShell DSC configuration has been applied. WARNING: You will lose all changes to all virtual machines that have not been committed via another snapshot. .PARAMETER ConfigurationData Specifies a PowerShell DSC configuration data hashtable or a path to an existing PowerShell DSC .psd1 configuration document. .LINK Checkpoint-Lab .NOTES This cmdlet uses the baseline snapshot snapshot created by the Start-LabConfiguration cmdlet. If the baseline was not created or the baseline snapshot does not exist, the lab VMs can be recreated with the Start-LabConfiguration -Force. #> [CmdletBinding()] param ( ## Lab DSC configuration data [Parameter(Mandatory, ValueFromPipeline)] [System.Collections.Hashtable] [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformationAttribute()] $ConfigurationData ) process { ## Revert to Base/Lab snapshots... $snapshotName = $localized.BaselineSnapshotName -f $labDefaults.ModuleName; Restore-Lab -ConfigurationData $ConfigurationData -SnapshotName $snapshotName -Force; } #end process } #end function Reset-Lab function Checkpoint-Lab { <# .SYNOPSIS Snapshots all lab VMs in their current configuration. .DESCRIPTION The Checkpoint-Lab creates a VM checkpoint of all the nodes defined in a PowerShell DSC configuration document. When creating the snapshots, they will be created using the snapshot name specified. All virtual machines should be powered off when the snapshot is taken to ensure that the machine is in a consistent state. If VMs are powered on, an error will be generated. You can override this behaviour by specifying the -Force parameter. WARNING: If the -Force parameter is used, the virtual machine snapshot(s) may be in an inconsistent state. .PARAMETER ConfigurationData Specifies a PowerShell DSC configuration data hashtable or a path to an existing PowerShell DSC .psd1 configuration document. .PARAMETER SnapshotName Specifies the virtual machine snapshot name that applied to each VM in the PowerShell DSC configuration document. This name is used to restore a lab configuration. It can contain spaces, but is not recommended. .PARAMETER Force Forces virtual machine snapshots to be taken - even if there are any running virtual machines. .LINK Restore-Lab Reset-Lab #> [CmdletBinding()] param ( ## Lab DSC configuration data [Parameter(Mandatory, ValueFromPipeline)] [System.Collections.Hashtable] [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformationAttribute()] $ConfigurationData, ## Snapshot name [Parameter(Mandatory)] [Alias('Name')] [System.String] $SnapshotName, ## Force snapshots if virtual machines are on [System.Management.Automation.SwitchParameter] $Force ) process { $nodes = $ConfigurationData.AllNodes | Where-Object { $_.NodeName -ne '*' } | ForEach-Object { ResolveLabVMProperties -NodeName $_.NodeName -ConfigurationData $ConfigurationData; }; $runningNodes = Get-VM -Name $nodes.NodeDisplayName | Where-Object { $_.State -ne 'Off' } if ($runningNodes -and $Force) { NewLabVMSnapshot -Name $nodes.NodeDisplayName -SnapshotName $SnapshotName; } elseif ($runningNodes) { foreach ($runningNode in $runningNodes) { Write-Error -Message ($localized.CannotSnapshotNodeError -f $runningNode.Name); } } else { NewLabVMSnapshot -Name $nodes.NodeDisplayName -SnapshotName $SnapshotName; } } #end process } #end function Checkpoint-Lab function Restore-Lab { <# .SYNOPSIS Restores all lab VMs to a previous configuration. .DESCRIPTION The Restore-Lab reverts all the nodes defined in a PowerShell DSC configuration document, back to a previously captured configuration. When creating the snapshots, they are created using a snapshot name. To restore a lab to a previous configuration, you must supply the same snapshot name. All virtual machines should be powered off when the snapshots are restored. If VMs are powered on, an error will be generated. You can override this behaviour by specifying the -Force parameter. WARNING: If the -Force parameter is used, running virtual machines will be powered off automatically. .PARAMETER ConfigurationData Specifies a PowerShell DSC configuration data hashtable or a path to an existing PowerShell DSC .psd1 configuration document. .PARAMETER SnapshotName Specifies the virtual machine snapshot name to be restored. You must use the same snapshot name used when creating the snapshot with the Checkpoint-Lab cmdlet. .PARAMETER Force Forces virtual machine snapshots to be restored - even if there are any running virtual machines. .LINK Checkpoint-Lab Reset-Lab #> [CmdletBinding()] param ( ## Lab DSC configuration data [Parameter(Mandatory, ValueFromPipeline)] [System.Collections.Hashtable] [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformationAttribute()] $ConfigurationData, ## Snapshot name [Parameter(Mandatory)] [Alias('Name')] [System.String] $SnapshotName, ## Force snapshots if virtual machines are on [System.Management.Automation.SwitchParameter] $Force ) process { $nodes = @(); $ConfigurationData.AllNodes | Where-Object { $_.NodeName -ne '*' } | ForEach-Object { $nodes += ResolveLabVMProperties -NodeName $_.NodeName -ConfigurationData $ConfigurationData; }; $runningNodes = $nodes | ForEach-Object { Get-VM -Name $_.NodeDisplayName } | Where-Object { $_.State -ne 'Off' } $currentNodeCount = 0; if ($runningNodes -and $Force) { $nodes | Sort-Object { $_.BootOrder } | ForEach-Object { $currentNodeCount++; [System.Int32] $percentComplete = ($currentNodeCount / $nodes.Count) * 100; $activity = $localized.ConfiguringNode -f $_.NodeDisplayName; Write-Progress -Id 42 -Activity $activity -PercentComplete $percentComplete; WriteVerbose ($localized.RestoringVirtualMachineSnapshot -f $_.NodeDisplayName, $SnapshotName); GetLabVMSnapshot -Name $_.NodeDisplayName -SnapshotName $SnapshotName | Restore-VMSnapshot; } } elseif ($runningNodes) { foreach ($runningNode in $runningNodes) { Write-Error -Message ($localized.CannotSnapshotNodeError -f $runningNode.NodeDisplayName); } } else { $nodes | Sort-Object { $_.BootOrder } | ForEach-Object { $currentNodeCount++; [System.Int32] $percentComplete = ($currentNodeCount / $nodes.Count) * 100; $activity = $localized.ConfiguringNode -f $_.NodeDisplayName; Write-Progress -Id 42 -Activity $activity -PercentComplete $percentComplete; WriteVerbose ($localized.RestoringVirtualMachineSnapshot -f $_.NodeDisplayName, $SnapshotName); GetLabVMSnapshot -Name $_.NodeDisplayName -SnapshotName $SnapshotName | Restore-VMSnapshot -Confirm:$false; } } Write-Progress -Id 42 -Activity $activity -Completed; } #end process } #end function Restore-Lab # SIG # Begin signature block # MIIXtwYJKoZIhvcNAQcCoIIXqDCCF6QCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUK18RnK6F22iD9SjWl1YFTHvV # IzWgghLqMIID7jCCA1egAwIBAgIQfpPr+3zGTlnqS5p31Ab8OzANBgkqhkiG9w0B # AQUFADCBizELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIG # A1UEBxMLRHVyYmFudmlsbGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhh # d3RlIENlcnRpZmljYXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcg # Q0EwHhcNMTIxMjIxMDAwMDAwWhcNMjAxMjMwMjM1OTU5WjBeMQswCQYDVQQGEwJV # UzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xMDAuBgNVBAMTJ1N5bWFu # dGVjIFRpbWUgU3RhbXBpbmcgU2VydmljZXMgQ0EgLSBHMjCCASIwDQYJKoZIhvcN # AQEBBQADggEPADCCAQoCggEBALGss0lUS5ccEgrYJXmRIlcqb9y4JsRDc2vCvy5Q # WvsUwnaOQwElQ7Sh4kX06Ld7w3TMIte0lAAC903tv7S3RCRrzV9FO9FEzkMScxeC # i2m0K8uZHqxyGyZNcR+xMd37UWECU6aq9UksBXhFpS+JzueZ5/6M4lc/PcaS3Er4 # ezPkeQr78HWIQZz/xQNRmarXbJ+TaYdlKYOFwmAUxMjJOxTawIHwHw103pIiq8r3 # +3R8J+b3Sht/p8OeLa6K6qbmqicWfWH3mHERvOJQoUvlXfrlDqcsn6plINPYlujI # fKVOSET/GeJEB5IL12iEgF1qeGRFzWBGflTBE3zFefHJwXECAwEAAaOB+jCB9zAd # BgNVHQ4EFgQUX5r1blzMzHSa1N197z/b7EyALt0wMgYIKwYBBQUHAQEEJjAkMCIG # CCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29tMBIGA1UdEwEB/wQIMAYB # Af8CAQAwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NybC50aGF3dGUuY29tL1Ro # YXd0ZVRpbWVzdGFtcGluZ0NBLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCDAOBgNV # HQ8BAf8EBAMCAQYwKAYDVR0RBCEwH6QdMBsxGTAXBgNVBAMTEFRpbWVTdGFtcC0y # MDQ4LTEwDQYJKoZIhvcNAQEFBQADgYEAAwmbj3nvf1kwqu9otfrjCR27T4IGXTdf # plKfFo3qHJIJRG71betYfDDo+WmNI3MLEm9Hqa45EfgqsZuwGsOO61mWAK3ODE2y # 0DGmCFwqevzieh1XTKhlGOl5QGIllm7HxzdqgyEIjkHq3dlXPx13SYcqFgZepjhq # IhKjURmDfrYwggSjMIIDi6ADAgECAhAOz/Q4yP6/NW4E2GqYGxpQMA0GCSqGSIb3 # DQEBBQUAMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3Jh # dGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2aWNlcyBD # QSAtIEcyMB4XDTEyMTAxODAwMDAwMFoXDTIwMTIyOTIzNTk1OVowYjELMAkGA1UE # BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMTQwMgYDVQQDEytT # eW1hbnRlYyBUaW1lIFN0YW1waW5nIFNlcnZpY2VzIFNpZ25lciAtIEc0MIIBIjAN # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomMLOUS4uyOnREm7Dv+h8GEKU5Ow # mNutLA9KxW7/hjxTVQ8VzgQ/K/2plpbZvmF5C1vJTIZ25eBDSyKV7sIrQ8Gf2Gi0 # jkBP7oU4uRHFI/JkWPAVMm9OV6GuiKQC1yoezUvh3WPVF4kyW7BemVqonShQDhfu # ltthO0VRHc8SVguSR/yrrvZmPUescHLnkudfzRC5xINklBm9JYDh6NIipdC6Anqh # d5NbZcPuF3S8QYYq3AhMjJKMkS2ed0QfaNaodHfbDlsyi1aLM73ZY8hJnTrFxeoz # C9Lxoxv0i77Zs1eLO94Ep3oisiSuLsdwxb5OgyYI+wu9qU+ZCOEQKHKqzQIDAQAB # o4IBVzCCAVMwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAO # BgNVHQ8BAf8EBAMCB4AwcwYIKwYBBQUHAQEEZzBlMCoGCCsGAQUFBzABhh5odHRw # Oi8vdHMtb2NzcC53cy5zeW1hbnRlYy5jb20wNwYIKwYBBQUHMAKGK2h0dHA6Ly90 # cy1haWEud3Muc3ltYW50ZWMuY29tL3Rzcy1jYS1nMi5jZXIwPAYDVR0fBDUwMzAx # oC+gLYYraHR0cDovL3RzLWNybC53cy5zeW1hbnRlYy5jb20vdHNzLWNhLWcyLmNy # bDAoBgNVHREEITAfpB0wGzEZMBcGA1UEAxMQVGltZVN0YW1wLTIwNDgtMjAdBgNV # HQ4EFgQURsZpow5KFB7VTNpSYxc/Xja8DeYwHwYDVR0jBBgwFoAUX5r1blzMzHSa # 1N197z/b7EyALt0wDQYJKoZIhvcNAQEFBQADggEBAHg7tJEqAEzwj2IwN3ijhCcH # bxiy3iXcoNSUA6qGTiWfmkADHN3O43nLIWgG2rYytG2/9CwmYzPkSWRtDebDZw73 # BaQ1bHyJFsbpst+y6d0gxnEPzZV03LZc3r03H0N45ni1zSgEIKOq8UvEiCmRDoDR # EfzdXHZuT14ORUZBbg2w6jiasTraCXEQ/Bx5tIB7rGn0/Zy2DBYr8X9bCT2bW+IW # yhOBbQAuOA2oKY8s4bL0WqkBrxWcLC9JG9siu8P+eJRRw4axgohd8D20UaF5Mysu # e7ncIAkTcetqGVvP6KUwVyyJST+5z3/Jvz4iaGNTmr1pdKzFHTx/kuDDvBzYBHUw # ggUZMIIEAaADAgECAhADViTO4HBjoJNSwH9//cwJMA0GCSqGSIb3DQEBCwUAMHIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJ # RCBDb2RlIFNpZ25pbmcgQ0EwHhcNMTUwNTE5MDAwMDAwWhcNMTcwODIzMTIwMDAw # WjBgMQswCQYDVQQGEwJHQjEPMA0GA1UEBxMGT3hmb3JkMR8wHQYDVQQKExZWaXJ0 # dWFsIEVuZ2luZSBMaW1pdGVkMR8wHQYDVQQDExZWaXJ0dWFsIEVuZ2luZSBMaW1p # dGVkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqLQmabdimcQtYPTQ # 9RSjv3ThEmFTRJt/MzseYYtZpBTcR6BnSfj8RfkC4aGZvspFgH0cGP/SNJh1w67b # iX9oT5NFL9sUJHUsVdyPBA1LhpWcF09PP28mGGKO3oQHI4hTLD8etiIlF9qFantd # 1Pmo0jdqT4uErSmx0m4kYGUUTa5ZPAK0UZSuAiNX6iNIL+rj/BPbI3nuPJzzx438 # oHYkZGRtsx11+pLA6hIKyUzRuIDoI7JQ0nZ0MkCziVyc6xGfS54JVLaVCEteTKPz # Gc4yyvCqp6Tfe9gs8UuxJiEMdH5fvllTU4aoXbm+W8tonkE7i/19rv8S1A2VPiVV # xNLbpwIDAQABo4IBuzCCAbcwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1 # DlgwHQYDVR0OBBYEFP2RNOWYipdNCSRVb5jIcyRp9tUDMA4GA1UdDwEB/wQEAwIH # gDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8v # Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYv # aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmww # QgYDVR0gBDswOTA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93 # d3cuZGlnaWNlcnQuY29tL0NQUzCBhAYIKwYBBQUHAQEEeDB2MCQGCCsGAQUFBzAB # hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTgYIKwYBBQUHMAKGQmh0dHA6Ly9j # YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURDb2RlU2ln # bmluZ0NBLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4IBAQCclXHR # DhDyJr81eiD0x+AL04ryDwdKT+PooKYgOxc7EhRn59ogxNO7jApQPSVo0I11Zfm6 # zQ6K6RPWhxDenflf2vMx7a0tIZlpHhq2F8praAMykK7THA9F3AUxIb/lWHGZCock # yD/GQvJek3LSC5NjkwQbnubWYF/XZTDzX/mJGU2DcG1OGameffR1V3xODHcUE/K3 # PWy1bzixwbQCQA96GKNCWow4/mEW31cupHHSo+XVxmjTAoC93yllE9f4Kdv6F29H # bRk0Go8Yn8WjWeLE/htxW/8ruIj0KnWkG+YwmZD+nTegYU6RvAV9HbJJYUEIfhVy # 3DeK5OlY9ima2sdtMIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1b5VQCDANBgkq # hkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB # c3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgxMDIyMTIwMDAw # WjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL # ExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3Vy # ZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB # CgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLXcep2nQUut4/6 # kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSRI5aQd4L5oYQj # ZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXiTWAYvqrEsq5w # MWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5Ng2Q7+S1TqSp # 6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8vYWxYoNzQYIH # 5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYDVR0TAQH/BAgw # BgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMweQYI # KwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j # b20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp # Q2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6 # Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmww # OqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ # RFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUH # AgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZIAYb9bAMwHQYD # VR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaAFEXroq/0ksuC # MS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPzItEVyCx8JSl2 # qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRupY5a4l4kgU4Q # pO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKNJK4kxscnKqEp # KBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmifz0DLQESlE/Dm # ZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN3fYBIM6ZMWM9 # CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKyZqHnGKSaZFHv # MYIENzCCBDMCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0 # IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNl # cnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQQIQA1YkzuBwY6CTUsB/ # f/3MCTAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkq # hkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGC # NwIBFTAjBgkqhkiG9w0BCQQxFgQUfZ+UQgTtNa5LSyM0Fti4HID938kwDQYJKoZI # hvcNAQEBBQAEggEANaMcqy5XOfTH3axDqEn0ccLm0IWyVBgy13Dtzl7RoExkCFIp # vfs7c2exCbfSG9766z9XwZT9iAIDemdUZQ/Mg5MIpOW70M6zfJVac2WjbRqiEAjB # bL12rb8oRdxwZUoZwTT3wUXA/0uSPFWGnrzukds59GhZDPinLxU6LZ1yVJWeeKKq # 8AHVfSE+xxg8TulJuRbgA/BXIsfI5xHNO6jcX+k8OomwnKLM3sDcouOMdYYmeI/O # kJWAHF1H+pIQs7m5cs8H9S3qdGZq086dQBHDfCikUEaM/ppzLrF+buOYXZIlPguN # 1yPTq4yPFwpiGpgD349q0iqju4HNTXvJM6iBr6GCAgswggIHBgkqhkiG9w0BCQYx # ggH4MIIB9AIBATByMF4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBD # b3Jwb3JhdGlvbjEwMC4GA1UEAxMnU3ltYW50ZWMgVGltZSBTdGFtcGluZyBTZXJ2 # aWNlcyBDQSAtIEcyAhAOz/Q4yP6/NW4E2GqYGxpQMAkGBSsOAwIaBQCgXTAYBgkq # hkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNjA0MTMxMzMz # MjBaMCMGCSqGSIb3DQEJBDEWBBR19Hi0QQCxrf0wYiDjoaaSiPU7uDANBgkqhkiG # 9w0BAQEFAASCAQB1iFazAswicf4xMISJWgHsUm5DByH/uLW4YJwy+5frQfiuG9QA # YO5hqDuZwWMS7PIK6fZYPB1fsPObVg+2BK0WZE6Y+PHJKyVMEmOAsR/JjnDJ0TaT # h3Nbwjd5q0FhhFfSqP7PZEOix0MHfN1PFsOpfZrczLF08ahGJE6oJXr4LDsuM6FQ # CsAx+sXZpiV/361p4YbVWXi6i22Q1Kn8Y8VWjvlKpui3/O/en1UQAasS/zpw6i/b # y9xhwjgiM1L6I6bI9URsECejTgHNyNIZWrgsOITghE+nIm8jtGcdL/giR+WkSilS # KEGo1nP6dKjKp/G5BoDcE83bktHBZFN3a9Yd # SIG # End signature block |