PureStorage.CBS.AVS.VVOLS.Replication.ps1
function Sync-VvolReplicationGroup { [CmdletBinding()] Param( [Parameter(mandatory = $true)] [String]$ReplicationGroupID, [Parameter(mandatory = $true)] [String]$PointInTimeReplicaName, [Parameter(Mandatory = $True)] $vCenterServer, [Parameter(Mandatory = $true)] [String]$AVSCloudName, [Parameter(Mandatory = $true)] [String]$AVSResourceGroup ) $PointInTimeReplica = Get-SpbmPointInTimeReplica -Server $vCenterServer -Name $PointInTimeReplicaName -ErrorAction Ignore if ($PointInTimeReplica) { throw "Point-in-time replica '$PointInTimeReplicaName' already exists." } $repGroup = Get-SpbmReplicationGroup -Server $vCenterServer -ID $ReplicationGroupID if (-not $repGroup) { throw "Could not find replication group '$ReplicationGroupID'..." } elseif ($repGroup.State -ne "Target") { throw "Replication group '$ReplicationGroupID' need to be the Target replication group." } # wait for rep groups to sync $retryCount = 10 $TimeoutInSecs = 10 do { Write-Progress -Activity "Start sync replication group" -Status "50% Complete:" -PercentComplete 50 $params = @{ ReplicationGroupId = $ReplicationGroupID PointInTimeReplicaName = $PointInTimeReplicaName } Invoke-RunScript -RunCommandName "Sync-ReplicationGroup" -RunCommandModule "Microsoft.AVS.VVOLS" -Parameters $params ` -AVSCloudName $AVSCloudName -AVSResourceGroup $AVSResourceGroup -ErrorAction Ignore Start-Sleep -Seconds $TimeoutInSecs Get-SpbmPointInTimeReplica -name $PointInTimeReplicaName -ErrorAction SilentlyContinue -ErrorVariable stopError $retryCount-- } while ($stopError -and $retryCount -gt 0) if ($stopError) { throw 'Took too long to sync. Giving up.' } } function Start-VvolReplicationGroupFailover { [CmdletBinding()] Param( [Parameter(mandatory = $true)] [String]$ClusterName, [Parameter(mandatory = $true)] [String]$ReplicationGroupID, [Parameter(mandatory = $false)] [String]$PointInTimeReplicaName, [Parameter(mandatory = $false)] [bool]$PowerOn, [Parameter(mandatory = $false)] [bool]$TestFailover, [Parameter(Mandatory = $True)] $vCenterServer, [Parameter(Mandatory = $true)] [String]$AVSCloudName, [Parameter(Mandatory = $true)] [String]$AVSResourceGroup ) ## check that the cluster exists ## $Cluster = Get-Cluster -Server $vCenterServer -Name $ClusterName -ErrorAction Stop if (-not $Cluster) { throw "Could not find cluster '$ClusterName'..." } $repGroup = Get-SpbmReplicationGroup -ID $ReplicationGroupID if (-not $repGroup) { throw "Could not find replication group '$ReplicationGroupID'." } elseif ($repGroup.State -ne "Target") { throw "Replication group '$ReplicationGroupID' need to be a replication group in 'Target' state." } if ($PointInTimeReplicaName) { $PointInTimeReplica = Get-SpbmPointInTimeReplica -Server $vCenterServer -Name $PointInTimeReplicaName -ErrorAction Ignore if (-not $PointInTimeReplica) { throw "Could not find point-in-time replica '$PointInTimeReplicaName'." } } #creates groupid tag to tag new VMs $cat = Get-TagCategory -Name "PCBS-Rep-Group-ID" -ErrorAction SilentlyContinue if (-not $cat) { $cat = New-TagCategory -Name "PCBS-Rep-Group-ID" -EntityType "VirtualMachine" } $tag = Get-Tag -Name $ReplicationGroupID -Category $cat -ErrorAction SilentlyContinue if (-not $tag) { $tag = New-Tag -Name $ReplicationGroupID -Category $cat } $params = @{ ReplicationGroupId = $ReplicationGroupID TestFailover = $TestFailover PointInTimeReplicaName = $PointInTimeReplicaName } Write-Progress -Activity "Start failover" -Status "50% Complete:" -PercentComplete 50 Invoke-RunScript -RunCommandName "Start-ReplicationFailover" -RunCommandModule "Microsoft.AVS.VVOLS" -Parameters $params ` -AVSCloudName $AVSCloudName -AVSResourceGroup $AVSResourceGroup -GetNamedOutputs $ReplicatedVMFiles = (Get-Variable -Name NamedOutputs).Value # Might need change after MSFT published the new package $ReplicatedVMFiles.psobject.Properties | ForEach-Object { # create VMs on the failover vcenter Write-Host "Creating vm from vm file $($_.value)..." $newvm = New-VM -VMFilePath $_.value -ResourcePool $ClusterName # assign rep group tag to new vm New-TagAssignment -Tag $tag -Entity $newvm | Out-Null ## Starting the VM if PowerOn param is true ## if ($PowerOn) { $newvm | Start-VM -ErrorAction SilentlyContinue -ErrorVariable hasQuestion | out-null if ($hasQuestion) { ## there is a question that is asked if the VM is copied or moved. This question must be answered ## $newvm | Get-VMQuestion | Set-VMQuestion -Option '*copied*' -Confirm:$false } } } } function Start-VvolCleanupSourceReplicationGroupForFailover { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [String]$ReplicationGroupID, [Parameter(Mandatory = $false)] [bool]$RemoveFromDisk, [Parameter(Mandatory = $True)] $vCenterServer, [Parameter(Mandatory = $true)] [String]$AVSCloudName, [Parameter(Mandatory = $true)] [String]$AVSResourceGroup ) ## Setting the Replication Group Variable ## $repGroup = Get-SpbmReplicationGroup -Server $vCenterServer -ID $ReplicationGroupID if (-not $repGroup) { throw "Could not find replication group '$ReplicationGroupID'." } elseif ($repGroup.State -ne "Source") { throw "Replication group '$ReplicationGroupID' need to be the Source replication group." } ## Get VMs related to replication Group ## $relatedVMs = Get-VM -RelatedObject $repGroup foreach ($vm in $relatedVMs) { # stop VMs # if we fail to stop it's probably powered off already so we can ignore, if it's not it will fail on the next step $vm | Stop-VM -Confirm:$false -ErrorAction SilentlyContinue # unregister VMs # if VM exists but we cannot remove it, we should not continue if ($RemoveFromDisk) { Write-Verbose "Removing VM files from disk for VM $($vm.Name)" $vm | Remove-VM -Confirm:$false -DeletePermanently -ErrorAction Stop } else { Write-Verbose "Unregister VM $($vm.Name) from inventory" $vm | Remove-VM -Confirm:$false -ErrorAction Stop } } # remove tag category created on previous failovers $cat = Get-TagCategory -Server $vCenterServer -Name "PCBS-Rep-Group-ID" -ErrorAction SilentlyContinue if ($cat) { $tag = Get-Tag -Server $vCenterServer -Category $cat -ErrorAction SilentlyContinue if (-not $tag) { Remove-TagCategory -Server $vCenterServer -Category $cat -Confirm:$false } } } function Remove-ReplicationTags { [CmdletBinding()] Param( [Parameter(mandatory = $true)] [String]$ReplicationGroupID, [Parameter(Mandatory = $True)] $vCenterServer ) $cat = Get-TagCategory -Server $vCenterServer -Name "PCBS-Rep-Group-ID" -ErrorAction SilentlyContinue if ($cat) { $tag = Get-Tag -Server $vCenterServer -Name $ReplicationGroupID -Category $cat -ErrorAction SilentlyContinue if ($tag) { # cleanup tags created by previous failovers Remove-Tag -Server $vCenterServer -Tag $tag -Confirm:$false } } } function Get-VMsByReplicationTags { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [String]$ReplicationGroupID, [Parameter(Mandatory = $True)] $vCenterServer ) $cat = Get-TagCategory -Server $vCenterServer -Name "PCBS-Rep-Group-ID" -ErrorAction SilentlyContinue $tag = Get-Tag -Server $vCenterServer -Name $ReplicationGroupID -Category $cat -ErrorAction SilentlyContinue if (-not $tag) { return $null } # get vms list $vms = Get-VM -Server $vCenterServer -Tag $tag return $vms } function Stop-VvolReplicationGroupFailoverTest { <# .SYNOPSIS Stops test failover operation against group .DESCRIPTION Issue test failover operation against group .INPUTS replication group ID, .OUTPUTS N.A. .NOTES Version: 1.0 .EXAMPLE Stop-VvolReplicationGroupFailoverTest -RepGroupID myGroupId #> [CmdletBinding()] Param( [Parameter(mandatory = $true)] [String]$ReplicationGroupID, [Parameter(Mandatory = $True)] $vCenterServer, [Parameter(Mandatory = $true)] [String]$AVSCloudName, [Parameter(Mandatory = $true)] [String]$AVSResourceGroup ) ## Setting the Replication Group Variable ## $repGroup = Get-SpbmReplicationGroup -Server $vCenterServer -ID $ReplicationGroupID if (-not $repGroup) { throw "Could not find replication group '$ReplicationGroupID'." } elseif ($repGroup.State -ne "InTest") { throw "Replication group '$ReplicationGroupID' need to be the InTest replication group." } # get vms list $vms = Get-VMsByReplicationTags -vCenterServer $vCenterServer -ReplicationGroupID $ReplicationGroupID foreach ($vm in $vms) { # stop VMs # if we fail to stop it's probably powered off already so we can ignore, if it's not it will fail on the next step $vm | Stop-VM -Confirm:$false -ErrorAction SilentlyContinue # unregister VMs # if VM exists but we cannot remove it, we should not continue $vm | Remove-VM -DeletePermanently:$true -Confirm:$false -ErrorAction Stop } Remove-ReplicationTags -vCenterServer $vCenterServer -ReplicationGroupID $ReplicationGroupID $retryCount = 5 $TimeoutInSecs = 20 do { # Issue test failover stop # can fail saying that resource is still in use, but works if we retry $params = @{ ReplicationGroupId = $ReplicationGroupID } Write-Progress -Activity "Stop failover" -Status "50% Complete:" -PercentComplete 50 Invoke-RunScript -RunCommandName "Stop-ReplicationTestFailover" -RunCommandModule "Microsoft.AVS.VVOLS" -Parameters $params ` -AVSCloudName $AVSCloudName -AVSResourceGroup $AVSResourceGroup -ErrorAction SilentlyContinue $SPBMGroup = Get-SpbmReplicationGroup -ID $ReplicationGroupID # wait sometimes for vms to cleanup Start-Sleep -Seconds $TimeoutInSecs } while ($SPBMGroup.state -eq "InTest" -and $retryCount -gt 0) } function Start-VvolReprotectReplicationGroup { [CmdletBinding()] Param( [Parameter(Mandatory = $true)] [String]$ReplicationGroupID, [Parameter(Mandatory = $false)] [String]$PolicyName, [Parameter(Mandatory = $True)] $vCenterServer, [Parameter(Mandatory = $true)] [String]$AVSCloudName, [Parameter(Mandatory = $true)] [String]$AVSResourceGroup ) ## Setting the Replication Group Variable ## $failoverGroup = Get-SpbmReplicationGroup -Server $vCenterServer -ID $ReplicationGroupID if (-not $failoverGroup) { throw "Could not find replication group '$ReplicationGroupID'." } elseif ($failoverGroup.State -ne "FailedOver") { throw "Replication group '$ReplicationGroupID' need to be the FailedOver replication group." } ## Running the reverse replication group operation to reverse the source and target status for the Replication Group ## Write-Progress -Activity "Start failover reverse" -Status "50% Complete:" -PercentComplete 50 $params = @{ ReplicationGroupId = $ReplicationGroupID } Invoke-RunScript -RunCommandName "Start-ReplicationReverse" -RunCommandModule "Microsoft.AVS.VVOLS" -Parameters $params ` -AVSCloudName $AVSCloudName -AVSResourceGroup $AVSResourceGroup -GetNamedOutputs # Might need change after MSFT published the new package $new_source_group = (Get-Variable -Name NamedOutputs).Value.new_source_group # get vms list $cat = Get-TagCategory -Server $vCenterServer -Name "PCBS-Rep-Group-ID" -ErrorAction SilentlyContinue $tag = Get-Tag -Server $vCenterServer -Name $ReplicationGroupID -Category $cat -ErrorAction SilentlyContinue if (-not $tag) { throw "VM tag '$ReplicationGroupID' is missing. Failed to find VMs to reprotect." } # get vms list $vms = Get-VM -Tag $tag ## Setting the New VM to a variable on the recovery vCenter Server $relevantObjs = @() foreach ($newvm in $vms) { $relevantObjs += $newvm $HD1 = $newvm | Get-HardDisk $relevantObjs += $HD1 } ## get relevant SPBM-related configuration data of Virtual Machine, Hard Disk, and Datastore objects $spbmConfig = $relevantObjs | Get-SpbmEntityConfiguration ## Resetting the storage policy for the VM and each virtual disk to the "VVol No Requirements Policy" ## Write-Host "Resetting the storage policy for the VM and each virtual disk to the 'VVol No Requirements Policy'..." $noReqPolicy = Get-SpbmStoragePolicy -name 'VVol No Requirements Policy' $spbmConfig | Set-SpbmEntityConfiguration -StoragePolicy $noReqPolicy if ($PolicyName) { Write-Host "Re-protecting VMs with policy $PolicyName..." ## Setting the Variables for the replication group and storage policy that we want to use to re-protect the VM to the previous source/protected site ## $new_policy = Get-SpbmStoragePolicy -name $PolicyName -ErrorAction Ignore if (-not $new_policy) { throw "Could not find storage policy '$PolicyName'..." } $new_rg = $new_policy | Get-SpbmReplicationGroup -Name $new_source_group ## Applying the Storage Policy and Replication group to the VMs to complete the Re-protect process ## $spbmConfig | Set-SpbmEntityConfiguration -StoragePolicy $new_policy -ReplicationGroup $new_rg } Remove-ReplicationTags -ReplicationGroupID $ReplicationGroupID -vCenterServer $vCenterServer } # SIG # Begin signature block # MIIn+AYJKoZIhvcNAQcCoIIn6TCCJ+UCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUkP2J1NplD0k4cZJ1h47nrZ/c # M8WggiEoMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B # AQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk # IElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw # ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz # 7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS # 5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7 # bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfI # SKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jH # trHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14 # Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2 # h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt # 6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPR # iQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ER # ElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4K # Jpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAd # BgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SS # y4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAk # BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAC # hjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURS # b290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRV # HSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyh # hyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO # 0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo # 8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++h # UD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5x # aiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMIIGrjCCBJag # AwIBAgIQBzY3tyRUfNhHrP0oZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQG # EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl # cnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIw # MzIzMDAwMDAwWhcNMzcwMzIyMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UE # ChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQg # UlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEF # AAOCAg8AMIICCgKCAgEAxoY1BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCw # zIP5WvYRoUQVQl+kiPNo+n3znIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFz # sbPuK4CEiiIY3+vaPcQXf6sZKz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ # 7Gnf2ZCHRgB720RBidx8ald68Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7 # QKxfst5Kfc71ORJn7w6lY2zkpsUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/teP # c5OsLDnipUjW8LAxE6lXKZYnLvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCY # OjgRs/b2nuY7W+yB3iIU2YIqx5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9K # oRxrOMUp88qqlnNCaJ+2RrOdOqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6 # dSgkQe1CvwWcZklSUPRR8zZJTYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM # 1+mYSlg+0wOI/rOP015LdhJRk8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbC # dLI/Hgl27KtdRnXiYKNYCQEoAA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbEC # AwEAAaOCAV0wggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1N # hS9zKXaaL3WMaiCPnshvMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9P # MA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcB # AQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggr # BgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1 # c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAI # BgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7Zv # mKlEIgF+ZtbYIULhsBguEE0TzzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI # 2AvlXFvXbYf6hCAlNDFnzbYSlm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/ty # dBTX/6tPiix6q4XNQ1/tYLaqT5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVP # ulr3qRCyXen/KFSJ8NWKcXZl2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmB # o1aGqwpFyd/EjaDnmPv7pp1yr8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc # 6UsCUqc3fpNTrDsdCEkPlM05et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3c # HXg65J6t5TRxktcma+Q4c6umAU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0d # KNPH+ejxmF/7K9h+8kaddSweJywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZP # J/tgZxahZrrdVcA6KYawmKAr7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLe # Mt8EifAAzV3C+dAjfwAL5HYCJtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDy # Divl1vupL0QVSucTDh3bNzgaoSv27dZ8/DCCBrAwggSYoAMCAQICEAitQLJg0pxM # n17Nqb2TrtkwDQYJKoZIhvcNAQEMBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoT # DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UE # AxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTIxMDQyOTAwMDAwMFoXDTM2 # MDQyODIzNTk1OVowaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ # bmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBS # U0E0MDk2IFNIQTM4NCAyMDIxIENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC # AgoCggIBANW0L0LQKK14t13VOVkbsYhC9TOM6z2Bl3DFu8SFJjCfpI5o2Fz16zQk # B+FLT9N4Q/QX1x7a+dLVZxpSTw6hV/yImcGRzIEDPk1wJGSzjeIIfTR9TIBXEmtD # mpnyxTsf8u/LR1oTpkyzASAl8xDTi7L7CPCK4J0JwGWn+piASTWHPVEZ6JAheEUu # oZ8s4RjCGszF7pNJcEIyj/vG6hzzZWiRok1MghFIUmjeEL0UV13oGBNlxX+yT4Us # SKRWhDXW+S6cqgAV0Tf+GgaUwnzI6hsy5srC9KejAw50pa85tqtgEuPo1rn3MeHc # reQYoNjBI0dHs6EPbqOrbZgGgxu3amct0r1EGpIQgY+wOwnXx5syWsL/amBUi0nB # k+3htFzgb+sm+YzVsvk4EObqzpH1vtP7b5NhNFy8k0UogzYqZihfsHPOiyYlBrKD # 1Fz2FRlM7WLgXjPy6OjsCqewAyuRsjZ5vvetCB51pmXMu+NIUPN3kRr+21CiRshh # WJj1fAIWPIMorTmG7NS3DVPQ+EfmdTCN7DCTdhSmW0tddGFNPxKRdt6/WMtyEClB # 8NXFbSZ2aBFBE1ia3CYrAfSJTVnbeM+BSj5AR1/JgVBzhRAjIVlgimRUwcwhGug4 # GXxmHM14OEUwmU//Y09Mu6oNCFNBfFg9R7P6tuyMMgkCzGw8DFYRAgMBAAGjggFZ # MIIBVTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBRoN+Drtjv4XxGG+/5h # ewiIZfROQjAfBgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8B # Af8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYIKwYBBQUHAQEEazBpMCQG # CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKG # NWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290 # RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMBwGA1UdIAQVMBMwBwYFZ4EMAQMw # CAYGZ4EMAQQBMA0GCSqGSIb3DQEBDAUAA4ICAQA6I0Q9jQh27o+8OpnTVuACGqX4 # SDTzLLbmdGb3lHKxAMqvbDAnExKekESfS/2eo3wm1Te8Ol1IbZXVP0n0J7sWgUVQ # /Zy9toXgdn43ccsi91qqkM/1k2rj6yDR1VB5iJqKisG2vaFIGH7c2IAaERkYzWGZ # gVb2yeN258TkG19D+D6U/3Y5PZ7Umc9K3SjrXyahlVhI1Rr+1yc//ZDRdobdHLBg # XPMNqO7giaG9OeE4Ttpuuzad++UhU1rDyulq8aI+20O4M8hPOBSSmfXdzlRt2V0C # FB9AM3wD4pWywiF1c1LLRtjENByipUuNzW92NyyFPxrOJukYvpAHsEN/lYgggnDw # zMrv/Sk1XB+JOFX3N4qLCaHLC+kxGv8uGVw5ceG+nKcKBtYmZ7eS5k5f3nqsSc8u # pHSSrds8pJyGH+PBVhsrI/+PteqIe3Br5qC6/To/RabE6BaRUotBwEiES5ZNq0RA # 443wFSjO7fEYVgcqLxDEDAhkPDOPriiMPMuPiAsNvzv0zh57ju+168u38HcT5uco # P6wSrqUvImxB+YJcFWbMbA7KxYbD9iYzDAdLoNMHAmpqQDBISzSoUSC7rRuFCOJZ # DW3KBVAr6kocnqX9oKcfBnTn8tZSkP2vhUgh+Vc7tJwD7YZF9LRhbr9o4iZghurI # r6n+lB3nYxs6hlZ4TjCCBsIwggSqoAMCAQICEAVEr/OUnQg5pr/bP1/lYRYwDQYJ # KoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ # bmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2 # IFRpbWVTdGFtcGluZyBDQTAeFw0yMzA3MTQwMDAwMDBaFw0zNDEwMTMyMzU5NTla # MEgxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEgMB4GA1UE # AxMXRGlnaUNlcnQgVGltZXN0YW1wIDIwMjMwggIiMA0GCSqGSIb3DQEBAQUAA4IC # DwAwggIKAoICAQCjU0WHHYOOW6w+VLMj4M+f1+XS512hDgncL0ijl3o7Kpxn3GIV # WMGpkxGnzaqyat0QKYoeYmNp01icNXG/OpfrlFCPHCDqx5o7L5Zm42nnaf5bw9Yr # IBzBl5S0pVCB8s/LB6YwaMqDQtr8fwkklKSCGtpqutg7yl3eGRiF+0XqDWFsnf5x # XsQGmjzwxS55DxtmUuPI1j5f2kPThPXQx/ZILV5FdZZ1/t0QoRuDwbjmUpW1R9d4 # KTlr4HhZl+NEK0rVlc7vCBfqgmRN/yPjyobutKQhZHDr1eWg2mOzLukF7qr2JPUd # vJscsrdf3/Dudn0xmWVHVZ1KJC+sK5e+n+T9e3M+Mu5SNPvUu+vUoCw0m+PebmQZ # BzcBkQ8ctVHNqkxmg4hoYru8QRt4GW3k2Q/gWEH72LEs4VGvtK0VBhTqYggT02ke # fGRNnQ/fztFejKqrUBXJs8q818Q7aESjpTtC/XN97t0K/3k0EH6mXApYTAA+hWl1 # x4Nk1nXNjxJ2VqUk+tfEayG66B80mC866msBsPf7Kobse1I4qZgJoXGybHGvPrhv # ltXhEBP+YUcKjP7wtsfVx95sJPC/QoLKoHE9nJKTBLRpcCcNT7e1NtHJXwikcKPs # CvERLmTgyyIryvEoEyFJUX4GZtM7vvrrkTjYUQfKlLfiUKHzOtOKg8tAewIDAQAB # o4IBizCCAYcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/ # BAwwCgYIKwYBBQUHAwgwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcB # MB8GA1UdIwQYMBaAFLoW2W1NhS9zKXaaL3WMaiCPnshvMB0GA1UdDgQWBBSltu8T # 5+/N0GSh1VapZTGj3tXjSTBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsMy5k # aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0 # YW1waW5nQ0EuY3JsMIGQBggrBgEFBQcBAQSBgzCBgDAkBggrBgEFBQcwAYYYaHR0 # cDovL29jc3AuZGlnaWNlcnQuY29tMFgGCCsGAQUFBzAChkxodHRwOi8vY2FjZXJ0 # cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGlt # ZVN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCBGtbeoKm1mBe8cI1P # ijxonNgl/8ss5M3qXSKS7IwiAqm4z4Co2efjxe0mgopxLxjdTrbebNfhYJwr7e09 # SI64a7p8Xb3CYTdoSXej65CqEtcnhfOOHpLawkA4n13IoC4leCWdKgV6hCmYtld5 # j9smViuw86e9NwzYmHZPVrlSwradOKmB521BXIxp0bkrxMZ7z5z6eOKTGnaiaXXT # UOREEr4gDZ6pRND45Ul3CFohxbTPmJUaVLq5vMFpGbrPFvKDNzRusEEm3d5al08z # jdSNd311RaGlWCZqA0Xe2VC1UIyvVr1MxeFGxSjTredDAHDezJieGYkD6tSRN+9N # UvPJYCHEVkft2hFLjDLDiOZY4rbbPvlfsELWj+MXkdGqwFXjhr+sJyxB0JozSqg2 # 1Llyln6XeThIX8rC3D0y33XWNmdaifj2p8flTzU8AL2+nCpseQHc2kTmOt44Owde # OVj0fHMxVaCAEcsUDH6uvP6k63llqmjWIso765qCNVcoFstp8jKastLYOrixRoZr # uhf9xHdsFWyuq69zOuhJRrfVf8y2OMDY7Bz1tqG4QyzfTkx9HmhwwHcK1ALgXGC7 # KP845VJa1qwXIiNO9OzTF/tQa/8Hdx9xl0RBybhG02wyfFgvZ0dl5Rtztpn5aywG # Ru9BHvDwX+Db2a2QgESvgBBBijCCB2cwggVPoAMCAQICEATd+82EVAN2YngfhA+f # z/UwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD # ZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2ln # bmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMTAeFw0yMzEwMDQwMDAwMDBaFw0y # NjExMTUyMzU5NTlaMG8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u # MREwDwYDVQQHEwhCZWxsZXZ1ZTEbMBkGA1UEChMSUHVyZSBTdG9yYWdlLCBJbmMu # MRswGQYDVQQDExJQdXJlIFN0b3JhZ2UsIEluYy4wggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQCdhXqOLFS3HR5KD2RtAOzGdwKU0mMGGHfU7qUo1YFvDCN8 # vF/X8LDhouGtsZPdIfd298orsXHfXYElTgBo91gba7SqKBWi9xdXTqMR5vpt41K/ # a554AgiQp02nfYwuspZoAGnt//mDJ6ErP1jUFiWuwHsYsxk0gFEayp5xIKzmj3q4 # 9g+AenKpktbDn6HPpXZPdvg+g+GR9lPpiJo7Z40SIqzaacJsVcl5MhPfbFdLeP1s # n0MBW3BiYLyz4CEUq8IA2vJ2557N0uB0UzWERE31brL0mBn5gB1g8Zij9VsI9J5+ # Q+THKYIgwknlnXFiSwQhQbJ3Cn7IVotei1M/D011XjUR66kNHm02VVDsbxX92xLf # qIX7BZ0e6shMsOFVakkdM00nXhfRscDkRqEQ+IwgC3vcyJgp/QRX0SfWaaD5G0fi # ECMBZtmq5hijTJ18MAW2KaFePW0PIn9IRnoXS3tx9coXVJMTFwnLYdIukelF4jIW # 779IP5lQH7IBNHS01BgysjWVaQhPYxWZYtsxyRUX3gVRjFChhOtBNCAy2S+YYjUS # TOM7CdUNTtCARX/HgcRYxxU7UTOYXPYyabdQu3mFF8yD5YNkarlgc4TQ+H1PWnIU # l7pq3P0ZSaE5Est24ApVi6wlZC/Q3jQRKPziRg8x7Zv1TZX8TfxPDmE0Nsd+BwID # AQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYD # VR0OBBYEFCvH/lBQxrVtiuuihv+e6+2VgDPXMD4GA1UdIAQ3MDUwMwYGZ4EMAQQB # MCkwJwYIKwYBBQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAOBgNV # HQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBT # oFGgT4ZNaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0 # Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6 # Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5n # UlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDAkBggr # BgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBo # dHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2Rl # U2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAAMA0GCSqG # SIb3DQEBCwUAA4ICAQCrjkZxw1B2w/pYu4siB36x5J9Xate13IDt57bxZvc7OGgz # limeUq1/HObzW4Vej9tESBpT6a5FBuVSXQXvYQntQczEFBBksRXyad3tx5/xElHA # LaE6BCZUtPKu3/CSrgsvVi7OgWNybOFWF2Xk9K1djImG55J7jOY+8ZKegUSlHPjB # 8HF9G4VdS85L2SuFaRzOMTEIW+h0Ihkp6Js1rbe0YLZu/ad6VWFKoX++FDg3cbM8 # FLf482p+XCmuX/qZuFmySYDQQ4jvNiecEiyZ4m6HUryx9Fagc0NBADiOJc1R2p2I # QbBasyndhn8KWlGSudJ+uCfuzD6ukGVe4kOpYlqkzVeOscetaY0/5v+896yP4FA8 # NS68I2eMuKbis2ouOIrAVkNPdymBjaEW1U6q979upeEG22UjjrRkq5qSdO+nk2tK # NL1ZIc92bqIs132yuwVZ6A7Dvez03VSitT2UVBMz0BKNy1EnZ4hjqBrApU+Bbcwc # 7nPV9hKKbEFKCcCNLpkAP8SCVX6r7qMyqYhAl+XKSfCkMpxRD2LykRup5mz54cQP # RPoy86iVhFhWUez1O3t371sgYulMuxaff5mXK3xlzYZUHpJGkOYntQ2VlqUpl/VO # KcNTXWnuPOyuUZY0b9tWU0Ofs8Imp7+lULJ7XUbrJoY1bUa22ce912PVBsWOojGC # BjowggY2AgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ # bmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBS # U0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQBN37zYRUA3ZieB+ED5/P9TAJBgUrDgMC # GgUAoHAwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcC # AQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYE # FA2UOoTRiKvNZgWqk6UjWBxy7g4+MA0GCSqGSIb3DQEBAQUABIICAEZ0JzxVJQJE # wnrX85gH6HlD4eREDgWZiH3FrfMgKwElZulpBzHvMl2Nzjm5LIIPSr+bOZeSLu7R # QWsMrZdMni35AnH/bCkBnnGO2s8fvywFobAmeErNzqNpFENYPI2pJfEUBz3+L6BP # l1IODpAR3rW9qG2e7mjXE8ksYn5J6cRc/1KpGxUWriRzkJzZuQ3vf4RrqApv31dh # NoUjR/NbrBuXMV1YQCVchm0HWTIY8mQrO6lhWNs2OrhM1W16qmcrndX8aVId1Vc4 # dWXC8XkPAWYXt7nEF/rnraM6jhUYnFjwf8dmd5l8SGtCazH8ZsX7T+5PowN6zCnA # g8KVTlkdYdIekS4zBQ1DTba9AvkpMNey1jMgcUk1vRn19LIzPHw34Y/AYmXSNMYT # 6jFjAf879h3UgEP+4gY27qaLlRNrAaQeEY/Xg9ppibpXohFmey5/SpKjjchlkA8a # 7M41h+6raZhkLEDJjLrhYlc6nw3Ya7G96vIrEphbgNxPIzQ9+5fRpSsaU78c8zbL # kXEdWAkehKEMY/mI6hJg82e7MbAkGQP5fvaYsVQ0Fw9u7tvFMJOJxvduTil1xwUW # ePO4B23+EsMW3IGhNcmQ/7fN+fB9gonqKU9d0GPTa3tuoPwCoTth7r5GgakXbMwV # GDX8ONAoKy9DJi4gyfkGnBT8PE1VlvtcoYIDIDCCAxwGCSqGSIb3DQEJBjGCAw0w # ggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu # MTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRp # bWVTdGFtcGluZyBDQQIQBUSv85SdCDmmv9s/X+VhFjANBglghkgBZQMEAgEFAKBp # MBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI0MDEx # MDAxMTM1NlowLwYJKoZIhvcNAQkEMSIEIHX3y0KmngSF/hkAF0+3qXmb0c+qJk2S # fnsjEgAZCBo8MA0GCSqGSIb3DQEBAQUABIICAEHsh3wsTk+7xJunJ95LG//o2cf1 # EITH44PEk5qXvIYX9IwzulG4gYhNqJyycg8aw59adZKI8RmgJBkHiFLuXCTuZrXk # D/9d47okNcMIB2EUtypyCS0T0TXvanp6xE+g/pQ/iU/4OF9OquFthoZaMgzRYY7D # NZo/IjxathNQo8ka51MeUU0LtPGNA5IJQRyN6Aqepytl4ka7TBKyKfEUwkF+nPdy # JBh/II5fGPlIZGTL7Bv8HC46466eLWf0TUwfeFaZPUzm9ExiQdKZZ//JWZUqEY0n # SewasbdD+nhvt49QWGJAAzpc7ps+URW76VuRZyLY8AVxkxp4HSv2ITaT/MuRLWsY # UaOWWkBkwCcgre9XLYsS925ah0g0ovsX9D/HjwAcCImY4DNVnjWj4TSg16YtdNc+ # o42bn8xy+pYxxvYLuMkTbF9eO5Pyn/NZEFUMBulfnf3S79e4uX0yQjCxTIA5oNY0 # 2IAzGNhyc6pLv/5QHHK2VDJp/IEByyx/s7NUtn+/yGZ13Fmqvbhoq2H+NYLgqTQ9 # tQxwH1z4xqOwo+Xj/wBCBzkdQcka7373XpSeEn8cBIcZsa7bps5jMDc71Gn4Pn2M # ptTHK2vZ14kZzZEWz0rb1mNGMzJqNp+yihYEIU7rDN5xNzD/OstzCSifOi+4RcTZ # e0QHDsBFLE/Ujr2/ # SIG # End signature block |