IP.Tools.psm1

## Running A Build Will Compile This To A Single PSM1 File Containing All Module Code ##

## If Importing Module Source Directly, This Will Dynamically Build Root Module ##

# Get list of private functions and public functions to import, in order.
$Private = @(Get-ChildItem -Path $PSScriptRoot\private -Recurse -Filter "*.ps1") | Sort-Object Name
$Public = @(Get-ChildItem -Path $PSScriptRoot\public -Recurse -Filter "*.ps1") | Sort-Object Name

$AllMask = [Math]::Pow(2, 32)
New-Variable -Name AllMask -Value $AllMask -Scope Script -Force

Class IpNetwork {

  [ipaddress]$IpAddress
  [ipaddress]$IpNetmask

  IpNetwork([string]$CIDR) {
    ($IP, $MaskLen) = $CIDR.Split('/')
    $IP = Get-IpNetworkBase -CIDR $CIDR
    Write-Verbose "IP: $($IP); Mask: $($MaskLen)"
    $this.IpAddress = [ipaddress]($IP)
    $this.IpNetmask = [ipaddress](Convert-MaskLenToIp($MaskLen))
  }

  IpNetwork([IpAddress]$IP, [IpAddress] $Mask) {
    Write-Verbose "IP: $($IP); Mask: $($Mask)"
    $IP = Get-IpNetworkBase -IP $IP -Mask $Mask
    $this.IpAddress = $IP
    $this.IpNetmask = $Mask
  }

  [system.net.ipaddress]GetStartAddress() {
    return Get-IpNetworkStartIp -Network $this
  }

  [system.net.ipaddress]GetEndAddress() {
    return Get-IpNetworkEndIP -Network $this
  }
}

# Dot source the private function files.
foreach ($ImportItem in $Private) {
  try {
    . $ImportItem.FullName
    Write-Verbose -Message ("Imported private function {0}" -f $ImportItem.FullName)
  }
  catch {
    Write-Error -Message ("Failed to import private function {0}: {1}" -f $ImportItem.FullName, $_)
  }
}

# Dot source the public function files.
foreach ($ImportItem in $Public) {
  try {
    . $ImportItem.FullName
    Write-Verbose -Message ("Imported public function {0}" -f $ImportItem.FullName)
  }
  catch {
    Write-Error -Message ("Failed to import public function {0}: {1}" -f $ImportItem.FullName, $_)
  }
}

# Export the public functions.
Export-ModuleMember -Function $Public.BaseName
# Private Function Example - Replace With Your Function
function Add-PrivateFunction {

  [CmdletBinding()]

  Param (
    # Your parameters go here...
  )

  # Your function code goes here...
  Write-Output "Your private function ran!"

}

function Get-IpBogon {
  <#
    .SYNOPSIS
        Return a list of IP Bogons with [ipaddress] objects representing the IP and Mask
    .DESCRIPTION
        Return a list of IP Bogons (Internet non-routable addresses) with [ipaddress] objects representing both IP and Mask.
 
        IP Bogons are Internet non-routable addresses that are either reserved for Private use (RFC1918), or are otherwise not available.
    .INPUTS
        None
    .OUTPUTS
        Array of [ipaddress] objects representing IP Bogons.
    .EXAMPLE
        PS> $Bogons = Get-IpBogon.ps1
    .LINK
        https://github.com/IPSecMSSP/ip.tools
  #>

  [CmdletBinding()]

  $Bogons = @()
  $Bogons += '0.0.0.0/8'          # RFC1122 "This" network
  $Bogons += '10.0.0.0/8'         # RFC1918 Private-use networks
  $Bogons += '100.64.0.0/10'      # RFC6598 Carrier-grade NAT
  $Bogons += '127.0.0.0/8'        # RFC1122 IPv4 Loopback
  $Bogons += '169.254.0.0/16'     # RFC3927 IPv4 Link local
  $Bogons += '172.16.0.0/12'      # RFC1918 Private-use networks
  $Bogons += '192.0.0.0/24'       # RFC5736 IETF protocol assignments
  $Bogons += '192.0.2.0/24'       # RFC5737 TEST-NET-1
  $Bogons += '192.168.0.0/16'     # RFC1918 Private-use networks
  $Bogons += '198.18.0.0/15'      # RFC2544 Network interconnect device benchmark testing
  $Bogons += '198.51.100.0/24'    # RFC5737 TEST-NET-2
  $Bogons += '203.0.113.0/24'     # RFC5737 TEST-NET-3
  $Bogons += '224.0.0.0/4'        # RFC1112 Multicast
  $Bogons += '240.0.0.0/4'        # Reserved for future use

  $BogonIps = @()

  foreach ($Bogon in $Bogons) {

      $BogonIp = [IpNetwork]::new($Bogon)

      $BogonIPs += $BogonIp
  }

  Write-Output $BogonIps

}

function Remove-IpBogon {
  #
  <#
    .SYNOPSIS
      Remove any Bogon IPs from the list of provided IPs.
    .DESCRIPTION
      Remove any Bogon IPs from the list of provided IPs. Each IP is expected to be either a dotted quad notation string representation of the address, or an [ipaddress] object.
    .INPUTS
      [IpAddress] or [string] values to filter
    .OUTPUTS
      Array of [ipaddress] objects that have had IP Bogons removed.
    .EXAMPLE
      PS> $IPs = Get-IpFromSomeSource
      PS> $IPs | Remove-IpBogon
 
      Obtain a list of IPs from some source (like a SIEM), and filter out the Bogon addresses
    .LINK
        https://github.com/IPSecMSSP/ip.tools
  #>

[cmdletbinding(SupportsShouldProcess)]
  param (
      [Parameter(Mandatory=$true,
          ValueFromPipeLine=$true)]
      [ipaddress] $Address
  )

  Begin {
      $Me = $MyInvocation.MyCommand.Name

      Write-Verbose $Me
  }

  Process {

    if ($PSCmdlet.ShouldProcess($Address, "Remove IP if Bogon")) {
      if (!(Test-IpBogon -Address $Address)) {
        Write-Output $Address
    }
  }

  }

  End {

  }

}

function Test-IpBogon {

  [cmdletbinding()]
  param (
      [Parameter(Mandatory=$true,
          ValueFromPipeLine=$true)]
      [ipaddress] $Address
  )

  Begin {
      $Me = $MyInvocation.MyCommand.Name

      Write-Verbose $Me

      $IpBogons = Get-IpBogon
  }

  Process {

      $IsBogon = $false

      foreach ($Bogon in $IpBogons) {
          if (Test-IpInNetwork -Address $Address -Network $Bogon) {
              $IsBogon = $true
          }
      }

      Write-Output $IsBogon

  }

  End {
      Clear-Variable 'IpBogons'
  }

}

function Convert-IpToMaskLen {
  <#
    .SYNOPSIS
        Convert a Subnet Mask to PrefixLength
    .DESCRIPTION
        Convert a Subnet Mask to a Prefix Length
    .EXAMPLE
        PS C:\> Convert-IpToMaskLen 255.255.0.0
        16
 
        This example counts the relevant network bits of the dotted SubnetMask 255.255.0.0.
    .INPUTS
        [string]
    .OUTPUTS
        [string]
  #>


  [CmdletBinding()]

  param (
    # SubnetMask to convert
    [Parameter(Mandatory)]
    [System.Net.IpAddress]$SubnetMask
  )

  Begin {
    $Me = $MyInvocation.MyCommand.Name

    Write-Verbose "$($Me): $($SubnetMask)"
  }

  Process {
    $Octets = $SubnetMask.IPAddressToString.Split('.')
    Write-Verbose "$($Me): Octets: $($Octets)"
    foreach($Octet in $Octets) {
      while(0 -ne $Octet){
        $Octet = ($Octet -shl 1) -band [byte]::MaxValue
        $result++
      }
    }

    $TestMask = Convert-MaskLenToIp -MaskLen $result

    if ($TestMask -ne $SubnetMask) {
      throw "Invalid Netmask Supplied"
    } else {
      $result -as [string]
    }
  }

  End {

  }

}

function Convert-MaskLenToIp {
  <#
    .SYNOPSIS
      Convert MaskLen from CIDR Notation (IP/MaskLen) to an IP Address object
    .DESCRIPTION
      Convert MaskLen from CIDR Notation (IP/MaskLen) to an IP Address object
    .PARAMETER MaskLen
      Integer value representing the mask length
    .INPUTS
      Integer Mask Lenth
    .OUTPUTS
      [ipaddress] object representing the Netmask
    .EXAMPLE
      Pass a single MaskLen as a parameter
 
      PS> Convert-MaskLenToIp -MaskLen 24
 
      AddressFamily : InterNetwork
      ScopeId :
      IsIPv6Multicast : False
      IsIPv6LinkLocal : False
      IsIPv6SiteLocal : False
      IsIPv6Teredo : False
      IsIPv6UniqueLocal : False
      IsIPv4MappedToIPv6 : False
      Address : 16777215
      IPAddressToString : 255.255.255.0
 
    .EXAMPLE
      Use Pipeline to convert MaskLen to IP Address
 
      PS> 27 | Convert-MaskLenToIp
 
      AddressFamily : InterNetwork
      ScopeId :
      IsIPv6Multicast : False
      IsIPv6LinkLocal : False
      IsIPv6SiteLocal : False
      IsIPv6Teredo : False
      IsIPv6UniqueLocal : False
      IsIPv4MappedToIPv6 : False
      Address : 3774873599
      IPAddressToString : 255.255.255.224
 
    .LINK
      https://github.com/IPSecMSSP/ip.tools
  #>

  [CmdletBinding()]
  [OutputType([ipaddress])]

  param(
    [Parameter(Mandatory=$true,
      ValueFromPipeLine=$true)]
    [ValidateRange([int]0, [int]32)]
    [int]$MaskLen
  )

  Begin {
    $Me = $MyInvocation.MyCommand.Name

    Write-Verbose $Me
  }

  Process {

    [ipaddress]($AllMask - ($AllMask -shr $MaskLen))

  }

  End {

  }

}

function Get-IpNetworkBase {
  <#
    .SYNOPSIS
      Get the Base Network address for the supplied IP/Mask
    .DESCRIPTION
      Get the Base Network address for the supplied IP/Mask
    .PARAMETER CIDR
      [string] containing CIDR notation for network address
    .PARAMETER IP
      [IPAddress] object or Dotted Quad notation string representing the IP address
    .PARAMETER Mask
      [IpNetwork] Object or Dotted Quad notation string representing the Netmask
    .INPUTS
      CIDR Strings
    .OUTPUTS
      [IpAddress] Object
    .EXAMPLE
      PS> (Get-IpNetworkBase -CIDR 192.168.100.20/24).IPAddressToString
      192.168.100.0
 
 
    .EXAMPLE
      Use Pipeline to convert MaskLen to IP Address
 
      PS> 27 | Convert-MaskLenToIp
 
 
    .LINK
      https://github.com/IPSecMSSP/ip.tools
  #>

  [CmdletBinding(DefaultParameterSetName = 'CIDR')]
  [OutputType([IpAddress])]
  param(
    [Parameter(ParameterSetName='CIDR',
      Mandatory=$true,
      Position = 0,
      ValueFromPipeline=$true)]
    [string] $CIDR,

    [Parameter(ParameterSetName='IpMask',
      Mandatory=$true,
      Position = 0)]
    [IpAddress] $IP,

    [Parameter(ParameterSetName='IpMask',
      Mandatory=$true,
      Position = 1)]
    [IpAddress] $Mask
  )

  Begin {
    $Me = $MyInvocation.MyCommand.Name

    Write-Verbose $Me
  }

  Process {
    If ($PSCmdlet.ParameterSetName -eq "CIDR") {
      ([IpAddress]$IP, $MaskLen) = $CIDR -split '/'
      [IpAddress]$Mask = Convert-MaskLenToIp $MaskLen
    }
    Write-Verbose "IP: $($IP); Mask: $($Mask);"
    [IpAddress]$Net = ($IP.Address -band $Mask.Address)
    return $Net
  }

  End {

  }

}

function Get-IpNetworkEndIP {
  [CmdletBinding(DefaultParameterSetName = 'CIDR')]
  [OutputType([ipaddress])]
  param (
      [Parameter(ParameterSetName='CIDR',
      Mandatory=$true,
      ValueFromPipeline=$true)]
      [string]$CIDR,

      [Parameter(ParameterSetName='IpMask',
        Mandatory=$true,
        Position = 0)]
      [string] $IP,

      [Parameter(ParameterSetName='IpMask',
        Mandatory=$true,
        Position = 1)]
      [string] $Mask,

      [Parameter(ParameterSetName='Network',
        Mandatory=$true,
        Position = 1)]
      [IpNetwork] $Network
  )

  Begin {
    $Me = $MyInvocation.MyCommand.Name

    Write-Verbose $Me
  }

  Process {
    Switch ($PSCmdlet.ParameterSetName) {
      "CIDR" {
        Write-Verbose "$($Me): Invoked with CIDR"
        $Network = [IpNetwork]::new($CIDR)
      }
      "IpMask" {
        Write-Verbose "$($Me): Invoked with IP/Mask"
        $Network = [IpNetwork]::new($IP, $Mask)
      }
      "Network" {
        Write-Verbose "$($Me): Invoked with IpNetwork Object"

      }
    }

    $NetworkIP = $Network.IPAddress.GetAddressBytes()
    Write-Verbose "$($Me): NetworkIP: $($NetworkIP)"
    [Array]::Reverse($NetworkIP)
    Write-Verbose "$($Me): NetworkIP (reversed): $($NetworkIP)"
    $NetworkIP = ([ipaddress]($NetworkIP -join ".")).Address

    $MaskLen = Convert-IpToMaskLen -SubnetMask $Network.IpNetmask

    $NumIPs = ([System.Math]::Pow(2,(32 -$MaskLen)))

    $EndIP = $NetworkIP + $NumIPs - 1

    # Convert to Double
    If (($EndIP.GetType()).Name -ine "double") {
      $EndIP = [Convert]::ToDouble($EndIP)
    }

    $EndIP = [ipaddress]$EndIP

    Return $EndIP
  }

  End {

  }
}

function Get-IpNetworkStartIP {
  [CmdletBinding(DefaultParameterSetName = 'CIDR')]
  [OutputType([ipaddress])]
  param (
      [Parameter(ParameterSetName='CIDR',
      Mandatory=$true,
      ValueFromPipeline=$true,
      Position = 1)]
      [String]$CIDR,

      [Parameter(ParameterSetName='IpMask',
        Mandatory=$true,
        Position = 0)]
      [string] $IP,

      [Parameter(ParameterSetName='IpMask',
        Mandatory=$true,
        Position = 1)]
      [string] $Mask,

      [Parameter(ParameterSetName='Network',
        Mandatory=$true,
        ValueFromPipeline=$true,
        Position = 1)]
      [IpNetwork] $Network,

      [Parameter(Mandatory=$false)]
      [switch]$ExcludeNetwork
  )

  Begin {
    $Me = $MyInvocation.MyCommand.Name

    Write-Verbose $Me
  }

  Process {
    Switch ($PSCmdlet.ParameterSetName) {
      "CIDR" {
        Write-Verbose "$($Me): Invoked with CIDR"
        $Network = [IpNetwork]::new($CIDR)
      }
      "IpMask" {
        Write-Verbose "$($Me): Invoked with IP/Mask"
        $Network = [IpNetwork]::new($IP, $Mask)
      }
      "Network" {
        Write-Verbose "$($Me): Invoked with IpNetwork Object"

      }
    }

    $NetworkIP = $Network.IPAddress.GetAddressBytes()
    [Array]::Reverse($NetworkIP)
    $NetworkIP = ([ipaddress]($NetworkIP -join ".")).Address

    if($ExcludeNetwork) {
      $StartIP = $NetworkIP + 1
    } else {
      $StartIP = $NetworkIP
    }

    # Convert to Double
    If (($StartIP.GetType()).Name -ine "double") {
      $StartIP = [Convert]::ToDouble($StartIP)
    }

    $StartIP = [ipaddress]$StartIP

    Return $StartIP
  }

  End {

  }

}

function New-IpNetwork {
  <#
    .SYNOPSIS
      Create a new IpNetwork object with the specified CIDR or IP and Mask parameters
    .DESCRIPTION
      Create a new IpNetwork object with the specified CIDR or IP and Mask parameters
    .PARAMETER CIDR
      [string] containing CIDR notation for network
    .PARAMETER IP
      [IPAddress] object or Dotted Quad notation string representing the IP address
    .PARAMETER Mask
      [IpNetwork] Object or Dotted Quad notation string representing the Netmask
    .INPUTS
      CIDR Strings
    .OUTPUTS
      [IpNetwork] Object
    .EXAMPLE
      PS> $Network =
      PS> Test-IpInNetwork -Address 192.168.100.20 -Network
 
 
    .EXAMPLE
      Use Pipeline to convert MaskLen to IP Address
 
      PS> 27 | Convert-MaskLenToIp
 
 
    .LINK
      https://github.com/IPSecMSSP/ip.tools
  #>

  [CmdletBinding(DefaultParameterSetName = 'CIDR', SupportsShouldProcess)]
  param(
    [Parameter(ParameterSetName='CIDR',
      Mandatory=$true,
      Position = 0,
      ValueFromPipeline=$true)]
    [string] $CIDR,

    [Parameter(ParameterSetName='IpMask',
      Mandatory=$true,
      Position = 0)]
    [string] $IP,

    [Parameter(ParameterSetName='IpMask',
      Mandatory=$true,
      Position = 1)]
    [string] $Mask
  )

  Begin {
    $Me = $MyInvocation.MyCommand.Name

    Write-Verbose $Me
  }

  Process {
    if ($PSCmdlet.ShouldProcess("IpNetwork", "Return new IP Network from CIDR or IP and Mask")) {
      Switch ($PSCmdlet.ParameterSetName) {
        "CIDR" {
          return [IpNetwork]::new($CIDR)
        }
        "IpMask" {
          return [IpNetwork]::new($IP, $Mask)
        }
      }
    }
  }

  End {

  }

}

function Test-IpInNetwork {
  <#
    .SYNOPSIS
      Test if an IP address exists in the specified network
    .DESCRIPTION
      Test if an IP address exists in the specified network
    .PARAMETER Address
      [IPAddress] object or Dotted Quad notation string representing the IP address to test
    .PARAMETER Network
      [IpNetwork] Object consisting of IpAddress and IpNetmask to check if IP belongs. If supplied as string, will be converted to IpNetwork before testing.
    .INPUTS
      IP Addresses and networks.
    .OUTPUTS
      [bool] result of test
    .EXAMPLE
      PS> $Network = New-IpNetwork "192.168.100.0/24"
      PS> Test-IpInNetwork -Address 192.168.100.20 -Network $Network
 
 
    .EXAMPLE
      Use Pipeline to convert MaskLen to IP Address
 
      PS> 27 | Convert-MaskLenToIp
 
 
    .LINK
      https://github.com/IPSecMSSP/ip.tools
  #>

  [cmdletbinding()]
  param (
      [Parameter(Mandatory=$true,
          ValueFromPipeLine=$true)]
      [ipaddress] $Address,

      [Parameter(Mandatory=$true,
          ValueFromPipeline=$true)]
      [ValidateScript({
        $TypeName = $_ | Get-Member | Select-Object -ExpandProperty TypeName -Unique
        if ($TypeName -eq 'System.String' -and $_ -match "(\d{1,3}\.){3}\d{1,3}\/\d{1,2}") {
          Write-Verbose "Convert From String: $_"
          New-IpNetwork $_
        } elseif ($TypeName -eq 'IpNetwork') {
          Write-Verbose "Taken as IpNetwork Object $_"
          $_
        }
      })]
      $Network
  )

  Begin {
      $Me = $MyInvocation.MyCommand.Name

      Write-Verbose $Me

  }

  Process {

    Write-Verbose "Network To Test: $Network"

    if ($Network.GetType().Name -eq 'String') {
      $Network = New-IpNetwork -CIDR $Network
    }

    if ($Network.IpAddress.Address -eq ($Address.Address -band $Network.IpNetmask.Address)) {
        Write-Output $true
    } else {
        Write-Output $false
    }
  }

  End {

  }
}

function Test-IpRangeIsSubnet {
  <#
    .SYNOPSIS
      Test if supplied IP Range is a valid Subnet
    .DESCRIPTION
      Test if supplied IP Range is a valid Subnet
    .PARAMETER StartAddress
      [IPAddress] object or Dotted Quad notation string representing the Start IP address of the range to test
    .PARAMETER EndAddress
      [IPAddress] object or Dotted Quad notation string representing the End IP address of the range to test
    .INPUTS
      IP Addresses
    .OUTPUTS
      [bool] False if the IP Range does not represent a valid subnet
      [ipaddress] representation of the Subnet Mask
    .EXAMPLE
      PS> $StartAddress = 192.168.1.0
      PS> $EndAddress = 192.168.1.15
      PS> Test-IpRangeIsSubnet -StartAddress $StartAddress -EndAddress $EndAddress
 
        AddressFamily : InterNetwork
        ScopeId :
        IsIPv6Multicast : False
        IsIPv6LinkLocal : False
        IsIPv6SiteLocal : False
        IsIPv6Teredo : False
        IsIPv6UniqueLocal : False
        IsIPv4MappedToIPv6 : False
        Address : 3774873599
        IPAddressToString : 255.255.255.224
 
    .LINK
      https://github.com/IPSecMSSP/ip.tools
  #>

  [cmdletbinding()]
  param (
      [Parameter(Mandatory=$true,
          ValueFromPipeLine=$true)]
      [ipaddress] $StartAddress,

      [Parameter(Mandatory=$true,
          ValueFromPipeLine=$true)]
      [ipaddress] $EndAddress
  )

  Begin {
      $Me = $MyInvocation.MyCommand.Name

      Write-Verbose $Me
  }

  Process {

    Write-Verbose "Address Range To Test: $StartAddress - $EndAddress"

    $StartAddressBytes = $StartAddress.GetAddressBytes()
    $EndAddressBytes = $EndAddress.GetAddressBytes()

    $AddressDiffBytes = @()
    for (($octet = 0);  ($octet -lt $StartAddressBytes.Count); $octet++) {
      Write-verbose "Octet $octet"
      $AddressDiffBytes += $StartAddressBytes[$octet] -bxor $EndAddressBytes[$octet]
    }

    Write-Verbose "$($AddressDiffBytes -join '.')"
    [ipaddress]$AddressDiff = $AddressDiffBytes -join '.'

    Write-Verbose $AddressDiff

    [ipaddress]$MaskDiff = ($AllMask - 1) - $AddressDiff.Address

    Write-Verbose $MaskDiff

    # Reverse the bytes
    $Octets = $MaskDiff.IPAddressToString.Split('.')
    [Array]::Reverse($Octets)
    $Mask = [IpAddress]($Octets -join '.')

    if (Test-ValidMask ($Mask)) {
        Write-Output $Mask
    } else {
        Write-Output $false
    }
  }

  End {

  }
}

function Test-ValidMask {
  <#
    .SYNOPSIS
      Test if an IP address represents a valid network mask
    .DESCRIPTION
      Test if an IP address represents a valid network mask. I.E. the binary representation contains all 1's followed by all 0'
    .PARAMETER Address
      [IPAddress] object or Dotted Quad notation string representing the IP address to test
    .INPUTS
      IP Address
    .OUTPUTS
      [bool] result of test
    .EXAMPLE
      PS> $Mask = "255.255.192.0"
      PS> Test-ValidMask -Address $Mask
 
    .EXAMPLE
      Use Pipeline to convert MaskLen to IP Address
 
      PS> 27 | Convert-MaskLenToIp
 
 
    .LINK
      https://github.com/IPSecMSSP/ip.tools
  #>

  [cmdletbinding()]
  param (
      [Parameter(Mandatory=$true,
          ValueFromPipeLine=$true)]
      [ipaddress] $Address
  )

  Begin {
      $Me = $MyInvocation.MyCommand.Name

      Write-Verbose $Me

  }

  Process {

    Write-Verbose "Mask To Test: $Address"

    # Convert Address to binary representation
    $binAddress = ($Address.GetAddressBytes() | ForEach-Object {[System.Convert]::ToString($_,2).PadLeft(8,'0')}) -join ''

    $AddressBits = $binAddress.ToCharArray()

    $Last = 1
    $ValidMask = $true
    Foreach ($bit in $AddressBits) {
      if ($bit -eq '1') {
        if ($Last -ne '1') {
          $ValidMask = $false
        }
      }
      $Last = $bit
    }

    Write-Output $ValidMask
  }

  End {

  }
}

Export-ModuleMember -Function Get-IpBogon, Remove-IpBogon, Test-IpBogon, Convert-IpToMaskLen, Convert-MaskLenToIp, Get-IpNetworkBase, Get-IpNetworkEndIP, Get-IpNetworkStartIP, New-IpNetwork, Test-IpInNetwork, Test-IpRangeIsSubnet, Test-ValidMask

# SIG # Begin signature block
# MIIoHgYJKoZIhvcNAQcCoIIoDzCCKAsCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCClTqrbd8x/ZwIH
# H3BfdSYW8FsHfhgU3KJi886fOpSgJaCCISEwggWNMIIEdaADAgECAhAOmxiO+dAt
# 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa
# Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD
# ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
# ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E
# MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy
# unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF
# xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1
# 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB
# MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR
# WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6
# nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB
# YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S
# UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x
# q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB
# NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP
# TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC
# AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
# Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv
# bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0
# aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB
# LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc
# Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov
# Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy
# oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW
# juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF
# mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z
# twGpn1eqXijiuZQwggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqG
# SIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx
# GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy
# dXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMx
# CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMy
# RGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcg
# Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXH
# JQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMf
# UBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w
# 1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRk
# tFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYb
# qMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yemj052FVUm
# cJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP6
# 5x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzK
# QtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo
# 80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjB
# Jgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXche
# MBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB
# /wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU
# 7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoG
# CCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29j
# c3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDig
# NqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v
# dEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZI
# hvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd
# 4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiC
# qBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl
# /Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeC
# RK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYT
# gAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/
# a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37
# xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmL
# NriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0
# YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJ
# RyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIG
# sDCCBJigAwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQsw
# CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
# ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw
# HhcNMjEwNDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEX
# MBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0
# ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjAN
# BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zr
# PYGXcMW7xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHM
# gQM+TXAkZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8Irg
# nQnAZaf6mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyC
# EUhSaN4QvRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0
# p6MDDnSlrzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQa
# khCBj7A7CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0
# XLyTRSiDNipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960I
# HnWmZcy740hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2
# FKZbS110YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBH
# X8mBUHOFECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q2
# 7IwyCQLMbDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD
# VR0OBBYEFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1k
# TN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcD
# AzB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj
# ZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29t
# L0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0
# cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmww
# HAYDVR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIB
# ADojRD2NCHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6j
# fCbVN7w6XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmI
# moqKwba9oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtf
# JqGVWEjVGv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrx
# oj7bQ7gzyE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3
# LIU/Gs4m6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx
# 4b6cpwoG1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9
# Oj9FpsToFpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+I
# Cw2/O/TOHnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug
# 0wcCampAMEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5
# Vzu0nAPthkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIGwDCCBKigAwIBAgIQ
# DE1pckuU+jwqSj0pB4A9WjANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEX
# MBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0
# ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTIyMDkyMTAw
# MDAwMFoXDTMzMTEyMTIzNTk1OVowRjELMAkGA1UEBhMCVVMxETAPBgNVBAoTCERp
# Z2lDZXJ0MSQwIgYDVQQDExtEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMiAtIDIwggIi
# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDP7KUmOsap8mu7jcENmtuh6BSF
# dDMaJqzQHFUeHjZtvJJVDGH0nQl3PRWWCC9rZKT9BoMW15GSOBwxApb7crGXOlWv
# M+xhiummKNuQY1y9iVPgOi2Mh0KuJqTku3h4uXoW4VbGwLpkU7sqFudQSLuIaQyI
# xvG+4C99O7HKU41Agx7ny3JJKB5MgB6FVueF7fJhvKo6B332q27lZt3iXPUv7Y3U
# TZWEaOOAy2p50dIQkUYp6z4m8rSMzUy5Zsi7qlA4DeWMlF0ZWr/1e0BubxaompyV
# R4aFeT4MXmaMGgokvpyq0py2909ueMQoP6McD1AGN7oI2TWmtR7aeFgdOej4TJEQ
# ln5N4d3CraV++C0bH+wrRhijGfY59/XBT3EuiQMRoku7mL/6T+R7Nu8GRORV/zbq
# 5Xwx5/PCUsTmFntafqUlc9vAapkhLWPlWfVNL5AfJ7fSqxTlOGaHUQhr+1NDOdBk
# +lbP4PQK5hRtZHi7mP2Uw3Mh8y/CLiDXgazT8QfU4b3ZXUtuMZQpi+ZBpGWUwFjl
# 5S4pkKa3YWT62SBsGFFguqaBDwklU/G/O+mrBw5qBzliGcnWhX8T2Y15z2LF7OF7
# ucxnEweawXjtxojIsG4yeccLWYONxu71LHx7jstkifGxxLjnU15fVdJ9GSlZA076
# XepFcxyEftfO4tQ6dwIDAQABo4IBizCCAYcwDgYDVR0PAQH/BAQDAgeAMAwGA1Ud
# EwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwIAYDVR0gBBkwFzAIBgZn
# gQwBBAIwCwYJYIZIAYb9bAcBMB8GA1UdIwQYMBaAFLoW2W1NhS9zKXaaL3WMaiCP
# nshvMB0GA1UdDgQWBBRiit7QYfyPMRTtlwvNPSqUFN9SnDBaBgNVHR8EUzBRME+g
# TaBLhklodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRS
# U0E0MDk2U0hBMjU2VGltZVN0YW1waW5nQ0EuY3JsMIGQBggrBgEFBQcBAQSBgzCB
# gDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFgGCCsGAQUF
# BzAChkxodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVk
# RzRSU0E0MDk2U0hBMjU2VGltZVN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUA
# A4ICAQBVqioa80bzeFc3MPx140/WhSPx/PmVOZsl5vdyipjDd9Rk/BX7NsJJUSx4
# iGNVCUY5APxp1MqbKfujP8DJAJsTHbCYidx48s18hc1Tna9i4mFmoxQqRYdKmEIr
# UPwbtZ4IMAn65C3XCYl5+QnmiM59G7hqopvBU2AJ6KO4ndetHxy47JhB8PYOgPvk
# /9+dEKfrALpfSo8aOlK06r8JSRU1NlmaD1TSsht/fl4JrXZUinRtytIFZyt26/+Y
# siaVOBmIRBTlClmia+ciPkQh0j8cwJvtfEiy2JIMkU88ZpSvXQJT657inuTTH4YB
# ZJwAwuladHUNPeF5iL8cAZfJGSOA1zZaX5YWsWMMxkZAO85dNdRZPkOaGK7DycvD
# +5sTX2q1x+DzBcNZ3ydiK95ByVO5/zQQZ/YmMph7/lxClIGUgp2sCovGSxVK05iQ
# RWAzgOAj3vgDpPZFR+XOuANCR+hBNnF3rf2i6Jd0Ti7aHh2MWsgemtXC8MYiqE+b
# vdgcmlHEL5r2X6cnl7qWLoVXwGDneFZ/au/ClZpLEQLIgpzJGgV8unG1TnqZbPTo
# ntRamMifv427GFxD9dAq6OJi7ngE273R+1sKqHB+8JeEeOMIA11HLGOoJTiXAdI/
# Otrl5fbmm9x+LMz/F0xNAKLY1gEOuIvu5uByVYksJxlh9ncBjDCCB2IwggVKoAMC
# AQICEA6ZYkUs3x6FUkpZyx3fNW8wDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMC
# VVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBU
# cnVzdGVkIEc0IENvZGUgU2lnbmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMTAe
# Fw0yMjExMTEwMDAwMDBaFw0yMzExMTAyMzU5NTlaMGcxCzAJBgNVBAYTAkFVMREw
# DwYDVQQIEwhWaWN0b3JpYTEVMBMGA1UEBxMMTm90dGluZyBIaWxsMRYwFAYDVQQK
# Ew1JUFNlYyBQdHkgTHRkMRYwFAYDVQQDEw1JUFNlYyBQdHkgTHRkMIICIjANBgkq
# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuJ4EsEL1x5o2E2m4pFTCeVzGv5URXuSd
# Q25eyXUbMGb7VsTbft4MYM6ySZe7I1Yk7Jm/rsSsjDuud9XbvLJB3qX/kdVCFMLn
# y2On85sFUQ67ZWHGh5ub9tIJzkJN7BlJ0u2Rw09AeLAArF3yqeQffu/YegMSH8rY
# eb8DLvFr9lxKjoWXg5khH3yXWaI0N0g/FHKWL9URn6HSStY90y4ilQCcjwjwA8Vp
# gIU9eCDj4kagwdU5ZvOazbzQXJqvzMB09ccLegf2MrPoMseRSksL0BBo5kkq5jiw
# Fc4HIf2/RYrjfVWtFLq33tvMDifpI/ZuhiBooaAEe3OA10s8+A4Ps3OkSP2hd/Hq
# UXGQZY1FN3fDRworMkEaaqQioeaaSePAIwdGTz2Z2aCY4b5taHWiOM/5+jhCr6Gq
# S8TXI1ODtZl2V11/KfKJDjiTes2lQ4zShHNAg40/aTOQxmsvv1zwlM9Dqf8GRDC1
# OThWrPc40s6RztXa9CnC3EQgxIUQs/qQwkToS3dJGcr/bsCmVCHPQKDjHYIHbU8n
# CMjSaG1YDIfdRW9MyyAFghtzjDDEyyN+LJCOdEnq4WgiaNIHNDsYABTAy9Nc2u4u
# VmQE387ZqbAww2Doo/eiEnPU5y1JgXvxhqgdL2Fg20gXagfBqysTuuExuh/AoSuM
# TEO02MRZ+78CAwEAAaOCAgYwggICMB8GA1UdIwQYMBaAFGg34Ou2O/hfEYb7/mF7
# CIhl9E5CMB0GA1UdDgQWBBTZSP/AY1Bcm0dUbWSS+LJDbsyIHzAOBgNVHQ8BAf8E
# BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwgbUGA1UdHwSBrTCBqjBToFGgT4ZN
# aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNp
# Z25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwU6BRoE+GTWh0dHA6Ly9jcmw0
# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5
# NlNIQTM4NDIwMjFDQTEuY3JsMD4GA1UdIAQ3MDUwMwYGZ4EMAQQBMCkwJwYIKwYB
# BQUHAgEWG2h0dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCBlAYIKwYBBQUHAQEE
# gYcwgYQwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBcBggr
# BgEFBQcwAoZQaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1
# c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcnQwDAYDVR0T
# AQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAFQZrq6Y5WS74dGqSjbSXHqiQeQhc
# emYWRNkPOnA4duyDdKNerNSkYDhqunW3igVhLkjYzV3rxPceL67+mUdy4ppf9g1Q
# e8f6cM/wELnKmXH/aCGBVvBEjVJnt3LTQLGUGNu28Np1Hdfg7H0SqRlSuvLCaibr
# C87bRHgzCLGixw/Bo2d/SuKze2EXTtt85DLvx7TCOE894bUuhaHUnz207+SUhRnm
# W4pvHel8wJWfDN7QXANFvaV667cOlPZ9Kz2Jrxgf389Pj2XPrfIL/oH3U5OY6Q0/
# dHpFrT8s30MpG5iFQKbYn8W4790Gt/tjJVAFhMxYfnylT+ppemmvrltG/0qah903
# /IxMgSVI9I/23Gs83i7ppeCNnncF/5JRfD2qkQqKRHaJx/6rMjV0MDmV+m16bllZ
# jEfnXIxPyB1P4tJEwiGtbKhuEX9WbdE5msxy64FFU/4Ucxa8dIjllcr1MMfwJttX
# QDLtBYXDFrtb4r26FGRe3M+mjmZ0skzWPEuZpnjR0wK8Ep8HzEdB5WzLB/7lf70n
# YEWfuE1CjviDRz9hesjHZZ7nvPNXuraIRqPdNWnI8eJ7sT+jnL9nP3/h/uDvuHZx
# LAUBvRo6iNOOmO34/TZNCV0fBpZEBUBLJTBmFZoBTMV8z156RL7QXjCK1cLgXuCU
# OfJLfjrNc5RZvtAxggZTMIIGTwIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQK
# Ew5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBD
# b2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEzODQgMjAyMSBDQTECEA6ZYkUs3x6FUkpZ
# yx3fNW8wDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKA
# ADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYK
# KwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgOTGJaBgsVbuyDI+D0RGQXcKPuK4O
# Gj9RtCpPY+b559MwDQYJKoZIhvcNAQEBBQAEggIAArkP1iKiUzvdQIYcbp/J37WL
# gMwNPEG8vXsYM29VvQPzd98pDuWll53IowSwjgkIntX6+MAvpA6lLX8oO9Eh/Cyk
# AKLXrPnetDgHI0b1bi1s5ZH/ORb/pd2YXBo9LKHdwMhDY2FAn0J+C6vKS7Whk2Ak
# 2yvOBse+/rU+uTwlicf6KmV+8TVpnzLFNYALQg1zvPUPQS5CbKDoH0N5hlqEAlJ9
# EBJpKsS/9lwKf3zmwW0OC3iE0kmWjMoqT1gdkcvJDfXfUMDB21rWWfUGH+jll1ot
# NVwPuMPVFOAnd4Cmtplg6IUiv0uVsXkTCBFeTuPUOM1H1PHfXXsIyFQbPKJkTDov
# GHQZF0jyBqltDNTFM8nViNBsTpWoIJ+CX4dKkY5c8wy6mAgCocGh5dWPXslEuSE3
# MiZ+RKUTqR1Pl8oIaWF6iUC4X1K3H7K4Ve4YoOd85xbkzCOduOjYxwKi80b9BGzp
# 8RoVjVhB8SiFPC8lZFqCbTt5fQOBkbF+bKruVQcdDkr3mNFG5S9KIeutMJ1P1O9q
# K5vzhieI9+WxyJtnp8tRM/B/G9K5gSptTqEZDuIkn8LmxiDRmfMuaiwQbCighazj
# m75gZQYOqr3S3jhnCUUugDdH+8RB5yLzuQQAcqQM2belJYkB3K0a1AFduB8upGTR
# 7iiYtv8I8tFDspMGacGhggMgMIIDHAYJKoZIhvcNAQkGMYIDDTCCAwkCAQEwdzBj
# MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMT
# MkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5n
# IENBAhAMTWlyS5T6PCpKPSkHgD1aMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcN
# AQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjIxMTE0MjMwMTU1WjAv
# BgkqhkiG9w0BCQQxIgQgFYWiOsH6+x5ZvjudSj3LnfWOXbBJl6m/3uW71AiaZNgw
# DQYJKoZIhvcNAQEBBQAEggIAkC1z+4Pmbf6wQ88SWF/iS6ZLYlOAB7lbicrXKyZ1
# bnAmoBFerQlZa0XEyISU/Oy8KxoX40U3ZAR0HqfJ3QqfQSsuHFU8cE8CeFCK5ZUT
# MJmEhLGkPeXMdm5kQ2sY1emyYw3WSoD9bAyxgAY8jFJ32Pgbke2kAnydcaRn6KDm
# MC8V52M+mb2H5XrP3Nxjks37yTRMruQ7RzHWp+JWpKisSjpxsKXyriXC/hTtdQ/4
# tQ/ntRwevkXW1bF62/dyWek/MHAUJAZ7sD2FKRKJsS6jX000RQVYILcp8goVRTSF
# PnvNQtid+8y3ofmcDm4SdJ1cXVV98H5OVFTm4WPgBf+g3pIFLhyfQ3IV70U27mTA
# hcC5XMgGusokaCsR7RG5dgq4HgILtovLx7cz42MDcbK8uXMovrQCwJVGV0W3QV37
# 9YzOirauXjgXdFlU8ynnvHpALi0BjPWY3t2OQ6JQm0gQEG/cjKTydtNwyyaijig1
# PLNshKIHKdEO/1pJWWbVGpcHVnSvzVmUKzJ246W8hdW6Cq+kFInO4mumOmKwtzJZ
# PlJPeqMGqMp3siR6fVfEJhR1zHBSiNociv68Gt+++IcbsGORsPEhuYfbEzcb6abO
# P2OuVHj1z9fBie+I5rhwZ/riBZutp3XnpcoowND2EUo4gXrxAlGxIFaKSU3wBJOY
# d4k=
# SIG # End signature block