PureStorage.CBS.AVS.VMFS.ps1
function Get-PCBSVolumeFromVMFSDataStore { Param( [Parameter(mandatory=$true)] $FlashArray, [Parameter(mandatory=$true)] $DataStore ) $Lun = $Datastore.ExtensionData.Info.Vmfs.Extent.DiskName |select-object -unique if ($Lun -like 'naa.624a9370*') { $VolSerial = ($lun.ToUpper()).substring(12) $PureVol = Get-Pfa2Volume -Array $FlashArray -Filter "Serial='$VolSerial'" } else { throw "This VMFS is not hosted on Pure Cloud Block Store." } return $PureVol } function Remove-PfaVmfsDatastore { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] $Cluster, [Parameter(Mandatory=$true)] $Datastore, [Parameter(ValueFromPipeline=$True)] $FlashArray, [Parameter(Mandatory=$false)] [String]$AVSCloudName, [Parameter(Mandatory=$false)] [String]$AzureSubscriptionId, [Parameter(Mandatory=$false)] [String]$AVSResourceGroup ) $PureVol = Get-PCBSVolumeFromVMFSDataStore -FlashArray $FlashArray -Datastore $Datastore Write-Progress -Activity "Dismounting datastore" -Status "25% Complete:" -PercentComplete 25 $params = @{ ClusterName = $Cluster.Name; DatastoreName = $Datastore.Name } # Question: We just do unmount/detach at VMWare side. Do we need to run Remove-Datastore to clean the datastore? Invoke-RunScript -CmdletName "Dismount-VmfsDatastore" -Parameters $params ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup Write-Progress -Activity "Removing volume" -Status "50% Complete:" -PercentComplete 50 # Remove volume from array hostgroup if available $FaHg = Get-PCBSHostGroupfromVcCluster -Flasharray $Flasharray -Cluster $Cluster $HgConnection = Get-Pfa2Connection -Array $FlashArray -VolumeNames $PureVol.Name -HostGroupNames $FaHg.Name -ErrorAction SilentlyContinue if ($HgConnection -ne $null) { Write-Host "Removing volume $($PureVol.Name) from host group $($FaHg.Name)..." Remove-Pfa2Connection -Array $FlashArray -VolumeNames $PureVol.Name -HostGroupNames $FaHg.Name } # Destroy volume if there is no host/hg connections for the volume $Connections = Get-Pfa2Connection -Array $FlashArray -VolumeNames $PureVol.Name if ($Connections -eq $null) { Write-Host "Destroying volume $($PureVol.Name)..." Remove-Pfa2Volume -Array $FlashArray -Name $PureVol.Name } Write-Progress -Activity "Rescanning storage" -Status "75% Complete:" -PercentComplete 75 $params = @{ ClusterName = $Cluster.Name; } Invoke-RunScript -CmdletName "Sync-ClusterVMHostStorage" -Parameters $params ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup } function New-VolumeFromSnaspshot { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$True)] $FlashArray, [Parameter(Mandatory=$true)] [String]$SnapshotName ) $VolumeSnapshot = Get-Pfa2VolumeSnapshot -Array $FlashArray -Name $SnapshotName -ErrorAction Ignore if (-not $VolumeSnapshot) { throw "Could not find snapshot '$SnapshotName'." } if ($VolumeSnapshot.Source.Name) { # If the original volume still exist $VolumeName = $volumeSnapshot.Source.Name + "-"+ (Get-Random -Minimum 10000000 -Maximum 99999999) } else { # If the original volume is missing, get volume name from snapshot name # Get Alphanumeric string from snapshot $FilteredSnapshotName = $SnapshotName -replace "[^a-zA-Z0-9]" $VolumeName = $FilteredSnapshotName + "-volcopy-"+ (Get-Random -Minimum 10000000 -Maximum 99999999) } $newVol = New-PfaVolumeByPrefix -FlashArray $FlashArray -Name $VolumeName -SourceName $SnapshotName return $newVol } function Restore-PfaVmfsFromProtectionGroupSnapshot { <# .SYNOPSIS Mounts a copy of a VMFS datastore to a VMware cluster from a Pure Storage Block Store protection groupsnapshot. .DESCRIPTION Takes in a snapshot name, the corresponding Pure Storage Block Store, and a cluster. The VMFS copy will be resignatured and mounted. .INPUTS Pure Cloud Block Store connection, a VolumeSnapshot, and a cluster. .OUTPUTS Returns the new datastore. #> [CmdletBinding()] Param( [Parameter(Mandatory=$true,ValueFromPipeline=$True)] $Cluster, [Parameter(ValueFromPipeline=$True)] $FlashArray, [Parameter(Mandatory=$true)] [String]$ProtectionGroupSnapshotName, [Parameter(Mandatory=$false)] [String]$AVSCloudName, [Parameter(Mandatory=$false)] [String]$AzureSubscriptionId, [Parameter(Mandatory=$false)] [String]$AVSResourceGroup ) $NewDatastore = @() $VolumeSnapshots = Get-Pfa2VolumeSnapshot -Array $FlashArray -Filter "Name='$($ProtectionGroupSnapshotName)*'" foreach ($VolumeSnapshot in $VolumeSnapshots) { try { $NewDatastore += Restore-PfaVmfsFromVolumeSnapshot -FlashArray $FlashArray -Cluster $Cluster -VolumeSnapshotName $VolumeSnapshot.Name ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup } catch { Write-Error "Failed to restore datastore from protection group $ProtectionGroupSnapshotName using volume snapshot $($VolumeSnapshot.Name)" Write-Error $_.Exception.Message } } return $NewDatastore } function Restore-PfaVmfsFromPod { <# .SYNOPSIS Mounts a copy of a VMFS datastore to a VMware cluster from a Pure Storage Block Store protection groupsnapshot. .DESCRIPTION Takes in a snapshot name, the corresponding Pure Storage Block Store, and a cluster. The VMFS copy will be resignatured and mounted. .INPUTS Pure Cloud Block Store connection, a VolumeSnapshot, and a cluster. .OUTPUTS Returns the new datastore. #> [CmdletBinding()] Param( [Parameter(Mandatory=$true,ValueFromPipeline=$True)] $Cluster, [Parameter(ValueFromPipeline=$True)] $FlashArray, [Parameter(Mandatory=$true)] [String]$PodName, [Parameter(Mandatory=$false)] [String]$AVSCloudName, [Parameter(Mandatory=$false)] [String]$AzureSubscriptionId, [Parameter(Mandatory=$false)] [String]$AVSResourceGroup ) $NewDatastore = @() $Volumes = Get-Pfa2Volume -Array $FlashArray -Filter "Name='$($PodName)::*'" foreach ($Volume in $Volumes) { try { $NewDatastore += Restore-PfaVmfsFromVolume -FlashArray $FlashArray -Cluster $Cluster -VolumeName $Volume.Name ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup } catch { Write-Error "Failed to restore datastore from pod $PodName using volume $($Volume.Name)" Write-Error $_.Exception.Message } } return $NewDatastore } function Restore-PfaVmfsFromVolumeSnapshot { <# .SYNOPSIS Mounts a copy of a VMFS datastore to a VMware cluster from a Pure Storage Block Store snapshot. .DESCRIPTION Takes in a snapshot name, the corresponding Pure Storage Block Store, and a cluster. The VMFS copy will be resignatured and mounted. .INPUTS Pure Cloud Block Store connection, a VolumeSnapshot, and a cluster. .OUTPUTS Returns the new datastore. #> [CmdletBinding()] Param( [Parameter(Mandatory=$true,ValueFromPipeline=$True)] $Cluster, [Parameter(ValueFromPipeline=$True)] $FlashArray, [Parameter(Mandatory=$true)] [String]$VolumeSnapshotName, [Parameter(Mandatory=$false)] [String]$DatastoreName, [Parameter(Mandatory=$false)] [String]$AVSCloudName, [Parameter(Mandatory=$false)] [String]$AzureSubscriptionId, [Parameter(Mandatory=$false)] [String]$AVSResourceGroup ) $hostGroup = Get-PCBSHostGroupfromVcCluster -cluster $cluster -FlashArray $FlashArray # Create volume from the volume snapshot $VolumesForRestore = New-VolumeFromSnaspshot -FlashArray $FlashArray -SnapshotName $VolumeSnapshotName try { $NewDatastore = Restore-PfaVmfsFromVolume -FlashArray $FlashArray -Cluster $Cluster -VolumeName $VolumesForRestore.Name ` -DatastoreName $DatastoreName ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup } catch { # Clean up created volume if restore failed Write-Host "Failed to restore datastore from the volume snapshot $($VolumeSnapshotName)..." Write-Host "Cleaning up the volume $($VolumesForRestore.name) created from $($VolumeSnapshotName)..." Remove-Pfa2Connection -Array $FlashArray -HostgroupNames $hostGroup.name -VolumeNames $VolumesForRestore.name -ErrorAction SilentlyContinue Remove-Pfa2Volume -Array $FlashArray -Name $VolumesForRestore.name -Confirm:$false -ErrorAction SilentlyContinue Remove-Pfa2Volume -Array $FlashArray -Name $VolumesForRestore.name -Eradicate -Confirm:$false -ErrorAction SilentlyContinue throw } return $NewDatastore } function Restore-PfaVmfsFromVolume { <# .SYNOPSIS Mounts a copy of a VMFS datastore to a VMware cluster from a Pure Storage Block Store volume. .DESCRIPTION Takes in a snapshot name, the corresponding Pure Storage Block Store, and a cluster. The VMFS copy will be resignatured and mounted. .INPUTS Pure Cloud Block Store connection, a VolumeSnapshot, and a cluster. .OUTPUTS Returns the new datastore. #> [CmdletBinding()] Param( [Parameter(Mandatory=$true,ValueFromPipeline=$True)] $Cluster, [Parameter(ValueFromPipeline=$True)] $FlashArray, [Parameter(Mandatory=$true)] [String]$VolumeName, [Parameter(Mandatory=$false)] [String]$DatastoreName, [Parameter(Mandatory=$false)] [String]$AVSCloudName, [Parameter(Mandatory=$false)] [String]$AzureSubscriptionId, [Parameter(Mandatory=$false)] [String]$AVSResourceGroup ) $Volume = Get-Pfa2Volume -Array $FlashArray -Name $VolumeName -ErrorAction Ignore if (-not $Volume) { throw "Volume $VolumeName does not exist." } $hostGroup = Get-PCBSHostGroupfromVcCluster -cluster $cluster -FlashArray $FlashArray Write-Progress -Activity "Connecting volume" -Status "25% Complete:" -PercentComplete 25 Write-Host "Connecting volume $($Volume.Name) to host group $($hostGroup.Name)..." $Connection = Get-Pfa2Connection -Array $FlashArray -VolumeName $($Volume.Name) -HostGroupName $hostGroup.name -ErrorAction Ignore if ($Connection) { Write-Host "Volume $($Volume.Name) is already connected to host group $($hostGroup.Name). Using the existing connection..." } else { New-Pfa2Connection -Array $FlashArray -VolumeName $($Volume.Name) -HostGroupName $hostGroup.name | Out-Null } $esxi = $cluster | Get-VMHost| where-object {($_.ConnectionState -eq 'Connected')} | Select-Object -last 1 Write-Progress -Activity "Rescanning storage" -Status "50% Complete:" -PercentComplete 50 Write-Host "Rescanning HBA..." $params = @{ VMHostName = $esxi.Name; } Invoke-RunScript -CmdletName "Sync-VMHostStorage" -Parameters $params ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup $newNAA = "naa.624a9370" + $Volume.serial.toLower() Write-Progress -Activity "Restoring volume" -Status "75% Complete:" -PercentComplete 75 $params = @{ ClusterName = $Cluster.Name; DeviceNaaId = $newNAA DatastoreName = $DatastoreName } Write-Host "Restoring VMFS Datastore $($DatastoreName) from volume $($Volume.Name)..." Invoke-RunScript -CmdletName "Restore-VmfsVolume" -Parameters $params ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup $NewDatastore = Get-Datastore -ErrorAction stop | Where-Object {$_.ExtensionData.Info.Vmfs.Extent.DiskName -eq $newNAA} return $NewDatastore } function New-PfaVolumeByPrefix { Param ( [Parameter(Mandatory=$true)] [string] $Name, [ValidateRange(1073741824,68169720922112)] # 1 GB to 62 TB [Parameter(Mandatory=$false)] [UInt64] $Size, [Parameter(Mandatory=$True)] $Flasharray, [Parameter(Mandatory=$false)] [string] $SourceName ) # Create a volume with the specified name. If the name already exists in the array, use it as a prefix $maxTries = 20 $count = 0 $existingVolume = $null # Get base volume name from source volume reflected in pure snapshot object # Source volume name possibility: # regular volume snapshot: testvol # pod volume snapshot: testpod::testacvol # array replicated volume snapshot: msconnect-ff-flasharray-1:testvol $BaseName = $Name.split(":")[-1] # Truncate the name if it is too large if ($BaseName.Length -gt 53) { $BaseName = $BaseName.Substring(0,53).TrimEnd("-") } $volName = $BaseName $existingVolume = Get-Pfa2Volume -Array $Flasharray -Name $volName -ErrorAction SilentlyContinue while ($existingVolume -and $count -lt $maxTries) { $count = $count + 1 $volName = "$BaseName-$count" $existingVolume = Get-Pfa2Volume -Array $Flasharray -Name $volName -ErrorAction SilentlyContinue } if ($existingVolume) { # We exhausted the max number of tries throw "Could note create a volume based on the Name '$Name', please select a unique volume name" } Write-Host "Creating volume $volName..." if ($SourceName) { # Create a volume from a snapshot $vol = New-Pfa2Volume -Array $FlashArray -Name $volName -SourceName $SourceName -ErrorAction Stop } else { # Create a fresh volume $vol = New-Pfa2Volume -Array $FlashArray -Name $volName -Provisioned $Size -ErrorAction Stop } return $vol } function New-PfaVmfs { <# .SYNOPSIS Create a new VMFS on a new Pure Cloud Block Store volume .DESCRIPTION Creates a new VMFS on Pure Cloud Block Store and presents it to a cluster. .INPUTS FlashArray connection, a vCenter cluster, a volume size, and name. .OUTPUTS Returns a VMFS object. #> [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [VMware.VimAutomation.ViCore.Types.V1.Inventory.Cluster]$Cluster, [Parameter(Mandatory=$True)] $Flasharray, [Parameter(Mandatory=$true)] [string]$Name, [Parameter(Mandatory=$true)] $vCenterServer, [ValidateRange(1073741824,68169720922112)] # 1 GB to 62 TB [Parameter(Mandatory=$true)] [UInt64]$Size, [Parameter(Mandatory=$false)] [String]$AVSCloudName, [Parameter(Mandatory=$false)] [String]$AzureSubscriptionId, [Parameter(Mandatory=$false)] [String]$AVSResourceGroup ) Write-Progress -Activity "Creating volume" -Status "25% Complete:" -PercentComplete 25 $datastore = Get-Datastore -Server $vCenterServer -Name $Name -ErrorAction Ignore if ($datastore) { throw "Cannot create the datastore. Datastore '$Name' already exists!" } $hostGroup = Get-PCBSHostGroupfromVcCluster -cluster $cluster -FlashArray $FlashArray -ErrorAction Stop $newVol = New-PfaVolumeByPrefix -FlashArray $FlashArray -Name $Name -Size $Size -ErrorAction Stop New-Pfa2Connection -Array $FlashArray -HostGroupNames $hostGroup.Name -VolumeNames $newVol.Name | Out-Null Write-Progress -Activity "Rescanning storage" -Status "50% Complete:" -PercentComplete 50 $newNAA = "naa.624a9370" + $newVol.serial.toLower() Write-Host "Rescanning storage..." $params = @{ ClusterName = $Cluster.Name; } Invoke-RunScript -CmdletName "Sync-ClusterVMHostStorage" -Parameters $params ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup Write-Debug -Message "NAA for datastore $Name is $newNAA" Write-Progress -Activity "Creating datastore" -Status "75% Complete:" -PercentComplete 75 try { $params = @{ ClusterName = $Cluster.Name; DatastoreName = $Name; DeviceNaaId = $newNAA; Size = $Size } Invoke-RunScript -CmdletName "New-VmfsDatastore" -Parameters $params ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup } catch { # Cleanup Remove-Pfa2Connection -Array $Flasharray -HostGroupNames $hostGroup.Name -VolumeNames $newVol.Name Remove-Pfa2Volume -Array $Flasharray -Name $newVol.Name | Out-Null Remove-Pfa2Volume -Array $Flasharray -Name $newVol.Name -Eradicate -Confirm:$false| Out-Null throw } } function Set-PfaVmfsCapacity { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] $Cluster, [Parameter(Position=0,ValueFromPipeline=$True)] $Flasharray, [Parameter(Position=1,mandatory=$true,ValueFromPipeline=$True)] $Datastore, [Parameter(mandatory=$false)] [UInt64]$SizeInByte, [Parameter(Mandatory=$false)] [String]$AVSCloudName, [Parameter(Mandatory=$false)] [String]$AzureSubscriptionId, [Parameter(Mandatory=$false)] [String]$AVSResourceGroup ) Write-Progress -Activity "Resizing volume" -Status "25% Complete:" -PercentComplete 25 $pureVol = Get-PCBSVolumeFromVMFSDataStore -Flasharray $FlashArray -Datastore $Datastore $Size = Get-FriendlySize -SizeInByte $SizeInByte $CurrentSize = Get-FriendlySize -SizeInByte $pureVol.Provisioned if ($SizeInByte -lt $pureVol.Provisioned) { throw "The new specified size '$Size' is not larger than the current size '$CurrentSize'. ESXi does not permit VMFS volumes to be shrunk--please specify a size larger than the existing." } elseif ($SizeInByte -eq $pureVol.Provisioned) { # Resize operation might not have been completed in the past, try again # Check if the datastore was already resizes $CapacityDiff = ($SizeInByte - $Datastore.CapacityGB * 1GB) / 1GB if ($CapacityDiff -lt 0) { throw "Cannot resize datastore to lower capacity than $($Datastore.CapacityGB)GB" } if ($CapacityDiff -le 1) { # Difference is negligible. Might be due to VMWare reserved capacity Write-Warning "Datastore '$Datastore.Name' is already set to requested capacity." return } Write-Warning "Volume $($pureVol.Name) is already set at the requested capacity. Refreshing datastore object on AVS.." } else { Write-Host "Increasing the size of the volume $($pureVol.Name) to $Size on Pure Cloud Block Store..." # FlashArray only accept byte that is multiple of 512. If not, we round up by 512 $SizeInByte = [math]::ceiling($SizeInByte/512) * 512 Update-Pfa2Volume -Array $FlashArray -Name $pureVol.Name -Provisioned $SizeInByte | Out-Null } Write-Progress -Activity "Resizing datastore" -Status "50% Complete:" -PercentComplete 50 $params = @{ ClusterName = $Cluster.Name; DeviceNaaId = $Datastore.ExtensionData.Info.Vmfs.Extent.DiskName } Invoke-RunScript -CmdletName "Resize-VmfsVolume" -Parameters $params ` -AVSCloudName $AVSCloudName -AzureSubscriptionId $AzureSubscriptionId -AVSResourceGroup $AVSResourceGroup } function Get-FriendlySize { [CmdletBinding()] Param( [Parameter(mandatory=$false)] [UInt64]$SizeInByte ) $SizeInGB = $SizeInByte / 1024 / 1024 / 1024 if ($SizeInGB -ge 1024) { $SizeInTB = $SizeInGB/1024 return "$([math]::Round($SizeInTB, 2)) TB" } else { return "$([math]::Round($SizeInGB, 2)) GB" } } # SIG # Begin signature block # MIIjUgYJKoZIhvcNAQcCoIIjQzCCIz8CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUNiodRj1+AVXTFpsa/H+/DfWN # GoCggh14MIIFMDCCBBigAwIBAgIQBAkYG1/Vu2Z1U0O1b5VQCDANBgkqhkiG9w0B # AQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk # IElEIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAwWhcNMjgxMDIyMTIwMDAwWjByMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQg # Q29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA # +NOzHH8OEa9ndwfTCzFJGc/Q+0WZsTrbRPV/5aid2zLXcep2nQUut4/6kkPApfmJ # 1DcZ17aq8JyGpdglrA55KDp+6dFn08b7KSfH03sjlOSRI5aQd4L5oYQjZhJUM1B0 # sSgmuyRpwsJS8hRniolF1C2ho+mILCCVrhxKhwjfDPXiTWAYvqrEsq5wMWYzcT6s # cKKrzn/pfMuSoeU7MRzP6vIK5Fe7SrXpdOYr/mzLfnQ5Ng2Q7+S1TqSp6moKq4Tz # rGdOtcT3jNEgJSPrCGQ+UpbB8g8S9MWOD8Gi6CxR93O8vYWxYoNzQYIH5DiLanMg # 0A9kczyen6Yzqf0Z3yWT0QIDAQABo4IBzTCCAckwEgYDVR0TAQH/BAgwBgEB/wIB # ADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwMweQYIKwYBBQUH # AQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYI # KwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz # c3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0 # LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaG # NGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RD # QS5jcmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0 # dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZIAYb9bAMwHQYDVR0OBBYE # FFrEuXsqCqOl6nEDwGD5LfZldQ5YMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6en # IZ3zbcgPMA0GCSqGSIb3DQEBCwUAA4IBAQA+7A1aJLPzItEVyCx8JSl2qB1dHC06 # GsTvMGHXfgtg/cM9D8Svi/3vKt8gVTew4fbRknUPUbRupY5a4l4kgU4QpO4/cY5j # DhNLrddfRHnzNhQGivecRk5c/5CxGwcOkRX7uq+1UcKNJK4kxscnKqEpKBo6cSgC # PC6Ro8AlEeKcFEehemhor5unXCBc2XGxDI+7qPjFEmifz0DLQESlE/DmZAwlCEIy # sjaKJAL+L3J+HNdJRZboWR3p+nRka7LrZkPas7CM1ekN3fYBIM6ZMWM9CBoYs4Gb # T8aTEAb8B4H6i9r5gkn3Ym6hU/oSlBiFLpKR6mhsRDKyZqHnGKSaZFHvMIIFNzCC # BB+gAwIBAgIQC4jZOitkx57ksuMgsWXX0jANBgkqhkiG9w0BAQsFADByMQswCQYD # VQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGln # aWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29k # ZSBTaWduaW5nIENBMB4XDTIwMDczMDAwMDAwMFoXDTIzMTAwNDEyMDAwMFowdDEL # MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50 # YWluIFZpZXcxGzAZBgNVBAoTElB1cmUgU3RvcmFnZSwgSW5jLjEbMBkGA1UEAxMS # UHVyZSBTdG9yYWdlLCBJbmMuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC # AQEA6nefE6+A0nNMY82xtkQb+akwI0oxLqEbRY65bE4re+CVQV2xP89/7FIAXooq # jxNOvrtWicWTGOZjBdAFEXXAUEyu9CkWFOXGLV3/QkcEfY3e3Z3jypa6h1EznSEp # 3wSQEIVbigi6jR2s7NDnDoSDAKnzcGcSZ8Nz7akXFrN8PAmg3gy8a/rwm2Ko7ClR # ZUHj1C/OMPXUqiN0Q4FyAsaeFmvg2PX2twxo192WRdNro1dkKNfmDvym2ss6MXcq # gFEjBcZtHDv3e/i0BjT24Jm1C27IVYZzVf28dqmVfPo7l8bLEHsVKgrRf0VzS2wI # R08gXiMrohf9tv3AbvtPk7ZaawIDAQABo4IBxTCCAcEwHwYDVR0jBBgwFoAUWsS5 # eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYEFJOwFn7S4Lj6QdNnH6tpm3FMFWJI # MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBu # MDWgM6Axhi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNz # LWcxLmNybDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNz # dXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAwEwKjAoBggrBgEF # BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYQG # CCsGAQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu # Y29tME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln # aUNlcnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIw # ADANBgkqhkiG9w0BAQsFAAOCAQEAMVAa7mXxhBHf0dTzf6LKDncN8KnzB59KBvd0 # KvXZc6FoLHGi2Wg6XBSP+9mdDMMYOkohqstSk7RD+reT8xiptrIkSMcVcTog1Z3e # JjYTK8B7QsSpuu2lo0RWA5rdvqMJ+lVzbbjteTq+uicP4T/EDwv2q+iPAgpXQD8y # r084ExDWJtMfhvy0cxh555xx88rvFWOhJnXYiFtjaO9dp7f2TnZRJ44rmB98jc9E # BR/8GLOi/BhyPiiU4nBv8JIHVP1E5zIt8/9PhfpenmiWBbuuP0YLnzrqRhswtJaq # jJirYNLYojmINrbvdcpEKGK1AitsnuOjFadLI7bc696Y35lUATCCBY0wggR1oAMC # AQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZIhvcNAQEMBQAwZTELMAkGA1UEBhMC # VVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0 # LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTIy # MDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVowYjELMAkGA1UEBhMCVVMxFTATBgNV # BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8G # A1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MIICIjANBgkqhkiG9w0BAQEF # AAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjwwIjBpM+zCpyUuySE98orYWcLhKac9 # WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J58soR0uRf1gU8Ug9SH8aeFaV+vp+p # VxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMHhOZ0O21x4i0MG+4g1ckgHWMpLc7s # Xk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6Zu53yEioZldXn1RYjgwrt0+nMNlW # 7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQecN4x7axxLVqGDgDEI3Y1DekLgV9 # iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4bA3VdeGbZOjFEmjNAvwjXWkmkwuap # oGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9WV1CdoeJl2l6SPDgohIbZpp0yt5L # HucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCUtNJhbesz2cXfSwQAzH0clcOP9yGy # shG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvoZKYz0YkH4b235kOkGLimdwHhD5QM # IR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/JvNNBERJb5RBQ6zHFynIWIgnffEx1 # P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCPorF+CiaZ9eRpL5gdLfXZqbId5RsC # AwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFOzX44LScV1k # TN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA4G # A1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6 # Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMu # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDBFBgNVHR8E # PjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1 # cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQwF # AAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cHvZqsoYcs7IVeqRq7IviHGmlUIu2k # iHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8UgPITtAq3votVs/59PesMHqai7Je # 1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTnf+hZqPC/Lwum6fI0POz3A8eHqNJM # QBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxUjG/voVA9/HYJaISfb8rbII01YBwC # A8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8jLfR+cWojayL/ErhULSd+2DrZ8LaH # lv1b0VysGMNNn3O3AamfV6peKOK5lDCCBq4wggSWoAMCAQICEAc2N7ckVHzYR6z9 # KGYqXlswDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERp # Z2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMY # RGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTIyMDMyMzAwMDAwMFoXDTM3MDMy # MjIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu # MTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRp # bWVTdGFtcGluZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMaG # NQZJs8E9cklRVcclA8TykTepl1Gh1tKD0Z5Mom2gsMyD+Vr2EaFEFUJfpIjzaPp9 # 85yJC3+dH54PMx9QEwsmc5Zt+FeoAn39Q7SE2hHxc7Gz7iuAhIoiGN/r2j3EF3+r # GSs+QtxnjupRPfDWVtTnKC3r07G1decfBmWNlCnT2exp39mQh0YAe9tEQYncfGpX # evA3eZ9drMvohGS0UvJ2R/dhgxndX7RUCyFobjchu0CsX7LeSn3O9TkSZ+8OpWNs # 5KbFHc02DVzV5huowWR0QKfAcsW6Th+xtVhNef7Xj3OTrCw54qVI1vCwMROpVymW # Jy71h6aPTnYVVSZwmCZ/oBpHIEPjQ2OAe3VuJyWQmDo4EbP29p7mO1vsgd4iFNmC # KseSv6De4z6ic/rnH1pslPJSlRErWHRAKKtzQ87fSqEcazjFKfPKqpZzQmiftkaz # nTqj1QPgv/CiPMpC3BhIfxQ0z9JMq++bPf4OuGQq+nUoJEHtQr8FnGZJUlD0UfM2 # SU2LINIsVzV5K6jzRWC8I41Y99xh3pP+OcD5sjClTNfpmEpYPtMDiP6zj9NeS3YS # UZPJjAw7W4oiqMEmCPkUEBIDfV8ju2TjY+Cm4T72wnSyPx4JduyrXUZ14mCjWAkB # KAAOhFTuzuldyF4wEr1GnrXTdrnSDmuZDNIztM2xAgMBAAGjggFdMIIBWTASBgNV # HRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS6FtltTYUvcyl2mi91jGogj57IbzAf # BgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYw # EwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzAB # hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9j # YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMG # A1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy # dFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG # /WwHATANBgkqhkiG9w0BAQsFAAOCAgEAfVmOwJO2b5ipRCIBfmbW2CFC4bAYLhBN # E88wU86/GPvHUF3iSyn7cIoNqilp/GnBzx0H6T5gyNgL5Vxb122H+oQgJTQxZ822 # EpZvxFBMYh0MCIKoFr2pVs8Vc40BIiXOlWk/R3f7cnQU1/+rT4osequFzUNf7WC2 # qk+RZp4snuCKrOX9jLxkJodskr2dfNBwCnzvqLx1T7pa96kQsl3p/yhUifDVinF2 # ZdrM8HKjI/rAJ4JErpknG6skHibBt94q6/aesXmZgaNWhqsKRcnfxI2g55j7+6ad # cq/Ex8HBanHZxhOACcS2n82HhyS7T6NJuXdmkfFynOlLAlKnN36TU6w7HQhJD5TN # OXrd/yVjmScsPT9rp/Fmw0HNT7ZAmyEhQNC3EyTN3B14OuSereU0cZLXJmvkOHOr # pgFPvT87eK1MrfvElXvtCl8zOYdBeHo46Zzh3SP9HSjTx/no8Zhf+yvYfvJGnXUs # HicsJttvFXseGYs2uJPU5vIXmVnKcPA3v5gA3yAWTyf7YGcWoWa63VXAOimGsJig # K+2VQbc61RWYMbRiCQ8KvYHZE/6/pNHzV9m8BPqC3jLfBInwAM1dwvnQI38AC+R2 # AibZ8GV2QqYphwlHK+Z/GqSFD/yYlvZVVCsfgPrA8g4r5db7qS9EFUrnEw4d2zc4 # GqEr9u3WfPwwggbCMIIEqqADAgECAhAFRK/zlJ0IOaa/2z9f5WEWMA0GCSqGSIb3 # DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7 # MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1l # U3RhbXBpbmcgQ0EwHhcNMjMwNzE0MDAwMDAwWhcNMzQxMDEzMjM1OTU5WjBIMQsw # CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xIDAeBgNVBAMTF0Rp # Z2lDZXJ0IFRpbWVzdGFtcCAyMDIzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAo1NFhx2DjlusPlSzI+DPn9fl0uddoQ4J3C9Io5d6OyqcZ9xiFVjBqZMR # p82qsmrdECmKHmJjadNYnDVxvzqX65RQjxwg6seaOy+WZuNp52n+W8PWKyAcwZeU # tKVQgfLPywemMGjKg0La/H8JJJSkghraarrYO8pd3hkYhftF6g1hbJ3+cV7EBpo8 # 8MUueQ8bZlLjyNY+X9pD04T10Mf2SC1eRXWWdf7dEKEbg8G45lKVtUfXeCk5a+B4 # WZfjRCtK1ZXO7wgX6oJkTf8j48qG7rSkIWRw69XloNpjsy7pBe6q9iT1HbybHLK3 # X9/w7nZ9MZllR1WdSiQvrCuXvp/k/XtzPjLuUjT71Lvr1KAsNJvj3m5kGQc3AZEP # HLVRzapMZoOIaGK7vEEbeBlt5NkP4FhB+9ixLOFRr7StFQYU6mIIE9NpHnxkTZ0P # 387RXoyqq1AVybPKvNfEO2hEo6U7Qv1zfe7dCv95NBB+plwKWEwAPoVpdceDZNZ1 # zY8SdlalJPrXxGshuugfNJgvOuprAbD3+yqG7HtSOKmYCaFxsmxxrz64b5bV4RAT # /mFHCoz+8LbH1cfebCTwv0KCyqBxPZySkwS0aXAnDU+3tTbRyV8IpHCj7ArxES5k # 4MsiK8rxKBMhSVF+BmbTO77665E42FEHypS34lCh8zrTioPLQHsCAwEAAaOCAYsw # ggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoG # CCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAfBgNV # HSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4EFgQUpbbvE+fvzdBk # odVWqWUxo97V40kwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybDMuZGlnaWNl # cnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGlu # Z0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v # Y3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDovL2NhY2VydHMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFt # cGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAgRrW3qCptZgXvHCNT4o8aJzY # Jf/LLOTN6l0ikuyMIgKpuM+AqNnn48XtJoKKcS8Y3U623mzX4WCcK+3tPUiOuGu6 # fF29wmE3aEl3o+uQqhLXJ4Xzjh6S2sJAOJ9dyKAuJXglnSoFeoQpmLZXeY/bJlYr # sPOnvTcM2Jh2T1a5UsK2nTipgedtQVyMadG5K8TGe8+c+njikxp2oml101DkRBK+ # IA2eqUTQ+OVJdwhaIcW0z5iVGlS6ubzBaRm6zxbygzc0brBBJt3eWpdPM43UjXd9 # dUWhpVgmagNF3tlQtVCMr1a9TMXhRsUo063nQwBw3syYnhmJA+rUkTfvTVLzyWAh # xFZH7doRS4wyw4jmWOK22z75X7BC1o/jF5HRqsBV44a/rCcsQdCaM0qoNtS5cpZ+ # l3k4SF/Kwtw9Mt911jZnWon49qfH5U81PAC9vpwqbHkB3NpE5jreODsHXjlY9Hxz # MVWggBHLFAx+rrz+pOt5Zapo1iLKO+uagjVXKBbLafIymrLS2Dq4sUaGa7oX/cR3 # bBVsrquvczroSUa31X/MtjjA2Owc9bahuEMs305MfR5ocMB3CtQC4Fxguyj/OOVS # WtasFyIjTvTs0xf7UGv/B3cfcZdEQcm4RtNsMnxYL2dHZeUbc7aZ+WssBkbvQR7w # 8F/g29mtkIBEr4AQQYoxggVEMIIFQAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMG # A1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEw # LwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENB # AhALiNk6K2THnuSy4yCxZdfSMAkGBSsOAwIaBQCgcDAQBgorBgEEAYI3AgEMMQIw # ADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYK # KwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUYveQ+FISj56tnjUpe8lhJOsKc6Aw # DQYJKoZIhvcNAQEBBQAEggEAmj6hzBRr7HWeIcgaBa4KqmkcHd9kcwm0Sz2gjZQH # paC/zA2zoJ+e3XW+mMR2+4VXi4d7yaJCKPP+5leNaT5kc8dGB3bUb6XpbUkCsLD2 # RxWGlc+riKn2U2zoI/ttToZKoNI9Vm/4lwAASSf3UJYGrWbZP+vGBK37q/zCa9Vj # J8jmZg+potPCJysfTlpLskJ1v6cg71fKv1+F8pzriDuQ8k9fkF51gRAc/4ujJcKo # VFu19RObCUbrWRAMsTmJ8nBlxCmDbodElJakZu91d4QCbf/xExjIlN/vi3pGVV/9 # +gqM9vLjBfANA0JHknTV2Be92av3eqzbG7dA7bscUaTb6KGCAyAwggMcBgkqhkiG # 9w0BCQYxggMNMIIDCQIBATB3MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp # Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2 # IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0ECEAVEr/OUnQg5pr/bP1/lYRYwDQYJYIZI # AWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJ # BTEPFw0yMzA5MTkwMDEyNDJaMC8GCSqGSIb3DQEJBDEiBCAlNmf7JgsR5FcydLRt # RSr4C+vhYdHfpRRNr6ksfXEb8zANBgkqhkiG9w0BAQEFAASCAgBXk/AO0YSDOZfV # igBgZh3qAtjJZ4oieIvvl/CYKwaTZy/8pJDxSwwluc+jB8g91E4Vdga9njQ+MSht # 8epKhdn6/NvzJw16lkYaUWUmLn7Nq9I7rS0p6t//ov7zUXUSuOCyo8lixMahKgpR # u+tzUJTd3RbAwxYcbEdw0bgzdpUBHVbjEU86zVuNN0jWvwEwxRsgFyvUlHxH0XBG # kT5ZyBYx9vlrua97q63FuioyYYAYMN3FzOK0QfKFlIgzZ+ZFqlNPpdah7/7fP1kb # SNkcNNSkdhL8XfBQtyFN2og4+u4vaGlO/gxer2FTyJjEDt9aCQE9gMa0Yyw/cIaa # xCprqgDaOZkIJ1NbXCAB8eNok4nYbO0dfU/NkNr3r9l96HnO8SoH1tAno4qWb6+J # EjKaHYevDF2VL0c6yX3Fesdoj94fanfPWq2OidG7MvTTVLhBzNlzl2jBP5uGNlRL # tVYPj/omJTLGyD0E2cQtk7RI1PMrIQ9nWFo0rdV67rq9Gp2ymUKMR6UGr4hhBiYA # p3YpGaZrjqo7cAVP2YgLNTTMxMrzYuz1b3nDAuSFjj3sjI0TLbPvJrDiHlINvnsa # gpyVlSzTI5g16Ey32T4Yf5JspBShIOtsaaWZ5qOC/LZXC7JToouBRyErxxzWwTzy # q5Ex7oKrwJAqw8FLJcmBzg8aICi2dw== # SIG # End signature block |