PureStorage.CBS.AVS.VMFS.ps1

function Get-PfaVolumeFromVMFSDataStore {
    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]$AVSResourceGroup
    )


    $PureVol = Get-PfaVolumeFromVMFSDataStore -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 -RunCommandName "Dismount-VmfsDatastore" -RunCommandModule "Microsoft.AVS.VMFS" -Parameters $params `
        -AVSCloudName $AVSCloudName -AVSResourceGroup $AVSResourceGroup

    Write-Progress -Activity "Removing volume" -Status "50% Complete:" -PercentComplete 50
    # Remove volume from array hostgroup if available
    $FaHg = Get-PfaHostGroupfromVcCluster -Flasharray $Flasharray -Cluster $Cluster
    $HgConnection = Get-Pfa2Connection -Array $FlashArray -VolumeNames $PureVol.Name -HostGroupNames $FaHg.Name -ErrorAction SilentlyContinue
    if ($HgConnection) {
        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 (-not $Connections) {
        Write-Host "Destroying volume $($PureVol.Name)..."
        Remove-Pfa2Volume -Array $FlashArray -Name $PureVol.Name -Confirm:$false
    }

    Write-Progress -Activity "Rescanning storage" -Status "75% Complete:" -PercentComplete 75
    $params = @{
        ClusterName = $Cluster.Name;
    }
    Invoke-RunScript -RunCommandName "Sync-ClusterVMHostStorage" -RunCommandModule "Microsoft.AVS.VMFS" -Parameters $params `
        -AVSCloudName $AVSCloudName -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]$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 -AVSResourceGroup $AVSResourceGroup
        } catch {
            Write-Error "Failed to restore datastore from protection group $ProtectionGroupSnapshotName using volume snapshot $($VolumeSnapshot.Name)"
            Write-Error $_.Exception.Message
        }
    }

    if (-not $NewDatastore) {
        throw "No datastore was restored from protection group snapshot $ProtectionGroupSnapshotName."
    }

    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]$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 -AVSResourceGroup $AVSResourceGroup
        } catch {
            Write-Error "Failed to restore datastore from pod $PodName using volume $($Volume.Name)"
            Write-Error $_.Exception.Message
        }
    }

    if (-not $NewDatastore) {
        throw "No datastore was restored from pod $PodName."
    }

    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]$AVSResourceGroup
    )

    $hostGroup = Get-PfaHostGroupfromVcCluster -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 -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]$AVSResourceGroup
    )

    $Volume = Get-Pfa2Volume -Array $FlashArray -Name $VolumeName -ErrorAction Ignore
    if (-not $Volume) {
        throw "Volume $VolumeName does not exist."
    }

    $newNAA =  "naa.624a9370" + $Volume.serial.toLower()
    $Datastore = Get-Datastore -ErrorAction stop | Where-Object {$_.ExtensionData.Info.Vmfs.Extent.DiskName -eq $newNAA}
    if ($Datastore) {
        throw "Datastore $($Datastore.Name) is using the volume $VolumeName. Please use a different volume. You can manually create a new volume copy from volume $VolumeName and restore the datastore from the new volume."
    }

    $hostGroup = Get-PfaHostGroupfromVcCluster -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 -RunCommandName "Sync-VMHostStorage" -RunCommandModule "Microsoft.AVS.VMFS" -Parameters $params `
        -AVSCloudName $AVSCloudName -AVSResourceGroup $AVSResourceGroup

    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 -RunCommandName  "Restore-VmfsVolume" -RunCommandModule "Microsoft.AVS.VMFS" -Parameters $params `
        -AVSCloudName $AVSCloudName -AVSResourceGroup $AVSResourceGroup

    $NewDatastore = Get-Datastore -ErrorAction stop | Where-Object {$_.ExtensionData.Info.Vmfs.Extent.DiskName -eq $newNAA}

    if (-not $NewDatastore) {
        throw "Failed to restore datastore from volume $($Volume.Name)."
    }

    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]$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-PfaHostGroupfromVcCluster -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 -RunCommandName "Sync-ClusterVMHostStorage" -RunCommandModule "Microsoft.AVS.VMFS" -Parameters $params `
        -AVSCloudName $AVSCloudName -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 -RunCommandName  "New-VmfsDatastore" -RunCommandModule "Microsoft.AVS.VMFS" -Parameters $params `
            -AVSCloudName $AVSCloudName -AVSResourceGroup $AVSResourceGroup
    }
    catch {
        # Cleanup
        Remove-Pfa2Connection -Array $Flasharray -HostGroupNames $hostGroup.Name -VolumeNames $newVol.Name
        Remove-Pfa2Volume -Array $Flasharray -Name $newVol.Name -Confirm:$false | 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]$AVSResourceGroup
    )

    Write-Progress -Activity "Resizing volume" -Status "25% Complete:" -PercentComplete 25


    $pureVol = Get-PfaVolumeFromVMFSDataStore -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 -RunCommandName "Resize-VmfsVolume" -RunCommandModule "Microsoft.AVS.VMFS" -Parameters $params `
        -AVSCloudName $AVSCloudName -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
# MIIn+AYJKoZIhvcNAQcCoIIn6TCCJ+UCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU8zWSs12FMNyS3fnRy87OKgx3
# ga+ggiEoMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B
# 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
# FFQ7QsY+9wjpprWCkqrWuhKLCco2MA0GCSqGSIb3DQEBAQUABIICAETLyO3O77yy
# sXN/G3JGQNuv8daoUwVHYZA0SNE2ZMCi+yk7YOW7/XNdwHoVGuXc3Uy+YzVZcnF4
# FNhL7CQq0oKS9aeCBW4bhcTH1pusPLTAtBXz+j5hrbwjLOfBK/f7rR5DdD+HICFg
# goJJFsbrJviHYDqmk6ZB9OWlVmMH8pfN+s+kcz0Mb7Fmucb4VKpsRlzCRAijaUmO
# xRrEMSqgR3UmRuzo/V/95CEAqwZ5e+rPl0IOcQfbFKmW7c5G1DlXp4Fj1UkYqHzh
# 7ty5LDEth27L3Fbxao0UflaYBxV7Alzu0+m+pXi4An6a5o8XGb9tcie4pwi2uRuO
# PLBilUSWCNsebZFRtPX17uCClqr8aR0DVsn4Zwv51z0fb9rxGANFbfi9jR3Zv5jU
# WtaMlu1qB0vglkykrQV2GkGdyWw8SO9l6VulkAnrjG7I5154ixVgUUkxO+yqt/r3
# nlRDI5kJlQuHYw28Ndrz3U6Np7huWSnjsoIpI8kWsg4Lg3Qx1P3Lc+Y4hN1l07Cn
# Ah8YnwIWZGOLy0PQ8thYXDc0RhV2dnEhlugZACLD+B2CrK5aI0eg371tcqXBlugh
# O3/M/JqAfN6fNyhWCXblvcpSVYyp4gk0cpV/Ot7el+Orzh+IMseacR4XtiVqsQsU
# mezhNUVLWVXe0vTounEQYlXKXuabIaMnoYIDIDCCAxwGCSqGSIb3DQEJBjGCAw0w
# ggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu
# MTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRp
# bWVTdGFtcGluZyBDQQIQBUSv85SdCDmmv9s/X+VhFjANBglghkgBZQMEAgEFAKBp
# MBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI0MDEy
# MzE3MjE1NlowLwYJKoZIhvcNAQkEMSIEIM7miGT8KzHd/lrBE4HW7zF8AkyZIOi2
# u8s+3msFFTfkMA0GCSqGSIb3DQEBAQUABIICAAiFuSeqQuwSzIXpRP+LJ2YKG/8c
# XIjZQ7rJ/TlndOwBs+kWqGSDrwCyPgIDwVaHrvDjA5DighRc4dPtfGs+OK/hW2j2
# oatVZ5F9xSLTCGMV3kiDrFUPCDCKpXfCa3WM7oE5rdzQPKPRVwOopVldQW54s9dB
# D0XN1SV7Asf7mu2eeP8xvIfBeyRmEhGA8DFrzi114GwIok2Q7ata5p3PPxwsHvLx
# T3xuzg5hoz4WPFyegPItRuZImJ4RKt2C4Em+kE2NTHAHyTCifLfaEpm3dK9kXhEv
# y74MD6xz7dbtIgdUwAgQR/joCQjwOEbthfMYdkPRELJVxxq5I5rDRMqfbO751L+a
# JOIdOkL8NlDrn/e2nbaiRD/tLUsanpZsrVmBdEAn5/GVKElqxVKEwzyAC01DXGvJ
# 7C1h6S9Q2LcdIE1etnEAq5PS5k7vBf0vDfSn2yA5lS+zYf6/fSJUgXbF7NgrtR7v
# +keU3VDxd+m+v1htcOJixKrfROYsIp662Oqfmx58O76rNwkPmONUTapZNWrWTUTT
# zDGdOc5mvipzUfOW6+KQ+CounKK1Df7KVSOp1UXREW0daD+TPqcr80CjxVUcJCL5
# pu0yLYFM7prCb/F/VQB3i7HloTkOcna9nRabw7bfY+SmlO/WFIkBBrMH0Evy9itU
# whxwEnNSsEQ4bbd/
# SIG # End signature block