Utils.VVOLS.ps1


function Copy-PfaSnapshotToNewVvolVmdk {
    <#
    .SYNOPSIS
      Takes a snapshot and creates a new vVol virtual disk from it.
    .DESCRIPTION
      Takes a snapshot and creates a new vVol virtual disk from it.
    .INPUTS
      FlashArray connection information, a datastore, target VM, and a source snapshot
    .OUTPUTS
      Returns the hard disk.
    .NOTES
      Ported from: PureStorage.FlashArray.VMware.VVol
      Version: 2.0
      Author: Cody Hosterman https://codyhosterman.com
      Creation Date: 08/26/2020
      Purpose/Change: Core support
    .EXAMPLE
      PS C:\ New-PfaConnection -endpoint flasharray-m20-2 -credentials (get-credential) -DefaultRestClient
      PS C:\ $vm = get-vm testvm01
      PS C:\ Copy-PfaSnapshotToNewVvolVmdk -targetVM $vm -snapshotName "vvol-testvm01-F90FC8A6-vg/Data-1fe45e4a.1"

      Takes a snapshot and overwrites a vVol VMDK on the same array

    *******Disclaimer:******************************************************
    This scripts are offered "as is" with no warranty. While this
    scripts is tested and working in my environment, it is recommended that you test
    this script in a test lab before using in a production environment. Everyone can
    use the scripts/commands provided here without any written permission but I
    will not be liable for any damage or loss to the system.
    ************************************************************************
    #>


    [CmdletBinding(DefaultParametersetname="FlashArray")]
    Param(
            [Parameter(Position=0,mandatory=$true)]
            [string]$SnapshotName,

            [Parameter(Position=1,mandatory=$True,ValueFromPipeline=$True)]
            [VMware.VimAutomation.ViCore.Types.V1.Inventory.VirtualMachine]$TargetVm,

            [Parameter(ParameterSetName='FlashArray',Position=2,ValueFromPipeline=$True)]
            [PureStorage.FlashArray.Rest.Rest2Api]$restClient,
            
            [Parameter(Position=3,mandatory=$false)]
            [string]$DatastoreName
    )

    if ($null -eq $restClient)
    {
        ThrowErrorCode -ErrorCode $ErrorCode_MissingRestClient
    }

    $arrayID = (Get-Pfa2Array -Array $RestClient).Id
    $datastore = $targetVm| Get-VMHost | Get-Datastore |where-object {$_.Type -eq "VVOL"} |Where-Object {$_.ExtensionData.info.vvolDS.storageArray[0].uuid.substring(16) -eq $arrayID} 

    if($DatastoreName){
      $datastore = $datastore | Where-Object {$_.Name -eq $DatastoreName}
    }

    # if not datastore/or multiple found throw error asking user to specify datastore
    if($datastore.count -ne 1){
      ThrowErrorCode -ErrorCode $ErrorCode_FailedToDetermineDatastore
    }

    $snapshotSize = (Get-Pfa2VolumeSnapshot -Array $RestClient -Name $SnapshotName).Space.TotalProvisioned
    $newHardDisk = New-HardDisk -Datastore $datastore -CapacityKB ($snapshotSize / 1024 ) -VM $targetVm

    if(-not $newHardDisk){
      ThrowErrorCode -ErrorCode $ErrorCode_NewHardDiskError
    }

    $newVvolUuid = Get-PfaVvolUuidFromVmdk -vmdk $newHardDisk
    $newFaVolume = get-PfaVolumeNameFromVvolUuid -restClient $restClient -vvolUUID $newVvolUuid
    $EV = $null
    $FAVolume = New-Pfa2Volume -Array $RestClient -Name $newFaVolume -SourceName $snapshotName -Overwrite $true -ErrorAction SilentlyContinue -ErrorVariable EV
    if ($EV) {
        ThrowErrorCode -ErrorCode $ErrorCode_VolumeCreateFailed -innerException $EV.Exception
    }
    return $newHardDisk,$FAVolume
}

function Get-PfaVolumeNameFromVvolUuid{
  <#
  .SYNOPSIS
    Connects to vCenter and FlashArray to return the FA volume that is a vVol virtual disk.
  .DESCRIPTION
    Takes in a vVol UUID to identify what volume it is on the FlashArray. If a vVol UUID is not specified it will ask you for a VM and then a VMDK and will find the UUID for you.
  .INPUTS
    FlashArray connection(s) and vVol UUID.
  .OUTPUTS
    Returns volume name.
  .NOTES
    Ported from: PureStorage.FlashArray.VMware.VVol
    Version: 2.1
    Author: Cody Hosterman https://codyhosterman.com
    Creation Date: 12/24/2019
    Purpose/Change: Updated for new connection mgmt
  .EXAMPLE
    PS C:\ New-PfaConnection -endpoint flasharray-m20-2 -credentials (get-credential) -DefaultRestClient
    PS C:\ Get-PfaVolumeNameFromVvolUuid -vvolUUID (get-vm myVM | get-harddisk | Get-PfaVvolUuidFromVmdk)

    Pass in one vVol UUID and return the corresponding FlashArray volume name

  *******Disclaimer:******************************************************
  This scripts are offered "as is" with no warranty. While this
  scripts is tested and working in my environment, it is recommended that you test
  this script in a test lab before using in a production environment. Everyone can
  use the scripts/commands provided here without any written permission but I
  will not be liable for any damage or loss to the system.
  ************************************************************************
  #>


  #Import PowerCLI. Requires PowerCLI version 6.3 or later. Will fail here if PowerCLI cannot be installed
  #Will try to install PowerCLI with PowerShellGet if PowerCLI is not present.

  [CmdletBinding()]
  Param(
          [Parameter(Position=0,mandatory=$true)]
          [string]$VvolUUID,

          [Parameter(Position=1,mandatory=$true)]
          [PureStorage.FlashArray.Rest.Rest2Api]$RestClient
  )
  $ErrorActionPreference = "stop"

  $volumeTag = get-pfa2volumeTag -Array $RestClient -Namespaces "vasa-integration.purestorage.com" | Where-Object {$_.Key -eq "PURE_VVOL_ID" -and $_.value -eq $VvolUUID}
  $volumeName = $volumeTag.Resource.Name

  if (-not $volumeName)
  {
    ThrowErrorCode -ErrorCode $ErrorCode_VVOLNotFound
  }

  return $volumeName
}

function Get-PfaVvolUuidFromVmdk {
    <#
    .SYNOPSIS
      Gets the vVol UUID of a virtual disk
    .DESCRIPTION
      Takes in a virtual disk object
    .INPUTS
      Virtual disk object (get-harddisk).
    .OUTPUTS
      Returns the vVol UUID.
    .NOTES
      Ported from: PureStorage.FlashArray.VMware.VVol
      Version: 2.0
      Author: Cody Hosterman https://codyhosterman.com
      Creation Date: 08/26/2020
      Purpose/Change: Core support
    .EXAMPLE
      PS C:\ New-PfaConnection -endpoint flasharray-m20-2 -credentials (get-credential) -DefaultRestClient
      PS C:\ get-vm myVM | get-harddisk | Get-PfaVvolUuidFromVmdk

      Pass in one or more vVol hard disks and return the corresponding vVol UUIDs

    *******Disclaimer:******************************************************
    This scripts are offered "as is" with no warranty. While this
    scripts is tested and working in my environment, it is recommended that you test
    this script in a test lab before using in a production environment. Everyone can
    use the scripts/commands provided here without any written permission but I
    will not be liable for any damage or loss to the system.
    ************************************************************************
    #>


    [CmdletBinding()]
    Param(
            [Parameter(Position=0,mandatory=$True,ValueFromPipeline=$True)]
            [VMware.VimAutomation.ViCore.Types.V1.VirtualDevice.HardDisk[]]$Vmdk
    )
    Begin {
        $allUuids = @()
    }
    Process {
        foreach ($vmdkDisk in $vmdk)
        {
          if ($vmdkDisk.ExtensionData.Backing.backingObjectId -eq "")
          {
              ThrowErrorCode -ErrorCode $ErrorCode_NotAVVOL
          }
          if ((($vmdkDisk |Get-Datastore).ExtensionData.Info.vvolDS.storageArray.vendorId) -ne "PURE") {
            ThrowErrorCode -ErrorCode $ErrorCode_NotAPureVVOL
          }
          $allUuids += $vmdkDisk.ExtensionData.Backing.backingObjectId
        }
    }
    End {
        return $allUuids
    }

}



# SIG # Begin signature block
# MIIn+AYJKoZIhvcNAQcCoIIn6TCCJ+UCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUvTnOgngIEi17K6B7oA3aApH2
# enOggiEoMIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0B
# 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
# FPeRVpekHSKhZFMiFFiyRljX89kFMA0GCSqGSIb3DQEBAQUABIICAFflNA+7EtT5
# r7iPYRlI3F913ofbIypKhT4W7qQ8I0vYJqCBfgP7FrsTWKV6Mo2kbFOUQf6VLpdw
# j1loXbIxgMKxDfodp3jfM6dUNfais2W1lYWWtmRaUu6Ak04mlsPJNYJRwW2/cyIK
# wck68JNnSgnk/LJ95II952ovLX9i+73wxCJ2Xsaw/eZ0wDgMguHAeioP5RhkAGsy
# Uz4VTcy3NfBJb76mfj4AE5YbVwsiMlbnOWBRJADyDxmVVa9S7auEPzSfJJgeMdZT
# wY2jiLp1W6ZCn5LTP923f++tW2G9x93MKhja5Pr6o5Rw6FORJkkNHkfjQw0TOuvM
# TFLqoaHA8m/fOK3ybHPdNqHiSrGCjtjdmyVzfUIOOehL8K+6U16eZ9FpvUs7H9Eq
# +Cbl96mvtRFhse4mR8CQnPJnvXSMiDgPltfM1LTW42FfPqjotvJP7SXCMEFBRbE3
# GDj7JguQisReJipDG9w/eVdMBf3wPqNNuaAjnlWVv/lbOg7+cTaTcfQ0qiBmSuW/
# AMd3OFQr46Sh/N6MWY6q3heFWy6YQy+DOrFW3XZzjbsXq+1r/A3bkoGD1BeeAu9c
# fB+S5vvQlkGr0Hk7fwZ96taIy9+r65wxUtn6eva+viy+wGOSbw954D82wwbN81tK
# 1TimxnkUh4sFs++SaAdGfGUWt2q9cJzsoYIDIDCCAxwGCSqGSIb3DQEJBjGCAw0w
# ggMJAgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu
# MTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRp
# bWVTdGFtcGluZyBDQQIQBUSv85SdCDmmv9s/X+VhFjANBglghkgBZQMEAgEFAKBp
# MBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIzMTEx
# MDAwMjcwM1owLwYJKoZIhvcNAQkEMSIEIFM0DeNcevzRyCaEpzY3iL8nFz5LFAqg
# KQlaJsskeJqqMA0GCSqGSIb3DQEBAQUABIICACUcig+MQJzaAEIub763xaZKuXSj
# Ib9kINbdzpeBirUGf8PXr/14RQmka9V+7J3WmydhiYey409/Om51bu7NirrENO4k
# 7YMND3Fcsho59bdDiDazQAa14atLmoA6X8J6y6pIYh3fRE1FaDgu6SGQUOKSBcf5
# o5fR5UgZlBzBMZ/TUJNBOtRIA+GKtVQ1KNSh/nmrOMtY0D0Ao/M/tzDTUvKwRS1l
# fvK2GaVSCLn1mjqSYuHBXXs0mN2k7WVes//2ZIYiQoSuU+zJ0ehzvboFCDhltRmN
# 2qBnuh0lxOzCF+m2fcwGzqq6NRKKs9Sw2uC41T3FVE2oKfTD39V/M5r2HKU945LS
# Ls/3iNRE/dfpWOBch9sHKY/6rChDaQhcJkWjst0gOkA+yfPtVCVcdoSTnV9eSw/F
# ggbLqRCkmS7uExZMxtyTa4Wt+pV1US3aQwCCONwd3sVk8gMPkh1UQlIAerLGLwfw
# sJtx7LfiEfO2MJ5VmUcQWN+4aE2tkzAWnyH0GGFD9OpqMLIk4RnbzZWNKks+eJQh
# R1ZY1zPFb8HEiF1tbQKj5ePiZwIwgTaJiEkGzJQYtLfm0S0P02xRArOE7VWjXH36
# 0/7P8EQYOGpUrOrMJz3Nx7b9MY1Pk/X7qDFSwK78tiYkzGu4Dpv8Pm6OWO13WeBg
# 7opl5J17/Bb6rWq2
# SIG # End signature block